Compare commits

...

847 Commits

Author SHA1 Message Date
Bakerboy448
09d423848d New: Use Notifiarr API
New: Notifiarr Add Instance Name Support

Fixed: Notifiarr - Better HTTP Error Handling

also quiet sentry

(cherry picked from commit 1db690ad39ec103c0f4dc89ac4545801ef95bec7)

Fixed: Improve Notifiarr Exception Handling and Validation Errors

(cherry picked from commit 6aaa024d71b939030950460ae986ada5bbae5ad7)

also move notifiarr to header auth from url auth
2022-11-25 20:34:22 -06:00
psylenced
e69371deca Fix: Trace logging postgres cleanse for large json files.
(cherry picked from commit 2ce9d099e1001eb4fccd61edcb0597782da872d4)
2022-11-25 20:30:54 -06:00
Chris
5ae8deb9d6 Fixed: Postgres secret regex now less greedy
[common]

(cherry picked from commit 812e5ac5a3d76b69c172c5611b315ea809ab4b48)
2022-11-25 20:30:54 -06:00
Chris
291674fc18 Fixed: Regex in log cleanser taking 10+ minutes on messages longer than 100k.
(cherry picked from commit d01bae92bfd68b04c54ab19bafe8af16c68ce711)
2022-11-25 20:30:54 -06:00
Qstick
774cd04d32 Fixed SeedConfigProvider cache refresh after indexer settings change
Fixes #1036

Co-Authored-By: Taloth <Taloth@users.noreply.github.com>
2022-11-25 20:24:00 -06:00
Qstick
3eb0533b17 New: Disable autocomplete of port number
Fixes #1249

Co-Authored-By: Stevie Robinson <stevie.robinson@gmail.com>
2022-11-25 20:21:10 -06:00
Qstick
2fe11ca1a9 Rename NzbSearchService to ReleaseSearchService
Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>
2022-11-25 20:18:28 -06:00
Qstick
c8ae6b0299 Fixed: Custom Script Health Issue Level
Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>
2022-11-25 20:14:47 -06:00
Qstick
2086ae1e2c Ensure .Mono and .Windows projects have all dependencies in build output
Co-Authored-By: ta264 <ta264@users.noreply.github.com>
2022-11-25 20:10:23 -06:00
Chris
2aeec97d5e Added: Ntfy provider for notifications
(cherry picked from commit f6e6bc98f7846328d158ab2f804ca65b49632912)
2022-11-25 20:02:23 -06:00
Qstick
45e9d14916 New: Base API info endpoint
(cherry picked from commit 5e57ffbcf9ac3a346d4bf2b692248393215bad89)
2022-11-25 20:01:21 -06:00
Qstick
ded45a53f3 Improve page scrollbar
Fixed: Scrolling in Firefox in small window (requires refresh)
New: Style scrollbar in Firefox
Fixed: Scrolling with click and drag
Fixes #3088
Fixes #2706
2022-11-25 20:00:56 -06:00
Mark McDowall
d5cbb8f84f Replace react-custom-scrollbars
(cherry picked from commit 1c6c9a7960865d4bf8f58d5d04bef1aa1409594a)
2022-11-25 20:00:56 -06:00
Mark McDowall
cac0fca0d2 Added react-hooks lint rules
(cherry picked from commit 381d64259396582de8d63ada99333e42cf5e3189)
2022-11-25 19:55:55 -06:00
Mark McDowall
9b5a050c40 Publish ApplicationStartingEvent during startup
(cherry picked from commit 5400bce1295bdc4198d2cfe0b9258bbb7ccf0852)
2022-11-25 19:54:05 -06:00
Weblate
9fa67dbe5f Translated using Weblate (German) [skip ci]
Currently translated at 100.0% (879 of 879 strings)

Translated using Weblate (Czech) [skip ci]

Currently translated at 62.4% (549 of 879 strings)

Translated using Weblate (Finnish) [skip ci]

Currently translated at 79.8% (702 of 879 strings)

Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: Zalhera <tobias.bechen@gmail.com>
Co-authored-by: marapavelka <mara.pavelka@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/cs/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/fi/
Translation: Servarr/Readarr
2022-11-25 19:25:06 -06:00
Mark McDowall
505ef5ee63 Fixed: Testing SABnzbd when no categories are configured
(cherry picked from commit 0e31281828c737e3f6eecbb870960194888a970a)
2022-11-25 19:24:38 -06:00
Mark McDowall
87a2d7382e Added SECURITY.md
(cherry picked from commit 80af164385d9087a627142ca2281ae74ac0572af)

(cherry picked from commit aa8e886dab3ffedc835900db39787d47dc12465c)
2022-11-21 19:25:11 -06:00
Qstick
7c74a8df01 Fixed: UI Errors in Add Book page
Fixes #1906
2022-11-03 16:30:54 -05:00
Qstick
f8324b3c92 Create CODE_OF_CONDUCT.md 2022-11-03 15:58:16 -05:00
Weblate
cb03f3bf6b Translated using Weblate (Chinese (Simplified) (zh_CN)) [skip ci]
Currently translated at 100.0% (879 of 879 strings)

Update translation files [skip ci]

Updated by "Remove blank strings" hook in Weblate.

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

Currently translated at 69.0% (607 of 879 strings)

Translated using Weblate (Portuguese) [skip ci]

Currently translated at 76.7% (675 of 879 strings)

Co-authored-by: Sincejunly <qq943384135@gmail.com>
Co-authored-by: Tiago Ribeiro <tiago.err@outlook.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: libsu <libsu@qq.com>
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/zh_CN/
Translation: Servarr/Readarr
2022-11-03 10:42:08 -05:00
ta264
d6f85ec4f9 Use wildcard for FreeBSD itemPattern 2022-11-02 21:22:34 +00:00
Qstick
dd0dd921b0 Ignore brotli test on osx
(cherry picked from commit 2afe6af5a6dac26fe9d2c20e806a93b621e18bbf)
2022-10-30 19:03:10 -05:00
Mark McDowall
1f02423148 Fixed: Series list jump bar click issues
(cherry picked from commit 9c7378625112088d022239fdbdb90c0dc941d61d)
2022-10-20 20:42:53 -05:00
Qstick
7a4fba851f fixup! 2022-10-20 20:39:36 -05:00
Qstick
2d5efc268f New: Retry Postgres connection 3 times (with 5 second sleep) on Startup
(cherry picked from commit 3e700b63c26b247fcac83428ba79e53c88f797ff)

(cherry picked from commit dbca393772d7f558b45a780a6767187bf5900a23)
2022-10-20 20:39:36 -05:00
Mark McDowall
cad5762f31 Sliding expiration for auth cookie and a little clean up
Fixes #1802

(cherry picked from commit 05ee4e644907b7f1e84589465ac9ab1848f5a766)
2022-10-20 20:23:15 -05:00
Qstick
bcc8370d05 Cleanup dual target and mono code
Fixes #1893
Fixes #1808
2022-10-20 20:19:52 -05:00
Qstick
3481168df5 Fixed: qBittorrent Updates
Fixes #1658
Fixes #1536
2022-10-20 20:03:55 -05:00
Qstick
337a30ac0f Add thread to discord notifications 2022-10-19 22:00:13 -05:00
Weblate
eaad4de4dc Translated using Weblate (Chinese (Simplified) (zh_CN)) [skip ci]
Currently translated at 69.0% (607 of 879 strings)

Translated using Weblate (Polish) [skip ci]

Currently translated at 65.4% (575 of 879 strings)

Translated using Weblate (Slovak) [skip ci]

Currently translated at 7.3% (65 of 879 strings)

Translated using Weblate (Portuguese) [skip ci]

Currently translated at 76.3% (671 of 879 strings)

Translated using Weblate (Portuguese) [skip ci]

Currently translated at 76.3% (671 of 879 strings)

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

Currently translated at 0.6% (6 of 879 strings)

Translated using Weblate (Finnish) [skip ci]

Currently translated at 79.8% (702 of 879 strings)

Translated using Weblate (Japanese) [skip ci]

Currently translated at 62.3% (548 of 879 strings)

Translated using Weblate (Italian) [skip ci]

Currently translated at 69.8% (614 of 879 strings)

Translated using Weblate (Icelandic) [skip ci]

Currently translated at 62.3% (548 of 879 strings)

Translated using Weblate (Hindi) [skip ci]

Currently translated at 62.3% (548 of 879 strings)

Translated using Weblate (Hebrew) [skip ci]

Currently translated at 63.8% (561 of 879 strings)

Translated using Weblate (French) [skip ci]

Currently translated at 75.9% (668 of 879 strings)

Translated using Weblate (Finnish) [skip ci]

Currently translated at 79.8% (702 of 879 strings)

Translated using Weblate (Greek) [skip ci]

Currently translated at 62.3% (548 of 879 strings)

Translated using Weblate (Danish) [skip ci]

Currently translated at 62.3% (548 of 879 strings)

Translated using Weblate (Czech) [skip ci]

Currently translated at 62.3% (548 of 879 strings)

Translated using Weblate (Bulgarian) [skip ci]

Currently translated at 62.3% (548 of 879 strings)

Translated using Weblate (Arabic) [skip ci]

Currently translated at 62.4% (549 of 879 strings)

Translated using Weblate (Spanish) [skip ci]

Currently translated at 67.2% (591 of 879 strings)

Translated using Weblate (Dutch) [skip ci]

Currently translated at 65.8% (579 of 879 strings)

Added translation using Weblate (Latvian) [skip ci]

Translated using Weblate (German) [skip ci]

Currently translated at 92.0% (809 of 879 strings)

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

Currently translated at 100.0% (879 of 879 strings)

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

Currently translated at 100.0% (879 of 879 strings)

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

Currently translated at 67.9% (597 of 879 strings)

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

Currently translated at 99.5% (875 of 879 strings)

Translated using Weblate (French) [skip ci]

Currently translated at 75.0% (660 of 879 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 92.0% (809 of 879 strings)

Translated using Weblate (Spanish) [skip ci]

Currently translated at 67.1% (590 of 879 strings)

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Dainel Amendoeira <daniel@amendoeira.eu>
Co-authored-by: Gian Klug <gian.klug@ict-scouts.ch>
Co-authored-by: Gylesie <github-anon.dasheens@aleeas.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: HiNesslio <chi.lio@shms-mail.ch>
Co-authored-by: Marcin <ml.cichy@gmail.com>
Co-authored-by: Mijail Todorovich <mijailtodorovich+git@gmail.com>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Thomas Schwery <thomas@schwery.me>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: cikyw <cikyw@vomoto.com>
Co-authored-by: fyu0h <biiigback@gmail.com>
Co-authored-by: reloxx <reloxx@interia.pl>
Co-authored-by: 麋鹿先生 <y.qiuyu@outlook.com>
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ar/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/bg/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/cs/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/da/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/el/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/he/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/hi/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/is/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ja/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/nl/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pl/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/sk/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/zh_CN/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/zh_TW/
Translation: Servarr/Readarr
2022-10-16 10:06:07 -05:00
Mark McDowall
b98ae37abf Handle redirects for 308 redirects
(cherry picked from commit 6eed7c8fed096fa1762448bc57876440f542be98)
2022-10-16 10:03:35 -05:00
Stevie Robinson
5dac84f9d8 New: Torrent Seed Ratio no longer advance settings
(cherry picked from commit c98fac65ed8e669c5e97ed3255c424b61fe0e8b3)
2022-10-16 10:03:06 -05:00
bakerboy448
ef21c73619 update feature request template
[skip ci]

(cherry picked from commit 362e664ce6d301e8283d489b3e0d945db46d22d3)
2022-10-16 10:02:34 -05:00
Joe Milazzo
14d74f2eca New: Kavita Connection (#1880)
* Added ability for Readarr to inform Kavita when a change occurs for rescan.

* Use the existing API with a POST rather than a new API.

* Updated some wording

* Fixed PR comments
2022-10-02 18:41:38 -05:00
servarr[bot]
c3cbbb7627 Update Bug Report Template [skip ci] (#1842)
(cherry picked from commit 99e0d42b717b279be0f9005039025cd730f90f6c)

Co-authored-by: bakerboy448 <55419169+bakerboy448@users.noreply.github.com>
2022-09-26 21:05:36 -05:00
servarr[bot]
ad3a58c422 New: Parse version with a space before 'v''
* New: Parse anime version with a space before 'v'

(cherry picked from commit e9123982f33ab35ca022f91f345da05fef23d6dc)

* Delete AnimeVersionFixture.cs

Co-authored-by: Mark McDowall <mark@mcdowall.ca>
Co-authored-by: Qstick <qstick@gmail.com>
2022-09-26 16:55:34 -05:00
Robin Dadswell
347b154882 Update Bug Report Template
[skip ci]

(cherry picked from commit b9185574f3761e125151907e3d31511689a4513e)
2022-09-26 16:42:52 -05:00
Weblate
63ccc155d6 Translated using Weblate (Russian) [skip ci]
Currently translated at 66.6% (586 of 879 strings)

Translated using Weblate (Romanian) [skip ci]

Currently translated at 60.5% (532 of 879 strings)

Translated using Weblate (Hungarian) [skip ci]

Currently translated at 100.0% (879 of 879 strings)

Translated using Weblate (Finnish) [skip ci]

Currently translated at 79.6% (700 of 879 strings)

Co-authored-by: AlexR-sf <omg.portal.supp@gmail.com>
Co-authored-by: Csaba <csab0825@gmail.com>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: emanuelsipos <emanuelsipos1@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ro/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ru/
Translation: Servarr/Readarr
2022-08-18 07:12:51 -05:00
ta264
76613316fa Fixed: Book filters on author properties
Fixes #1755
2022-08-15 14:04:29 +01:00
ta264
f33e9f2bbc Fixed: Selecting edition for books in manual import 2022-08-15 14:04:29 +01:00
Robin Dadswell
e4a3d7b273 Fixed: Postgres Timezone Issues
Co-authored-by: ta264 <ta264@users.noreply.github.com>
2022-08-13 19:55:48 +01:00
Robin Dadswell
46c2e0ba82 New: Postgres Support
Co-Authored-By: Qstick <376117+Qstick@users.noreply.github.com>
Co-authored-by: ta264 <ta264@users.noreply.github.com>

(cherry picked from commit 80b1aa9a2c81617bdda7ef551c19a2f114e49204)
2022-08-13 19:55:48 +01:00
Robin Dadswell
8616373f96 Bump FluentMigrator to 3.3.2 2022-08-13 19:55:48 +01:00
ta264
b3f99d8c20 Fixed: Add missing author when a book's author changes in metadata
Fixes READARR-VH
2022-08-05 11:30:13 +01:00
ta264
c0c0847963 Update packages 2022-08-05 11:30:13 +01:00
Qstick
c92f9d03c0 Fixed: Releases Size filter has incorrect value type
(cherry picked from commit 46bc711558d9f3ab278125a4292eb7851e51d308)
2022-07-29 23:26:22 -04:00
bakerboy448
f7bf1e243d Fixed: List Import additions when book / author lookup required 2022-07-29 12:06:53 -05:00
Weblate
20b1f41ac1 Translated using Weblate (Catalan) [skip ci]
Currently translated at 49.4% (433 of 876 strings)

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

Currently translated at 0.5% (5 of 876 strings)

Co-authored-by: beefnoodle <acer.wang@protonmail.com>
Co-authored-by: dtalens <databio@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/zh_TW/
Translation: Servarr/Readarr
2022-07-26 09:22:12 +01:00
bakerboy448
f703db1e00 Fixed: Better Cleansing of Tracker Announce Keys
Fixed: Cleanse Notifiarr secret from URL in logs

Fixes: #4623
(cherry picked from commit e6210aede6f7ead197e82572976bc0267d910d46)

(cherry picked from commit ec866082d44d299096112a6c7c232384b1f74505)
2022-07-26 09:21:28 +01:00
bakerboy448
20f67c8035 Fixed: Importing Readarr Lists
Fixes #1747
2022-07-26 09:20:38 +01:00
Qstick
56ae497bfa Fixed: Don't call for server notifications on event driven check 2022-07-17 13:48:12 -05:00
Weblate
e760dc56c6 Translated using Weblate (French) [skip ci]
Currently translated at 75.1% (658 of 876 strings)

Co-authored-by: Sytha <tharaud.sylvain@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/fr/
Translation: Servarr/Readarr
2022-07-17 13:42:13 -05:00
Weblate
7ad26b386c Translated using Weblate (Hungarian) [skip ci]
Currently translated at 100.0% (876 of 876 strings)

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

Currently translated at 100.0% (876 of 876 strings)

Translated using Weblate (Italian) [skip ci]

Currently translated at 69.8% (612 of 876 strings)

Translated using Weblate (French) [skip ci]

Currently translated at 75.1% (658 of 876 strings)

Translated using Weblate (Ukrainian) [skip ci]

Currently translated at 10.9% (96 of 876 strings)

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

Currently translated at 0.1% (1 of 876 strings)

Translated using Weblate (Portuguese) [skip ci]

Currently translated at 76.3% (669 of 876 strings)

Translated using Weblate (Vietnamese) [skip ci]

Currently translated at 62.4% (547 of 876 strings)

Translated using Weblate (Turkish) [skip ci]

Currently translated at 62.5% (548 of 876 strings)

Translated using Weblate (Thai) [skip ci]

Currently translated at 62.4% (547 of 876 strings)

Translated using Weblate (Swedish) [skip ci]

Currently translated at 89.8% (787 of 876 strings)

Translated using Weblate (Russian) [skip ci]

Currently translated at 66.0% (579 of 876 strings)

Translated using Weblate (Romanian) [skip ci]

Currently translated at 62.4% (547 of 876 strings)

Translated using Weblate (Polish) [skip ci]

Currently translated at 65.6% (575 of 876 strings)

Translated using Weblate (Korean) [skip ci]

Currently translated at 62.6% (549 of 876 strings)

Translated using Weblate (Japanese) [skip ci]

Currently translated at 62.4% (547 of 876 strings)

Translated using Weblate (Italian) [skip ci]

Currently translated at 69.8% (612 of 876 strings)

Translated using Weblate (Icelandic) [skip ci]

Currently translated at 62.4% (547 of 876 strings)

Translated using Weblate (Hindi) [skip ci]

Currently translated at 62.4% (547 of 876 strings)

Translated using Weblate (Hebrew) [skip ci]

Currently translated at 63.8% (559 of 876 strings)

Translated using Weblate (French) [skip ci]

Currently translated at 67.1% (588 of 876 strings)

Translated using Weblate (Finnish) [skip ci]

Currently translated at 79.9% (700 of 876 strings)

Translated using Weblate (Greek) [skip ci]

Currently translated at 62.4% (547 of 876 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 89.1% (781 of 876 strings)

Translated using Weblate (Danish) [skip ci]

Currently translated at 62.4% (547 of 876 strings)

Translated using Weblate (Czech) [skip ci]

Currently translated at 62.4% (547 of 876 strings)

Translated using Weblate (Bulgarian) [skip ci]

Currently translated at 62.4% (547 of 876 strings)

Translated using Weblate (Arabic) [skip ci]

Currently translated at 62.5% (548 of 876 strings)

Translated using Weblate (Spanish) [skip ci]

Currently translated at 67.0% (587 of 876 strings)

Translated using Weblate (Dutch) [skip ci]

Currently translated at 65.8% (577 of 876 strings)

Translated using Weblate (Finnish) [skip ci]

Currently translated at 79.9% (700 of 876 strings)

Added translation using Weblate (Lithuanian) [skip ci]

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Csaba <csab0825@gmail.com>
Co-authored-by: Giorgio <sannagiorgio1997@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Maxent <rouaultmaxent@gmail.com>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: loksum213108 <lok3222003@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ar/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/bg/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/cs/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/da/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/el/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/he/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/hi/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/is/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ja/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ko/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/nl/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pl/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ro/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ru/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/sv/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/th/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/tr/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/uk/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/vi/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/zh_TW/
Translation: Servarr/Readarr
2022-07-13 11:01:02 -05:00
Weblate
199085249f Translated using Weblate (Portuguese) [skip ci]
Currently translated at 75.9% (665 of 876 strings)

Translated using Weblate (Hungarian) [skip ci]

Currently translated at 100.0% (876 of 876 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 88.0% (771 of 876 strings)

Translated using Weblate (Polish) [skip ci]

Currently translated at 64.2% (563 of 876 strings)

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

Currently translated at 100.0% (876 of 876 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 87.7% (769 of 876 strings)

Co-authored-by: Csaba <csab0825@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Marcin <ml.cichy@gmail.com>
Co-authored-by: Vitor Brito <main@vitorbrito.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: reloxx <reloxx@interia.pl>
Co-authored-by: ηg <jonas.konrath@icloud.com>
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pl/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt_BR/
Translation: Servarr/Readarr
2022-06-25 20:30:02 -05:00
ta264
b84041d95f Use DryIoc for Automoqer, drop Unity dependency
(cherry picked from commit e3468daba04b52fbf41ce3004934a26b0220ec4f)
(cherry picked from commit cf4103d73d74896daa12e7a0237e8923eaa6c095)
2022-06-22 10:13:37 +01:00
Robin Dadswell
615facb3c4 fixed test due to GoodReads BookId change 2022-06-15 23:28:43 +01:00
Weblate
b4fd1340c2 Translated using Weblate (Chinese (Simplified) (zh_CN)) [skip ci]
Currently translated at 68.1% (597 of 876 strings)

Translated using Weblate (Finnish) [skip ci]

Currently translated at 78.9% (692 of 876 strings)

Translated using Weblate (Polish) [skip ci]

Currently translated at 64.2% (563 of 876 strings)

Translated using Weblate (Hungarian) [skip ci]

Currently translated at 99.8% (875 of 876 strings)

Translated using Weblate (Hungarian) [skip ci]

Currently translated at 97.6% (855 of 876 strings)

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

Currently translated at 68.0% (596 of 876 strings)

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

Currently translated at 68.0% (596 of 876 strings)

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

Currently translated at 8.5% (75 of 876 strings)

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

Currently translated at 67.9% (595 of 876 strings)

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

Currently translated at 100.0% (876 of 876 strings)

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

Currently translated at 100.0% (851 of 851 strings)

Translated using Weblate (Italian) [skip ci]

Currently translated at 69.8% (594 of 851 strings)

Translated using Weblate (Finnish) [skip ci]

Currently translated at 81.3% (692 of 851 strings)

Translated using Weblate (Italian) [skip ci]

Currently translated at 69.8% (594 of 851 strings)

Translated using Weblate (Italian) [skip ci]

Currently translated at 69.6% (593 of 851 strings)

Translated using Weblate (Italian) [skip ci]

Currently translated at 69.6% (593 of 851 strings)

Co-authored-by: Csaba <csab0825@gmail.com>
Co-authored-by: Francesco <francy.ammirati@hotmail.com>
Co-authored-by: Giorgio <sannagiorgio1997@gmail.com>
Co-authored-by: Gjermund Wiggen <gjermundwiggen@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Matrixlee <matrix.alax@gmail.com>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Pan Jarek <jsawiuk@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: carreyli <laddie1987@qq.com>
Co-authored-by: un110 <13735581@qq.com>
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/nb_NO/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pl/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/zh_CN/
Translation: Servarr/Readarr
2022-06-11 15:13:19 -05:00
bakerboy448
1da27b0978 Fixed: Cleanse GoodReads oauth from logs 2022-05-30 09:26:47 +01:00
ta264
b0a3ddef9c Fixed: Speed up book api 2022-05-30 09:05:25 +01:00
ta264
a59706ceb4 Fixed: Removed unnecessary author data from book endpoint 2022-05-30 09:05:25 +01:00
nitsua
ce58e6ecdb Fixed: Mark as Failed errors
Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>

(cherry picked from commit a9792973eef960e8310a611cf1da2d2cada57532)
2022-05-25 17:02:44 +01:00
bakerboy448
d01ce8b908 Fixed: Added new and missing translations 2022-05-25 14:08:08 +01:00
ta264
575f995916 Reinstate tests 2022-05-24 21:16:00 +01:00
ta264
c17c8815ef New: Add linux-x86 builds
(cherry picked from commit 8907b06899483d7cb3ecb9546d82af00d129f8e1)
2022-05-25 13:06:39 +01:00
ta264
8445941510 New: .NET 6.0.5 2022-05-25 13:06:39 +01:00
ta264
32ae18ae6f Fix bad translation 2022-05-25 13:06:39 +01:00
PearsonFlyer
b91ec241a6 Fixed: Add translation for RestartRequiredHelpTextWarning 2022-05-15 20:18:29 +01:00
Qstick
17ce8187fd New: Instance name in System/Status API endpoint 2022-05-15 13:05:44 -05:00
Qstick
41615fe026 New: Instance name for Page Title 2022-05-15 13:05:44 -05:00
Robin Dadswell
9cff8f31e9 New: Instance Name used for Syslog 2022-05-15 13:05:44 -05:00
Robin Dadswell
21538b972d New: Set Instance Name 2022-05-15 13:05:44 -05:00
Robin Dadswell
5a7b4d41d8 New: Added UDP syslog support
(cherry picked from commit 8d856b2edb8bf46a2b516d5f7644ae3fa1151323)
2022-05-15 13:05:44 -05:00
Weblate
16f67265c9 Translated using Weblate (Finnish) [skip ci]
Currently translated at 79.7% (679 of 851 strings)

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

Currently translated at 100.0% (851 of 851 strings)

Translated using Weblate (Russian) [skip ci]

Currently translated at 67.3% (573 of 851 strings)

Translated using Weblate (Italian) [skip ci]

Currently translated at 66.3% (565 of 851 strings)

Translated using Weblate (Italian) [skip ci]

Currently translated at 66.3% (565 of 851 strings)

Translated using Weblate (Ukrainian) [skip ci]

Currently translated at 11.1% (95 of 851 strings)

Translated using Weblate (Slovak) [skip ci]

Currently translated at 5.5% (47 of 851 strings)

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

Currently translated at 7.1% (61 of 851 strings)

Translated using Weblate (Catalan) [skip ci]

Currently translated at 1.4% (12 of 851 strings)

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

Currently translated at 69.8% (594 of 851 strings)

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

Currently translated at 69.8% (594 of 851 strings)

Translated using Weblate (Portuguese) [skip ci]

Currently translated at 78.0% (664 of 851 strings)

Translated using Weblate (Vietnamese) [skip ci]

Currently translated at 63.8% (543 of 851 strings)

Translated using Weblate (Turkish) [skip ci]

Currently translated at 63.9% (544 of 851 strings)

Translated using Weblate (Thai) [skip ci]

Currently translated at 63.8% (543 of 851 strings)

Translated using Weblate (Swedish) [skip ci]

Currently translated at 91.5% (779 of 851 strings)

Translated using Weblate (Russian) [skip ci]

Currently translated at 66.2% (564 of 851 strings)

Translated using Weblate (Romanian) [skip ci]

Currently translated at 63.8% (543 of 851 strings)

Translated using Weblate (Polish) [skip ci]

Currently translated at 63.8% (543 of 851 strings)

Translated using Weblate (Korean) [skip ci]

Currently translated at 64.0% (545 of 851 strings)

Translated using Weblate (Japanese) [skip ci]

Currently translated at 63.8% (543 of 851 strings)

Translated using Weblate (Italian) [skip ci]

Currently translated at 66.3% (565 of 851 strings)

Translated using Weblate (Icelandic) [skip ci]

Currently translated at 63.8% (543 of 851 strings)

Translated using Weblate (Hindi) [skip ci]

Currently translated at 63.8% (543 of 851 strings)

Translated using Weblate (Hebrew) [skip ci]

Currently translated at 63.8% (543 of 851 strings)

Translated using Weblate (French) [skip ci]

Currently translated at 68.6% (584 of 851 strings)

Translated using Weblate (Finnish) [skip ci]

Currently translated at 79.7% (679 of 851 strings)

Translated using Weblate (Greek) [skip ci]

Currently translated at 63.8% (543 of 851 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 90.2% (768 of 851 strings)

Translated using Weblate (Danish) [skip ci]

Currently translated at 63.8% (543 of 851 strings)

Translated using Weblate (Czech) [skip ci]

Currently translated at 63.8% (543 of 851 strings)

Translated using Weblate (Bulgarian) [skip ci]

Currently translated at 63.8% (543 of 851 strings)

Translated using Weblate (Arabic) [skip ci]

Currently translated at 63.9% (544 of 851 strings)

Translated using Weblate (Spanish) [skip ci]

Currently translated at 68.5% (583 of 851 strings)

Translated using Weblate (Dutch) [skip ci]

Currently translated at 67.3% (573 of 851 strings)

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

Currently translated at 69.4% (591 of 851 strings)

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

Currently translated at 69.4% (591 of 851 strings)

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: DarkFighterLuke <luca-consoli@live.it>
Co-authored-by: Giorgio <sannagiorgio1997@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: ZakiZtraki <vovanjudo@gmail.com>
Co-authored-by: lhquark <lhquark@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ar/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/bg/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/cs/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/da/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/el/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/he/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/hi/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/is/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ja/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ko/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/nb_NO/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/nl/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pl/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ro/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ru/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/sk/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/sv/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/th/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/tr/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/uk/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/vi/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/zh_CN/
Translation: Servarr/Readarr
2022-05-09 17:32:50 -05:00
Qstick
03d2a85821 Fixed: Correct User-Agent api logging
(cherry picked from commit 5824ba963b480c920cee9d8ae6594c820167cd07)
2022-05-06 20:15:01 -05:00
Qstick
fa68a9559f Deleted translation using Weblate (zh_HANS (generated) (zh_HANS)) [skip ci] 2022-05-01 22:35:19 -05:00
Qstick
c4a2a432d2 Deleted translation using Weblate (zh_HANS (generated) (zh_HANS)) [skip ci] 2022-05-01 22:34:16 -05:00
Weblate
0b3eda4de3 Added translation using Weblate (zh_HANS (generated) (zh_HANS)) [skip ci]
Deleted translation using Weblate (Chinese (Min Nan)) [skip ci]

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

Currently translated at 22.6% (193 of 851 strings)

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

Currently translated at 58.5% (498 of 851 strings)

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

Currently translated at 100.0% (851 of 851 strings)

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

Currently translated at 3.2% (28 of 851 strings)

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

Currently translated at 58.5% (498 of 851 strings)

Translated using Weblate (Dutch) [skip ci]

Currently translated at 56.9% (485 of 851 strings)

Translated using Weblate (Dutch) [skip ci]

Currently translated at 56.8% (484 of 851 strings)

Update translation files [skip ci]

Updated by "Remove blank strings" hook in Weblate.

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

Currently translated at 3.1% (27 of 851 strings)

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

Currently translated at 100.0% (851 of 851 strings)

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

Currently translated at 1.6% (14 of 851 strings)

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

Currently translated at 100.0% (851 of 851 strings)

Translated using Weblate (French) [skip ci]

Currently translated at 58.7% (500 of 851 strings)

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

Currently translated at 98.8% (841 of 851 strings)

Translated using Weblate (Ukrainian) [skip ci]

Currently translated at 6.8% (58 of 851 strings)

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

Currently translated at 58.5% (498 of 851 strings)

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

Currently translated at 58.5% (498 of 851 strings)

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

Currently translated at 95.1% (810 of 851 strings)

Translated using Weblate (Hungarian) [skip ci]

Currently translated at 100.0% (851 of 851 strings)

Translated using Weblate (Finnish) [skip ci]

Currently translated at 70.7% (602 of 851 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 82.1% (699 of 851 strings)

Translated using Weblate (Spanish) [skip ci]

Currently translated at 59.3% (505 of 851 strings)

Translated using Weblate (Spanish) [skip ci]

Currently translated at 59.3% (505 of 851 strings)

Co-authored-by: Ana <phampyk@gmail.com>
Co-authored-by: AnlakHui <AnlakHui@gmail.com>
Co-authored-by: Csaba <csab0825@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: M1C <webnar@gmail.com>
Co-authored-by: Mateo Periago Serrano <mateoperi@pm.me>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Qstick <qstick@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: Zalhera <tobias.bechen@gmail.com>
Co-authored-by: andrey4korop <andrey999@i.ua>
Co-authored-by: jianjam <jianjam@qq.com>
Co-authored-by: killsover <w904202822@163.com>
Co-authored-by: lhquark <lhquark@gmail.com>
Co-authored-by: marcosteam <wdy71608161@gmail.com>
Co-authored-by: minermartijn <minermartijn@gmail.com>
Co-authored-by: neoestremi <remidu34070@hotmail.fr>
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/nl/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/uk/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/zh_CN/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/zh_Hans/
Translation: Servarr/Readarr
2022-05-01 22:34:16 -05:00
Mark McDowall
a1d4b3a0cf Fixed: UI hiding search results with duplicate GUIDs
(cherry picked from commit 458c5cd0b3c8efe6fc7cd852c357138468f8446e)
2022-04-24 13:54:39 -05:00
Douglas R Andreani
28f055e838 New: Add date picker for custom filter dates
(cherry picked from commit 5a08d5dc248bf1dbaa43264a2a470149cf716a3c)
2022-04-18 21:08:44 -05:00
Mark McDowall
8d91fb81bd Fixed: Interactive Search Filter not filtering multiple qualities in the same filter row
(cherry picked from commit c93f63cd204bf62dab3dffef6e29c8dd4c408cab)
2022-04-18 21:08:30 -05:00
bakerboy448
085913a852 Fixed: Clarify Qbit Content Path Error
(cherry picked from commit bba4a5636ed07277d82531c35cfc996bd17870eb)
2022-04-06 22:09:34 -05:00
ta264
8599fc4ee6 Fix .editorconfig to disallow this
(cherry picked from commit be29fc6adb2c8d8e52afea301118cf413bdc2d57)
2022-04-06 15:28:32 -05:00
Marcelo Castagna
68f017cd84 Fixed: Properly handle 119 error code from Synology Download Station
(cherry picked from commit 3be5d6c258bd947ae4c4d895b2f54faa5a7a222b)
2022-04-05 20:40:56 -05:00
bakerboy448
f34171444e Fixed: API error when sending payload without optional parameters
Co-authored-by: Qstick <qstick@gmail.com>

(cherry picked from commit 8d83b1d8d66ef24a25f312bdeac1e5625a630c00)
2022-04-05 20:40:36 -05:00
Qstick
10760471e0 Fixed: Cleanup Temp files after backup creation
(cherry picked from commit 7f0b708cb9f16a0116199625a2a5b4e67049be6a)
2022-04-05 20:40:13 -05:00
ta264
4ecabcd3d6 Fixed: Loading old commands from database
(cherry picked from commit 0f87cb72e559a19bddc6c9d4387ec7d9428291f8)
2022-04-02 20:05:00 +01:00
Weblate
1af2e14474 Translated using Weblate (Chinese (Simplified)) [skip ci]
Currently translated at 0.7% (6 of 851 strings)

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

Currently translated at 58.6% (499 of 851 strings)

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

Currently translated at 94.7% (806 of 851 strings)

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

Currently translated at 58.6% (499 of 851 strings)

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

Currently translated at 57.5% (490 of 851 strings)

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

Currently translated at 94.4% (804 of 851 strings)

Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: killsover <w904202822@163.com>
Co-authored-by: libsu <libsu@qq.com>
Co-authored-by: 無情天 <kofzhanganguo@126.com>
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/zh_CN/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/zh_Hans/
Translation: Servarr/Readarr
2022-04-01 07:32:31 -05:00
Ajax
fe836c56ee New: Update Cert Validation Help Text
(cherry picked from commit 66be23a7c4ae717cf060f5e89b4df7a08bdff5ac)

Closes #1541
Closes #1546
2022-03-31 20:46:08 -05:00
bakerboy448
ae611cca74 Fix Release Profile Typos 2022-03-31 20:46:08 -05:00
bakerboy448
c446f9835e Fixed: Clarify Indexer Priority Helptext
(cherrypicked from f4dbda1318564463b23056b866cb87a7c0e50393)

Closes #1481
2022-03-31 20:46:08 -05:00
bakerboy448
2ff8bf204f Fixed: Improve help text for download client Category
(cherry picked from commit d18751eff2c684a72e4c698a1e0f6c282c8da0da)

Closes #1535
2022-03-31 20:46:08 -05:00
Ajax
5aa17e7a67 Fixed: IPv4 instead of IP4
(cherry picked from commit c7427f8df828733a81d83ea28393a18d10875769)

Closes #1532
2022-03-31 20:46:08 -05:00
bakerboy448
312cf2d364 remove unnecessary usings 2022-03-31 20:44:49 -05:00
Taloth Saldono
a9852ded2f Add response size to http responses
(cherry picked from commit d899225509f04a9b6c72da19c7d63ff53498de22)
2022-03-23 19:58:08 -05:00
Weblate
4286f546e9 Translated using Weblate (Spanish) [skip ci]
Currently translated at 59.6% (508 of 851 strings)

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

Currently translated at 57.5% (490 of 851 strings)

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

Currently translated at 57.3% (488 of 851 strings)

Translated using Weblate (French) [skip ci]

Currently translated at 58.5% (498 of 851 strings)

Co-authored-by: EthanChoy <ethanchoy@163.com>
Co-authored-by: Kakise <sam.taa@icloud.com>
Co-authored-by: RicardoVelaC <ricardovelac@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: westay1984 <westjay@qq.com>
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/zh_CN/
Translation: Servarr/Readarr
2022-03-23 19:57:48 -05:00
Qstick
482fe04161 New: Add Validations for Recycle Bin Folder 2022-03-23 19:26:11 -05:00
Qstick
cbdc2c51c4 Improve path validation for Custom Script notifications 2022-03-23 19:21:12 -05:00
Weblate
f55fda9bac Translated using Weblate (Spanish) [skip ci]
Currently translated at 57.2% (487 of 851 strings)

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

Currently translated at 0.5% (5 of 851 strings)

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

Currently translated at 57.5% (490 of 851 strings)

Co-authored-by: Ayi <4ayixd@gmail.com>
Co-authored-by: Mateo Periago Serrano <mateoperi@pm.me>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: liuliping <306166677@qq.com>
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/zh_CN/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/zh_Hans/
Translation: Servarr/Readarr
2022-03-18 14:41:35 -05:00
Weblate
3841f7708e Translated using Weblate (Hungarian) [skip ci]
Currently translated at 100.0% (851 of 851 strings)

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

Currently translated at 91.8% (782 of 851 strings)

Translated using Weblate (Portuguese) [skip ci]

Currently translated at 68.7% (585 of 851 strings)

Co-authored-by: Csaba <csab0825@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: José Eduardo Veiga <vitruxpt@vitruxbot.com>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt_BR/
Translation: Servarr/Readarr
2022-03-11 01:44:35 -06:00
ta264
f2bfed0252 New: .NET 6.0.3 2022-03-09 21:47:57 +00:00
PearsonFlyer
bc7e4ea622 Fixed: Healthcheck warning message used incorrect variable 2022-03-09 14:14:54 -06:00
Marcelo Castagna
38f16e6b85 Update Synology error codes
(cherry picked from commit a8cb7784f2a6f833bda9e24ca2146701df8da75c)
2022-03-08 16:10:53 -06:00
Weblate
af57024c63 Translated using Weblate (French) [skip ci]
Currently translated at 57.5% (490 of 851 strings)

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

Currently translated at 0.1% (1 of 851 strings)

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

Currently translated at 90.7% (772 of 851 strings)

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

Currently translated at 90.7% (772 of 851 strings)

Translated using Weblate (Portuguese) [skip ci]

Currently translated at 66.8% (569 of 851 strings)

Translated using Weblate (Russian) [skip ci]

Currently translated at 56.0% (477 of 851 strings)

Translated using Weblate (Hungarian) [skip ci]

Currently translated at 100.0% (851 of 851 strings)

Translated using Weblate (Finnish) [skip ci]

Currently translated at 71.3% (607 of 851 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 82.4% (702 of 851 strings)

Translated using Weblate (Dutch) [skip ci]

Currently translated at 57.3% (488 of 851 strings)

Update translation files [skip ci]

Updated by "Cleanup translation files" hook in Weblate.

Update translation files [skip ci]

Updated by "Cleanup translation files" hook in Weblate.

Co-authored-by: AlexR-sf <omg.portal.supp@gmail.com>
Co-authored-by: Csaba <csab0825@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: KevoM <lilmarsu@gmail.com>
Co-authored-by: Nuno Filipe de Vilhena Santos <nunovilhenasantos@msn.com>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Renan da Mota Ciciliato <renanciciliato@gmail.com>
Co-authored-by: Rico_Walker <ricardo.walker1203@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: Zalhera <tobias.bechen@gmail.com>
Co-authored-by: nopetw <lubduphaur@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/nl/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ru/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/zh_TW/
Translation: Servarr/Readarr
2022-03-07 13:14:37 +00:00
bakerboy448
54faa58a4d Fixed: Assume SABnzbd develop version is 3.0.0 if not specified
(cherry picked from commit 77412f23766e8bb553e83d87f1e599e795a67f8b)
2022-03-06 21:27:33 -06:00
servarr[bot]
8ca35a709c Fixed: Updater version number logging
(cherry picked from commit b34f4fde1bbe611bb5c886890e3be7cec2b96e6b)
2022-03-06 21:26:52 -06:00
bakerboy448
72a0e38b36 Fixed: Update from version in logs
Closes #1574

(cherry picked from commit bc3e3714b97dec19091e45324d9f2b550f1dbbd5)
2022-03-04 20:46:06 -06:00
bakerboy448
b25f8449a2 New: Add more information about Windows service to installer
Closes #520
2022-02-22 20:54:53 +00:00
Mark McDowall
cf0a15a308 Fixed: Recycle bin log message
(cherry picked from commit 9e1b799fb74c341510d6da98f9f658d642b25c02)
2022-02-22 12:46:43 -06:00
ta264
a677098f0f Fixed: Make authentication cookie name unique to Readarr 2022-02-20 21:32:38 +00:00
ta264
a40cce9c71 Bump to 0.1.1 2022-02-20 21:31:57 +00:00
ta264
6d94136273 Report runtime identifier to sentry
[common]
2022-02-20 13:32:21 +00:00
ta264
f6d620f969 Fixed: Crash on startup on arm32 due to ImageSharp
See https://github.com/SixLabors/ImageSharp/issues/2001
2022-02-20 12:06:06 +00:00
ta264
8d9302da77 Fixed: No longer require first run as admin on windows 2022-02-16 21:07:58 +00:00
ta264
f5cbab6ac9 Fixed: Exception tagging audio files on import
Fixes #1523
2022-02-15 21:51:23 +00:00
ta264
cb0ae36033 Fixed: Enable response compression over https
[common]
2022-02-15 21:11:39 +00:00
ta264
93a42e2fe9 Fix duplicates in author search 2022-02-11 21:32:09 +00:00
ta264
0f9ab46dd6 New: Upgrade to .NET 6.0.2 2022-02-09 20:59:34 +00:00
ta264
3a360d7a1e Fixed: Contain memory usage during library import 2022-02-09 20:59:34 +00:00
ta264
8e37aa2e78 Fixed: Take publisher and format into account when choosing best edition 2022-02-09 20:59:34 +00:00
ta264
000022a927 Fixed: Return sensible value from Levenshtein when distance too large 2022-02-09 20:59:34 +00:00
ta264
2bfc50b59b Fixed: Don't forget about existing match when trying remote candidates 2022-02-09 20:59:34 +00:00
ta264
4f46ab9a9a Speed up FuzzyContains a bit more 2022-02-04 19:57:24 +00:00
ta264
e7410959fe Fixed: Correct and speed up FuzzyContains
Fixes READARR-C1
2022-02-04 17:28:33 +00:00
PearsonFlyer
ee1112026a Fixed: Updated ruTorrent stopped state helptext 2022-01-26 10:52:43 -06:00
ta264
65681cad10 Fixed: Catch any exceptions thrown identifying books 2022-01-25 21:02:33 +00:00
ta264
9653f9bbca Fixed: Error reading PDF file
Fixes READARR-6P
2022-01-24 21:16:55 +00:00
ta264
6f97ca9a55 Fixed: Handle missing category when getting Qbittorrent download path
[common]

Fixes READARR-2VR
Fixes READARR-1GP
2022-01-24 21:13:20 +00:00
ta264
c0e193dd1f Fixed: Improve fuzzy matching algorithm to match around word boundaries
Fixes READARR-C1
2022-01-24 20:58:00 +00:00
ta264
ecf1e1a130 Fixed: Error splitting subtitle from book title
Fixes #1473
Fixes READARR-39N
Fixes READARR-3ES
Fixes READARR-6CM
2022-01-24 20:58:00 +00:00
PearsonFlyer
967dae5132 Fixed: Email attachments of ebooks 2022-01-24 18:04:36 -06:00
PearsonFlyer
f4b96dc45e Fixed: Avoid download path check false positives for Flood
(cherry picked from commit d4d4bf8784fedbf76f938685229a700a2e552e79)
2022-01-23 16:22:26 -06:00
bakerboy448
8181749629 Fixed: Improved Indexer test failure message when no results are returned
(cherry picked from commit 05b1581b7dfa5bc8a2b38a60179e3472c8134f74)
2022-01-23 16:19:18 -06:00
PearsonFlyer
9bca258541 Fixed: Changed movie references to book 2022-01-22 15:04:08 -06:00
bakerboy448
77d2db3c47 Fixed: More Translations 2022-01-22 19:23:24 +00:00
ta264
1dd61e826b Fixed: SourceTitle if Book Title null in Discord ImportFailed event
Fixes READARR-FG
2022-01-20 22:08:00 +00:00
ta264
857a5f5005 Fix remote path mapping health check interface 2022-01-20 22:21:41 +00:00
bakerboy448
a321288a71 Fixed: Various Translations
Fixes #1209
2022-01-21 13:45:54 +00:00
ta264
62a3355546 Remove unused code 2022-01-21 13:28:04 +00:00
ta264
6db135877a Build installer from build.sh
[common]
2022-01-21 13:28:04 +00:00
ta264
fa1985509d Centralise image choice, update to latest images
[common]
2022-01-21 13:28:04 +00:00
ta264
01a5c456c4 Fixed: Set part numbers using alphabetical file ordering if not set in tags 2022-01-19 21:29:50 +00:00
ta264
3ec451e85e Fixed: Correct the 'Ignored' history filter
Closes #1463
2022-01-19 21:29:50 +00:00
Weblate
bf7fc6fa19 Translated using Weblate (Portuguese (Brazil)) [skip ci]
Currently translated at 96.4% (763 of 791 strings)

Translated using Weblate (Hungarian) [skip ci]

Currently translated at 100.0% (791 of 791 strings)

Update translation files [skip ci]

Updated by "Cleanup translation files" hook in Weblate.

Update translation files [skip ci]

Updated by "Cleanup translation files" hook in Weblate.

Translated using Weblate (Hungarian) [skip ci]

Currently translated at 100.0% (787 of 787 strings)

Co-authored-by: Csaba <csab0825@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt_BR/
Translation: Servarr/Readarr
2022-01-20 11:17:28 +00:00
Mark McDowall
cbf2f0f4fb Fixed: Jump bar on series page not showing when window is made wider
(cherry picked from commit 0cb8d93069d6310abd39ee2fe73219e17aa83fe6)
2022-01-20 11:16:37 +00:00
ta264
565fb77713 Fixed: Attempt to fix uncaught exceptions fetching book data
Closes #1465
Closes #1464
2022-01-20 10:50:51 +00:00
Robin Dadswell
3ea0c8e5fa New: End Jackett 'all' endpoint support
(cherry picked from commit 54c914d48fefa730728518d50fc9e49032d0947b)
2022-01-20 10:50:51 +00:00
Qstick
61454955be New: Support server notifications
(cherry picked from commit f5f0dd6fae5bc9f308506d56be42ac9a4be908e7)
2022-01-20 10:50:51 +00:00
ta264
34506025ac Fixed: Better searching for local candidate editions 2022-01-20 10:50:51 +00:00
ta264
ef35efb127 Fixed: Make sure exactly one edition is monitored when using remote candidates 2022-01-20 10:50:51 +00:00
ta264
2a4f681b17 Fixed: Speed up RSS sync 2022-01-20 10:50:51 +00:00
bakerboy448
24e2ff56dd New: Various Healthcheck enhancements
Various pulls from Radarr;  Completed at the file - not commit - level
2022-01-19 18:47:38 +00:00
Qstick
c5787b0c87 New: Add AppName to system status response 2022-01-18 23:26:09 -06:00
Qstick
d6ba6bbfd1 Fixed: Parse endpoint response when title failed to parse
Fixes #1175

Co-Authored-By: Taloth <Taloth@users.noreply.github.com>
2022-01-18 18:35:10 -06:00
ta264
de72cfcaaa Update DSN 2022-01-16 22:37:06 +00:00
ta264
90d671d68d Fixed: Error fetching metadata when redirected to work endpoint 2022-01-16 22:09:21 +00:00
ta264
b4b14a5359 Fixed: Error parsing books with no contributors
Fixes #1454
2022-01-16 22:09:21 +00:00
ta264
759c132797 Fixed: Allow scrolling in Select Edition modal
Fixes #1442
2022-01-16 22:09:21 +00:00
ta264
dc1fbb3a7e Fixed: Support nested file naming formats 2022-01-16 22:09:21 +00:00
ta264
eb431f09fd Fixed: Close all database connections on shutdown to remove shm/wal files
[common]
2022-01-16 22:00:47 +00:00
ta264
0031214fb3 Fixed: Check language of book file matches edition language if possible 2022-01-16 21:57:09 +00:00
bakerboy448
94adb4d582 Fixed: Added Various Missing Translations
cleanup en.json of unused translates

Fixes #1397

Closes Sonarr PR # 4791 'Fixed: Better wording of MissingFromDisk'
2022-01-16 21:53:43 +00:00
ta264
bc3764dcda Fixed: Error getting search results when there is only one result 2022-01-16 21:47:52 +00:00
bakerboy448
64fafc599c fix calibre validation typo 2022-01-17 09:17:01 +00:00
ta264
53f66606bc New: Upgrade to .NET 6.0.1 2022-01-17 09:14:28 +00:00
Qstick
706f8310bb Fixed: Use general settings cert validation for email 2022-01-17 09:14:28 +00:00
ta264
ae4994571a Fixed: Use our own HttpClient for Aria2 requests 2022-01-17 09:14:28 +00:00
ta264
258847a83b Fixed: Use our own HttpClient for rTorrent RPC requests 2022-01-17 09:14:28 +00:00
Qstick
43f1d77b9f Fixed: Twitter connect not sending messages after http rework 2022-01-17 09:14:28 +00:00
ta264
f451796cf5 Fixed: Better check for write access in Calibre 2022-01-16 13:33:16 +00:00
Weblate
620fb57b30 Translated using Weblate (Portuguese (Brazil)) [skip ci]
Currently translated at 99.7% (785 of 787 strings)

Translated using Weblate (Hungarian) [skip ci]

Currently translated at 100.0% (787 of 787 strings)

Translated using Weblate (Hungarian) [skip ci]

Currently translated at 100.0% (787 of 787 strings)

Translated using Weblate (Finnish) [skip ci]

Currently translated at 71.2% (561 of 787 strings)

Translated using Weblate (Russian) [skip ci]

Currently translated at 63.0% (496 of 787 strings)

Translated using Weblate (Finnish) [skip ci]

Currently translated at 71.1% (560 of 787 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 70.3% (554 of 787 strings)

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

Currently translated at 99.7% (785 of 787 strings)

Translated using Weblate (Russian) [skip ci]

Currently translated at 63.0% (496 of 787 strings)

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

Currently translated at 99.8% (769 of 770 strings)

Translated using Weblate (Russian) [skip ci]

Currently translated at 64.2% (495 of 770 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 71.9% (554 of 770 strings)

Translated using Weblate (Russian) [skip ci]

Currently translated at 64.2% (495 of 770 strings)

Co-authored-by: AlexR-sf <omg.portal.supp@gmail.com>
Co-authored-by: Csaba <csab0825@gmail.com>
Co-authored-by: Gian Klug <gian.klug@ict-scouts.ch>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: diemade <spamkill@posteo.ch>
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ru/
Translation: Servarr/Readarr
2022-01-15 13:25:44 +00:00
PearsonFlyer
bca70e931f Fixed: Translation warning for search all 2022-01-15 13:12:24 +00:00
ta264
c7f0a8578a Fixed: Calibre auth check when library missing 2022-01-15 06:04:15 +00:00
ta264
c92563ea10 New: Validate remote calibre servers have authentication enabled 2022-01-14 19:54:18 +00:00
ta264
66e7ce6f27 Fixed: Queue items hanging in 'Downloaded - Importing' state 2022-01-14 19:54:18 +00:00
ta264
b1da9a1934 Fixed: Null reference setting download history for unmapped downloads 2022-01-14 19:54:17 +00:00
BookInfo
1491788081 Move all data fetching to BookInfo v2 2022-01-14 19:54:06 +00:00
ta264
33e1c4a537 Fixed: Books must match the edition title, not the work title 2022-01-03 21:23:58 +00:00
ta264
8c3dd3730a Fixed: Determine book author as primary author of most popular edition 2022-01-03 21:17:52 +00:00
bakerboy448
02927dc37d Fixed: Various Wiki Links 2021-12-30 16:39:18 -06:00
Robin Dadswell
be46d5ae8f New: On delete notifications 2021-12-30 16:38:49 -06:00
bakerboy448
e4fdf71eee New: Display Unknown Items in Activity Queue by Default 2021-12-27 17:46:48 -06:00
ta264
9a2260a00f Revert "Move all data fetching to BookInfo"
This reverts commit f6ff53ca31.
2021-12-26 19:01:35 +00:00
Qstick
399a370e7a Fix Index creation on migration 20 2021-12-25 15:20:58 -06:00
Weblate
ff27ad2096 Translated using Weblate (Slovak) [skip ci]
Currently translated at 6.2% (48 of 770 strings)

Translated using Weblate (Icelandic) [skip ci]

Currently translated at 63.8% (492 of 770 strings)

Translated using Weblate (Hebrew) [skip ci]

Currently translated at 64.2% (495 of 770 strings)

Translated using Weblate (Italian) [skip ci]

Currently translated at 65.9% (508 of 770 strings)

Translated using Weblate (Dutch) [skip ci]

Currently translated at 65.7% (506 of 770 strings)

Translated using Weblate (Polish) [skip ci]

Currently translated at 63.8% (492 of 770 strings)

Translated using Weblate (Spanish) [skip ci]

Currently translated at 64.6% (498 of 770 strings)

Translated using Weblate (Greek) [skip ci]

Currently translated at 63.8% (492 of 770 strings)

Translated using Weblate (Vietnamese) [skip ci]

Currently translated at 63.8% (492 of 770 strings)

Translated using Weblate (Romanian) [skip ci]

Currently translated at 63.8% (492 of 770 strings)

Translated using Weblate (Thai) [skip ci]

Currently translated at 63.8% (492 of 770 strings)

Translated using Weblate (Russian) [skip ci]

Currently translated at 64.2% (495 of 770 strings)

Translated using Weblate (Korean) [skip ci]

Currently translated at 62.9% (485 of 770 strings)

Translated using Weblate (French) [skip ci]

Currently translated at 66.1% (509 of 770 strings)

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

Currently translated at 66.2% (510 of 770 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 71.6% (552 of 770 strings)

Translated using Weblate (Turkish) [skip ci]

Currently translated at 64.0% (493 of 770 strings)

Translated using Weblate (Czech) [skip ci]

Currently translated at 64.2% (495 of 770 strings)

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

Currently translated at 8.1% (63 of 770 strings)

Translated using Weblate (Portuguese) [skip ci]

Currently translated at 76.7% (591 of 770 strings)

Translated using Weblate (Arabic) [skip ci]

Currently translated at 64.0% (493 of 770 strings)

Translated using Weblate (Swedish) [skip ci]

Currently translated at 96.4% (743 of 770 strings)

Translated using Weblate (Finnish) [skip ci]

Currently translated at 72.7% (560 of 770 strings)

Translated using Weblate (Bulgarian) [skip ci]

Currently translated at 63.7% (491 of 770 strings)

Translated using Weblate (Japanese) [skip ci]

Currently translated at 63.8% (492 of 770 strings)

Translated using Weblate (Hindi) [skip ci]

Currently translated at 63.8% (492 of 770 strings)

Translated using Weblate (Danish) [skip ci]

Currently translated at 63.8% (492 of 770 strings)

Translated using Weblate (Finnish) [skip ci]

Currently translated at 72.7% (560 of 770 strings)

Added translation using Weblate (Ukrainian) [skip ci]

Added translation using Weblate (Persian) [skip ci]

Added translation using Weblate (Bengali) [skip ci]

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

Currently translated at 100.0% (770 of 770 strings)

Translated using Weblate (Russian) [skip ci]

Currently translated at 62.0% (478 of 770 strings)

Translated using Weblate (Hungarian) [skip ci]

Currently translated at 100.0% (770 of 770 strings)

Translated using Weblate (Portuguese) [skip ci]

Currently translated at 74.8% (575 of 768 strings)

Co-authored-by: AlexR-sf <omg.portal.supp@gmail.com>
Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Csaba <csab0825@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Nuno Filipe de Vilhena Santos <nunovilhenasantos@msn.com>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ar/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/bg/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/cs/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/da/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/el/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/he/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/hi/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/is/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ja/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ko/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/nb_NO/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/nl/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pl/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ro/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ru/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/sk/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/sv/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/th/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/tr/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/vi/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/zh_CN/
Translation: Servarr/Readarr
2021-12-24 10:12:41 -06:00
ta264
76bcf94f1d Fixed: Added missing sort token details for poster views
Fixes #1424
2021-12-23 21:41:43 +00:00
ta264
472da10149 Fixed: Fix book index footer stats
Fixes #1405
Fixes #1407
2021-12-23 21:41:43 +00:00
ta264
8011112919 Fixed: Error opening manual import for unmatched items
Fixes #1425
2021-12-23 21:41:43 +00:00
ta264
6d8adec7dc Fixed: Frontend error sorting book index by status
Fixes #1426
2021-12-23 21:41:43 +00:00
ta264
29c7404185 Fixed: Send primary series to Calibre
Fixes #1419
2021-12-23 21:41:43 +00:00
BookInfo
f6ff53ca31 Move all data fetching to BookInfo 2021-12-24 15:41:29 +00:00
Davide Z
2dff18490e remove movies reference from readme.MD (#1423)[skip ci] 2021-12-21 09:45:32 -06:00
Qstick
6d7657e8b3 Bump RestSharp to 106.15.0
Fixes #1400
2021-12-18 10:30:48 -06:00
ta264
0db6cf272f New: Add release date sort option to book index view
Fixes #1403
2021-12-16 21:22:54 +00:00
ta264
5827644300 Fixed: Error getting seed config for rtorrent 2021-12-16 21:50:07 +00:00
ta264
d1f1052d7d Fixed: Missing / Wanted filter on book index view
Fixes #1366
2021-12-16 20:12:04 +00:00
ta264
341d64ebf7 Fixed: Don't try to read audio tags from a book file 2021-12-15 11:55:55 +00:00
ta264
c817d6c0d8 Fixed: Error 'Book with Id not found' in manual import 2021-12-15 11:55:55 +00:00
ta264
735fceb074 Fixed: Prevent duplicate searches on list add 2021-12-15 11:55:55 +00:00
ta264
0e43f67a9f Fixed: Track when calibre changes files to prevent unnecessary re-scans 2021-12-15 11:55:55 +00:00
ta264
eb95fe265a New: Send genres to calibre as tags 2021-12-15 11:55:55 +00:00
Taloth Saldono
3e32f7d49f Clarified Aria2 RPC Path field.
closes #4738
2021-12-15 11:55:55 +00:00
Mark McDowall
4b8c739b5c Aria2 fixes
Fixed: Removing completed downloads from Aria2
Fixed: Return correct path for Aria2 downloads in a job folder
Fixed: Seeding torrents in Aria2 are treated as finished downloading
2021-12-15 11:55:55 +00:00
Qstick
eeb172d3bf Aria2 formatting cleanup 2021-12-15 11:55:55 +00:00
Mark McDowall
e2745c5956 Fixed: Blocklisting pending releases 2021-12-15 11:55:55 +00:00
LLeny
ede981f737 New: Aria2 Torrent Client 2021-12-15 11:55:55 +00:00
Jesse Chan
e2c1d76516 Flood: explicitly cast DateFinished long? to long 2021-12-15 11:55:55 +00:00
Jesse Chan
05a8a3d764 New: Removing Flood downloads when seeding criteria have been met 2021-12-15 11:55:55 +00:00
leaty
da262f3d95 New: Removing rtorrent downloads when seeding criteria have been met
(cherry picked from commit 411be4d0116f0739bb9c71235312d0c5a26dd3a2)
2021-12-15 11:55:55 +00:00
Taloth Saldono
a5b1711827 Fixed: Refreshing Plex Server series in high volume systems
(cherry picked from commit 3fb55e9defdb90ab807fcacff249193a4d6114d5)
2021-12-15 11:55:55 +00:00
Mark McDowall
7b0802cfd6 Fixed: Errors loading queue after episodes in series are removed
Closes #3565
2021-12-15 11:55:55 +00:00
Mark McDowall
16fcba02ba Fixed: Update path before importing to ensure it hasn't changed
Closes #684
2021-12-15 11:55:55 +00:00
Mark McDowall
b3c217d713 Some cleanup of things marked for removal in v3 2021-12-15 11:55:55 +00:00
Mark McDowall
975ff0baf3 Mark completed imports based on history as imported to remove from queue 2021-12-15 11:55:55 +00:00
Mark McDowall
0bb8672119 Fixed: Mark "BAD" Nzbget Downloads as Failed 2021-12-15 11:55:55 +00:00
Mark McDowall
9ebeee8b4f Fixed: Exception thrown when marking download as complete
Closes #326

(cherry picked from commit 27a9edf33d6ddb5f028f19b308245a067f1d8f2a)
2021-12-15 11:55:55 +00:00
Mark McDowall
894adbe91e Fixed: Error when processing release with files Sonarr is unable to parse 2021-12-15 11:55:55 +00:00
Mark McDowall
e7628476f7 Additional logging when trying to complete tracked downloads
(cherry picked from commit 2df6b5370067635fdc9196451e09e4c2e6427eac)
2021-12-15 11:55:55 +00:00
Mark McDowall
3e5045e496 Fixed: Not removing seeded download if it was manual imported in some cases 2021-12-15 11:55:55 +00:00
Mark McDowall
95d93dfa09 Fixed: Manual import for unknown series items will properly mark as imported
Fixes: #277
(cherry picked from commit 3ffcf114682f9b1730f54706ecbf1bf237206bb1)
2021-12-15 11:55:55 +00:00
Mark McDowall
842f80d567 Fixed: Imports triggered through API not being marked as imported/removed from client
Fixes #258

(cherry picked from commit 382bcbcbeddcf04d5bc361744b6b57ca3c2c54e6)
2021-12-15 11:55:55 +00:00
Mark McDowall
fc8b6014ec Fixed: Imported downloads not being removed when seeding goals are met
Fixes #3693
2021-12-15 11:55:55 +00:00
Mark McDowall
6fb24128f8 Fixed: Episodes removed from queue re-appearing on refresh
Fixes #249

(cherry picked from commit 1a921c09e5180e283f52411dd2d0344a96015c0c)
2021-12-15 11:55:55 +00:00
Mark McDowall
8dbd006978 Fixed: Remove seeded downloads if they've finished seeding after import 2021-12-15 11:55:55 +00:00
Mark McDowall
fed67044f0 Fixed: Don't process downloads removed from the client 2021-12-15 11:55:55 +00:00
Mark McDowall
f7c05d98a9 Don't re-trigger completed event 2021-12-15 11:55:55 +00:00
Mark McDowall
25b37ace34 Track fully imported downloads in separate history table
New: Improved detection of already imported downloads
Closes #232
2021-12-15 11:55:55 +00:00
Servarr
e1eb9a0ba7 Translations from Weblate 2021-12-12 11:05:34 -06:00
ta264
b6055c3339 Fixed: Correctly set MonitorNewItems for new list authors 2021-12-08 21:30:24 +00:00
bakerboy448
0e78d8d535 Fixed: Support older glibc in libMonoPosixHelper
(based on Prowlarr 9e7af8369e165c19a2f181071e63bef6961cd64e)
2021-12-08 16:11:06 -06:00
ta264
0cf7953cab Fixed: Correctly force add duplicate books 2021-12-06 21:09:05 +00:00
Weblate
0d3cd24fb2 Translated using Weblate (Portuguese (Brazil)) [skip ci]
Currently translated at 98.4% (756 of 768 strings)

Translated using Weblate (Hungarian) [skip ci]

Currently translated at 100.0% (768 of 768 strings)

Translated using Weblate (Italian) [skip ci]

Currently translated at 64.7% (495 of 764 strings)

Translated using Weblate (Hungarian) [skip ci]

Currently translated at 100.0% (764 of 764 strings)

Translated using Weblate (Finnish) [skip ci]

Currently translated at 70.5% (539 of 764 strings)

Co-authored-by: Csaba <csab0825@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: hidaba <nag@hidaba.com>
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt_BR/
Translation: Servarr/Readarr
2021-12-05 10:53:12 -06:00
bakerboy448
41d7a1f355 update contributing [skip ci] 2021-12-03 11:11:54 +00:00
bakerboy448
608c0f268f fixup! readme updates [skip ci] 2021-12-03 11:11:54 +00:00
bakerboy448
8c38e4ede8 readme updates [skip ci] 2021-12-03 11:11:54 +00:00
bakerboy448
4f791f965a Update Github Templates [skip ci]
(cherry picked from commit beb22844c960db8e0f42a32809ad74cffce06e09)
2021-12-03 11:11:38 +00:00
PearsonFlyer
0b0bebf3aa Fixed: Improved root folder setup page
(cherry picked from commit eb4f55de85)
2021-12-02 21:59:59 +00:00
ta264
05a0508d78 Fixed: Add author/book fails unless you change Monitor New Items value 2021-12-02 21:15:49 +00:00
ta264
6cecf23b88 Fixed: Removing from Goodreads shelf when different edition imported 2021-12-02 21:40:28 +00:00
Weblate
fb0128e3be Translated using Weblate (Portuguese (Brazil)) [skip ci]
Currently translated at 100.0% (757 of 757 strings)

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

Currently translated at 64.4% (488 of 757 strings)

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

Currently translated at 99.7% (755 of 757 strings)

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

Currently translated at 98.1% (743 of 757 strings)

Translated using Weblate (Finnish) [skip ci]

Currently translated at 68.6% (520 of 757 strings)

Translated using Weblate (Finnish) [skip ci]

Currently translated at 68.6% (520 of 757 strings)

Translated using Weblate (Hungarian) [skip ci]

Currently translated at 100.0% (757 of 757 strings)

Translated using Weblate (Finnish) [skip ci]

Currently translated at 67.6% (512 of 757 strings)

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

Currently translated at 99.7% (743 of 745 strings)

Translated using Weblate (Hungarian) [skip ci]

Currently translated at 100.0% (745 of 745 strings)

Translated using Weblate (Finnish) [skip ci]

Currently translated at 66.8% (498 of 745 strings)

Co-authored-by: Csaba <csab0825@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Lizandra Candido da Silva <lizandra.c.s@gmail.com>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: mm519897405 <baiya@vip.qq.com>
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/zh_CN/
Translation: Servarr/Readarr
2021-12-02 20:06:24 +00:00
ta264
6947e6e34c Fixed: Speed up initial author load 2021-12-01 21:56:48 +00:00
ta264
c51ae664aa New: Option to control which new author books get monitored 2021-12-01 21:23:23 +00:00
ta264
1d694af98e Workaround .net error serializing new object()
See https://github.com/dotnet/runtime/issues/61995
2021-12-01 21:23:22 +00:00
ta264
bc678e1976 Fixed: Books added via import list default to 'Automatically Switch Edition'
Fixes #565
2021-12-01 21:13:59 +00:00
Taloth Saldono
c0db20a860 Fixed: OSX version detection
ref sonarr/4113 (not a fix, just partially)

(cherry picked from commit 026af222297d1d90d824e077e989ffd146bb5016)
2021-12-01 22:04:33 +00:00
Mark McDowall
621bb20756 Improve default path for Synology Download Station
Fixes: Missing default path for Download Station
Fixes: Error when getting destination path for Synology Download Station in health check

(cherry picked from commit 4bf3ab1511b4ea25642476bf9df13f91b6f73d76)
2021-12-01 21:18:46 +00:00
ta264
326d395da4 Fixed: Don't allow interactive import while book match is calculating
Fixes #1238
2021-11-29 21:49:12 +00:00
ta264
7be2effa05 Fixed: Sort by path in book index view
Fixes #1233
2021-11-28 19:24:39 +00:00
ta264
8f965a7cd5 New: Add book custom filters for author and automatic release switching
Fixes #1355
2021-11-28 19:19:39 +00:00
ta264
15dee29057 Fixed: Missing Book column in cutoff unmet 2021-11-28 19:11:18 +00:00
ta264
61617ff5bc Bump System.Data.Sqlite to fix osx-arm64 builds 2021-11-28 18:18:03 +00:00
ta264
27e3b5e630 Fixed: Windows installer and adding/removing services
Fixes #1361
2021-11-28 18:18:03 +00:00
ta264
1b6694739e Fixed: Sorting by Series, Rating and Status on author details page
Fixes #1315
2021-11-23 21:55:33 +00:00
ta264
a7c0eabb56 New: Series file naming tokens
Closes #25
Closes #26
2021-11-23 21:05:40 +00:00
Qstick
7c5188638f Fixed: Combine content headers with response headers
(cherry picked from commit c4cf38255e422b5c0d4e5c3909810cc596b0510b)
2021-11-24 01:59:19 +00:00
ta264
4ce405728a New: Add osx-arm64 and linux-musl-arm builds 2021-11-22 19:06:02 +00:00
ta264
615acdaebe New: Combine mass editor and author editor, enable book editor 2021-11-22 19:05:39 +00:00
Weblate
d460cbf319 merge 2021-11-20 16:51:49 +00:00
ta264
4887ed0d2f New: Book editor on author details page 2021-11-19 20:03:32 +00:00
ta264
bf852cadbe Fixed: Prevent frontend errors when many books added to Readarr 2021-11-19 20:03:32 +00:00
ta264
05d24821f7 Fixed: Restarting windows service from UI
(cherry picked from commit 3ae1ccc5e25eb16420c1f4ab627f42e3f478b22e)
2021-11-19 20:03:32 +00:00
ta264
04e575903f Fixed: Tray app restart
(cherry picked from commit 5fce3bbedb48edc547d1e6a1db3af06b5542886d)
2021-11-19 20:03:32 +00:00
ta264
dfb9558868 Fixed: Broken SSL certificate validation option
(cherry picked from commit a6a761cb32a268c4447071dc692c428789063fce)
2021-11-19 20:03:32 +00:00
Weblate
808fb5f2aa Translated using Weblate (Chinese (Simplified) (zh_CN)) [skip ci]
Currently translated at 65.7% (488 of 742 strings)

Translated using Weblate (Korean) [skip ci]

Currently translated at 65.0% (483 of 742 strings)

Translated using Weblate (Japanese) [skip ci]

Currently translated at 65.3% (485 of 742 strings)

Translated using Weblate (Italian) [skip ci]

Currently translated at 66.3% (492 of 742 strings)

Translated using Weblate (Icelandic) [skip ci]

Currently translated at 65.3% (485 of 742 strings)

Translated using Weblate (Hungarian) [skip ci]

Currently translated at 100.0% (742 of 742 strings)

Translated using Weblate (Hindi) [skip ci]

Currently translated at 65.3% (485 of 742 strings)

Translated using Weblate (Hebrew) [skip ci]

Currently translated at 65.3% (485 of 742 strings)

Translated using Weblate (French) [skip ci]

Currently translated at 67.2% (499 of 742 strings)

Translated using Weblate (Finnish) [skip ci]

Currently translated at 65.3% (485 of 742 strings)

Translated using Weblate (Greek) [skip ci]

Currently translated at 65.3% (485 of 742 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 73.1% (543 of 742 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 73.1% (543 of 742 strings)

Translated using Weblate (Danish) [skip ci]

Currently translated at 65.3% (485 of 742 strings)

Translated using Weblate (Czech) [skip ci]

Currently translated at 65.3% (485 of 742 strings)

Translated using Weblate (Bulgarian) [skip ci]

Currently translated at 65.2% (484 of 742 strings)

Translated using Weblate (Arabic) [skip ci]

Currently translated at 65.4% (486 of 742 strings)

Translated using Weblate (Spanish) [skip ci]

Currently translated at 65.7% (488 of 742 strings)

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Csaba <csab0825@gmail.com>
Co-authored-by: mm519897405 <baiya@vip.qq.com>
Co-authored-by: reloxx <reloxx@interia.pl>
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ar/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/bg/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/cs/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/da/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/el/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/he/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/hi/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/is/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ja/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ko/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/zh_CN/
Translation: Servarr/Readarr
2021-11-18 02:00:01 -06:00
Weblate
9f62ee34f1 Translated using Weblate (Hungarian) [skip ci]
Currently translated at 100.0% (743 of 743 strings)

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

Currently translated at 65.7% (488 of 742 strings)

Translated using Weblate (Korean) [skip ci]

Currently translated at 65.0% (483 of 742 strings)

Translated using Weblate (Japanese) [skip ci]

Currently translated at 65.3% (485 of 742 strings)

Translated using Weblate (Italian) [skip ci]

Currently translated at 66.3% (492 of 742 strings)

Translated using Weblate (Icelandic) [skip ci]

Currently translated at 65.3% (485 of 742 strings)

Translated using Weblate (Hungarian) [skip ci]

Currently translated at 100.0% (742 of 742 strings)

Translated using Weblate (Hindi) [skip ci]

Currently translated at 65.3% (485 of 742 strings)

Translated using Weblate (Hebrew) [skip ci]

Currently translated at 65.3% (485 of 742 strings)

Translated using Weblate (French) [skip ci]

Currently translated at 67.2% (499 of 742 strings)

Translated using Weblate (Finnish) [skip ci]

Currently translated at 65.3% (485 of 742 strings)

Translated using Weblate (Greek) [skip ci]

Currently translated at 65.3% (485 of 742 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 73.1% (543 of 742 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 73.1% (543 of 742 strings)

Translated using Weblate (Danish) [skip ci]

Currently translated at 65.3% (485 of 742 strings)

Translated using Weblate (Czech) [skip ci]

Currently translated at 65.3% (485 of 742 strings)

Translated using Weblate (Bulgarian) [skip ci]

Currently translated at 65.2% (484 of 742 strings)

Translated using Weblate (Arabic) [skip ci]

Currently translated at 65.4% (486 of 742 strings)

Translated using Weblate (Spanish) [skip ci]

Currently translated at 65.7% (488 of 742 strings)

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Csaba <csab0825@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: mm519897405 <baiya@vip.qq.com>
Co-authored-by: reloxx <reloxx@interia.pl>
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ar/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/bg/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/cs/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/da/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/el/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/he/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/hi/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/is/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ja/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ko/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/zh_CN/
Translation: Servarr/Readarr
2021-11-17 14:30:07 +00:00
ta264
847a9eae93 New: Improve match by adding small penalty for missing isbn/asin 2021-11-17 14:30:01 +00:00
ta264
a9e181425b Fixed: Only send supported image data to calibre 2021-11-17 14:30:01 +00:00
ta264
357245a9eb Fixed: None metadata profile no longer grabs future books
Fixes #1234
2021-11-17 14:30:01 +00:00
ta264
8280908c39 Fixed: Import list exclusion display overflow
Fixes #1140
2021-11-17 14:30:01 +00:00
ta264
b05bd685bc New: Make monitoring existing books on an import list optional 2021-11-17 14:30:01 +00:00
ta264
33e5351add New: Add option to only monitor selected book when adding single book 2021-11-17 14:30:01 +00:00
ta264
a1c2986af8 Fixed: UI updates when new author book monitor state set
Fixes #1298
2021-11-17 14:30:01 +00:00
bakerboy448
2983b60026 Fixed: Cleanse APIKey from Signalr logging
[common]
2021-11-15 07:38:57 -06:00
bakerboy448
0d9e98cf51 various fixups of confusing UI translates 2021-11-15 07:38:32 -06:00
ta264
5d63ef01b6 Fixed: Calibre authentication with Basic auth 2021-11-14 21:06:02 +00:00
Qstick
0bb391235f Translation sync 2021-11-14 11:00:55 -06:00
ta264
c4d02c1666 Fixed: Gracefully fall back to ipv4 if ipv6 is broken 2021-11-14 15:38:11 +00:00
ta264
7c6adb0da7 New: Use native .NET socks proxy
(cherry picked from commit d93110336fea31565129b356c90043761f8c2c5b)
(cherry picked from commit 6a0bd0e8207d7e21240a91d219f279a9a7a1bf30)
2021-11-13 08:45:25 +00:00
ta264
8f2ae2beff New: Upgrade to .NET 6 2021-11-13 08:45:25 +00:00
ta264
f53a1d7942 Package updates 2021-11-13 08:45:25 +00:00
ta264
cef15887a4 Use modern HttpClient
(cherry picked from commit 402f8b296f17bf161824ec5ff40d67d036d00d94)
2021-11-13 08:45:25 +00:00
Qstick
5f946c0aa3 New: HealthCheck for valid Branch value
(cherry picked from commit ef2f954b814b10094de25d691812e699a587e0f4)
2021-11-11 18:04:26 +00:00
bakerboy448
7528ed4084 Fixed: Default Branch to Develop 2021-11-11 13:24:51 +00:00
Robin Dadswell
e8ddaf6ccf Fixed: Audiobooks will not be attached to email notifications 2021-11-11 13:23:42 +00:00
ta264
c5281d04f1 Bump macos build agent 2021-11-11 11:08:43 +00:00
ta264
ec0e930a54 New: Goodreads listopia import list 2021-11-11 11:08:43 +00:00
ta264
fb7ec5c61e New: Goodreads series import list 2021-11-11 11:08:43 +00:00
ta264
cb2bd0273f Fixed: Null reference error importing some books 2021-11-11 11:08:43 +00:00
ta264
d6e55e2913 Fixed: Deleted books removed from UI 2021-11-11 11:08:43 +00:00
ta264
a3a914adfe Fixed: Forms login persists across restarts in docker
Closes #1307

(cherry picked from commit a219b4a1b869863b2ef47d4bdf33d308cb261ba3)
2021-11-11 11:08:43 +00:00
ta264
1835f15460 Improve ErrorHandler and quieten logging
Closes #1301

(cherry picked from commit 5fb6b449507af0b238afe6b699d8f55cc5deb790)
2021-11-11 11:08:43 +00:00
ta264
d1caed5c7d Fiddle release date 2021-11-11 11:08:43 +00:00
BookInfo
6bdfe01fbc Alternative metadata source 2021-11-11 11:08:43 +00:00
Robin Dadswell
225f0b310a Fixed: Time column is first column on events page
(cherry picked from commit c14ef7bee7477ad5d29498f1cba94267eb11daf0)
2021-11-09 18:54:33 -06:00
Weblate
6a0c99d32b Translated using Weblate (Chinese (Simplified) (zh_CN)) [skip ci]
Currently translated at 66.1% (488 of 738 strings)

Translated using Weblate (Hungarian) [skip ci]

Currently translated at 100.0% (738 of 738 strings)

Translated using Weblate (French) [skip ci]

Currently translated at 66.1% (488 of 738 strings)

Translated using Weblate (Hungarian) [skip ci]

Currently translated at 100.0% (738 of 738 strings)

Translated using Weblate (French) [skip ci]

Currently translated at 66.1% (488 of 738 strings)

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

Currently translated at 99.8% (737 of 738 strings)

Co-authored-by: Csaba <csab0825@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Nackophilz <clement.wigy@gmail.com>
Co-authored-by: Stéphane Dupont <aleistor@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: zpengcom <z.peng.com@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/zh_CN/
Translation: Servarr/Readarr
2021-11-06 18:08:28 -05:00
Robin Dadswell
04cf0594f6 Fixed: Prowl notification priority 2021-11-06 18:08:05 -05:00
ta264
2001035257 Fixed: Correctly detect mounts in FreeBSD jails
(cherry picked from commit 67b1fd9bc5c3808ef7227a40ceb5304eefd50fa7)
2021-10-27 17:22:28 +01:00
ta264
355dcaed6c Fixed: Calender .ics feed
(cherry picked from commit 147cfe538a3ac1a54ae9e84460e37f744e69668f)
2021-10-26 19:14:26 +01:00
ta264
3d3292fd3d Fixed: Add missing index to improve book import performance 2021-10-23 14:10:00 +01:00
ta264
78d073a0a8 Fixed: Filtering editions by language 2021-10-23 14:09:54 +01:00
ta264
ca8f768f84 Fixed: Error adding book to existing author in incognito session 2021-10-23 13:59:48 +01:00
Mark McDowall
b57ba3d6e2 New: Add logging is release is rejected because no download URL is available
(cherry picked from commit a83ed3bcce4b0a5ed5279029eed1b2ccfb4e8b85)
2021-10-18 06:20:49 -05:00
Mark McDowall
d48f2a1cb6 Fixed: Qbit torrents treated as failed after error
(cherry picked from commit 7e175bf95ed0a7b624b04a397b953f27043211ae)
2021-10-17 14:23:26 -05:00
Weblate
d8e4d388dc Translated using Weblate (Hungarian) [skip ci]
Currently translated at 100.0% (738 of 738 strings)

Update translation files [skip ci]

Updated by "Cleanup translation files" hook in Weblate.

Update translation files [skip ci]

Updated by "Cleanup translation files" hook in Weblate.

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

Currently translated at 100.0% (737 of 737 strings)

Translated using Weblate (Hungarian) [skip ci]

Currently translated at 100.0% (737 of 737 strings)

Translated using Weblate (Hungarian) [skip ci]

Currently translated at 100.0% (737 of 737 strings)

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

Currently translated at 100.0% (737 of 737 strings)

Translated using Weblate (Hungarian) [skip ci]

Currently translated at 100.0% (737 of 737 strings)

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

Currently translated at 100.0% (737 of 737 strings)

Co-authored-by: Csaba <csab0825@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: zsigus <zsigus.attila@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt_BR/
Translation: Servarr/Readarr
2021-10-17 14:22:54 -05:00
bakerboy448
47ae2032e5 update contributing [skip ci] 2021-10-10 17:09:17 -05:00
Robin Dadswell
89319f9833 New: Renamed Blacklist to Blocklist
(cherry picked from commit ead1371846b1f19cd49928052be0128bf7ccd41f)
2021-10-10 17:02:48 -05:00
ta264
07829a19b8 Fixed: Account for ISO 639 B vs T 2021-10-07 21:01:45 +01:00
Sean A
27259c1ebd Fixed: Ensure AudioTag years have default values (#1272)
* Fixed: Ensure AudioTagService years have default values

* Fix AudioTagServiceFixture.cs tests

Co-authored-by: Sean Anderson <sean.anderson@gaiaresources.com.au>
2021-10-08 09:58:20 +01:00
Qstick
d14a64caf9 Bump System.Data.Sqlite to 1.0.115.0-0 2021-10-03 19:23:19 -05:00
Mark McDowall
af2e743994 New: Log which DB is being migrated
(cherry picked from commit 07c95f06d3b9b32aaeb923d4c678f10a2bf1141a)
2021-10-03 10:22:46 -04:00
Kevin Lau
398ab902dc New: Change Today color in calendar for better visibility
(cherry picked from commit d9e9b72a894a238e58d40cc0a6aa83c416db1a44)
2021-10-02 11:06:53 -04:00
Qstick
007edcba9e Weblate Updates 2021-10-02 10:02:22 -05:00
Qstick
26b0034bbb Create swagger.json 2021-09-26 19:42:27 -05:00
ta264
e842137385 Fix backend analyze 2021-09-20 19:33:43 +01:00
Thomas White
294346db35 Fixed: Null reference error when import list adds new book to existing author
Fixes #1235

(cherry picked from commit 5e3045db86748d0ab407a6785007cb6bbd4f46a6)
2021-09-20 17:43:47 +01:00
Peter Sarossy
859dd091f3 Fix README typo (#1237) [skip CI] 2021-09-18 20:22:06 -05:00
ta264
72ae466892 Fixed: Calculate author statistics correctly
Fixes #1213
2021-09-02 21:12:14 +01:00
ta264
12c67891fb Fixed: Better book status column in author details 2021-09-02 21:12:14 +01:00
ta264
ffc97d8489 Fixed: Use track title tag if album tag not set 2021-09-02 21:12:14 +01:00
ta264
bdcee8c7c1 New: Try matching with "Unabridged" removed from title 2021-09-02 21:12:14 +01:00
ta264
6325432a34 Fixed: Filter by page count after filtering editions 2021-09-02 21:12:14 +01:00
ta264
1e82c7a67a New: Add book, series and files counts to author details page 2021-09-02 21:12:14 +01:00
ta264
8b19f02ade Fixed: Don't repeatedly refresh queue when author deleted 2021-09-02 21:12:14 +01:00
ta264
3c4c6b855e Fix add new book prop validation 2021-09-02 21:12:14 +01:00
ta264
9d78e5bfd8 Fixed: Bookshelf not updating after adjusting monitored options 2021-09-02 21:12:13 +01:00
Taloth Saldono
0e5f45a457 Send signalr message for episode monitored flag changes
(cherry picked from commit 9e81d41f262fb1f9d798374673b0a0427bf1a6e3)

Closes #1049
2021-09-02 21:12:13 +01:00
Robin Dadswell
2317665f33 New: Added book monitoring to author details
(cherry picked from commit 0ff889c3be1e8ee48759b233aeabf1bf1c4b4ff4)
(cherry picked from commit 0bd74098f9)
2021-09-02 21:12:13 +01:00
ta264
73950ca431 Fixed: Show metadata profile in mass editor by default 2021-09-02 21:12:13 +01:00
ta264
a746a9a4b1 Fixed: Cannot edit root folder calibre option after creation
Fixes #1188
2021-09-02 21:12:13 +01:00
ta264
7a969a63e4 New: Use ISO 639-3 language codes in metadata profile 2021-09-02 21:12:13 +01:00
ta264
7c10f3a74d New: Speed up metadata refresh 2021-09-02 21:12:13 +01:00
ta264
8edadbbfa2 Separate out Goodreads search from Author/Book data 2021-09-02 21:12:13 +01:00
ta264
dc2de62b03 Fixed: Use both album artist and track artist fields to pick up author for audiobooks 2021-09-01 21:04:39 +01:00
ta264
cdf8b0bc8f Fixed: Split concatenated authors when calculating match 2021-09-01 21:04:39 +01:00
ta264
17535bd8d6 Fixed: Better detection of series in search results 2021-09-01 21:04:39 +01:00
ta264
5f1be9e447 Fixed: Previous / Next author buttons sort by last name 2021-09-01 21:04:39 +01:00
ta264
c9cb0a9774 New: Search bar searches books as well as authors 2021-09-01 21:04:39 +01:00
Taloth Saldono
ba9f618405 Lazy Loading fuse-worker and fixed some potential timing issues when it's slow. Also keep last result while typing.
(cherry picked from commit 1e98002b8f3b01e41bff011644a9345c37c259c1)
2021-09-01 21:04:39 +01:00
ta264
468ebc3307 New: Load all books on page load and store in the browser 2021-09-01 21:04:39 +01:00
ta264
2558660b7b New: Add index views for all books 2021-09-01 21:04:39 +01:00
ta264
a774cf0682 Fixed: Bookshelf jump bar 2021-09-01 21:04:39 +01:00
Mark McDowall
924e393d1a Fixed: Log active indexers instead of implying all indexers are searched
(cherry picked from commit e19d4cf85b5a48ef823b9a983591d2bf7e72c621)
2021-09-01 09:35:00 -04:00
bakerboy448
98cc8f0a4b update bug report [skip ci]
(cherry picked from commit e912e14cbbc3fedf2242281609a96760a716d16f)
2021-08-27 21:08:27 -05:00
ta264
665d87b8d7 Fixed: Prefer 13 character ISBN from epub metadata
Fixes #1210
2021-08-21 14:36:44 +01:00
nitsua
7c662d4628 Add a link to the github issue if it is added to the change notes
Database Migration
NO

Description
Add a link to the github issue if it is added to the change notes
2021-08-18 16:23:52 +01:00
ta264
d5199ebcd7 Don't fail builds if sentry down 2021-08-17 21:43:29 +01:00
Thomas White
466876da62 Fixed: "Specific Book" setting for readarr list import (#1200) 2021-08-18 14:14:54 +01:00
bakerboy448
109fd22d1f New: Add missing Part Number and Part Count Examples 2021-08-14 18:08:58 -05:00
bakerboy448
001e24aaae Fixed: Corrected Indexer Category Help Text 2021-08-14 16:38:07 -05:00
Qstick
bbff60a2b0 Fixed: Avoid fetching quality definitions twice 2021-08-12 21:17:08 -04:00
Qstick
4b88cc5ea5 Fixed: Cleanup of unused tags for Import lists
Fixes #1181
2021-08-12 20:50:44 -04:00
Servarr
cf49404e13 Translated using Weblate (Portuguese (Brazil)) [skip ci] (#1147)
Currently translated at 99.7% (720 of 722 strings)

Translated using Weblate (Portuguese) [skip ci]

Currently translated at 77.9% (563 of 722 strings)

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

Currently translated at 99.7% (720 of 722 strings)

Translated using Weblate (Arabic) [skip ci]

Currently translated at 66.0% (477 of 722 strings)

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

Currently translated at 99.3% (717 of 722 strings)

Translated using Weblate (Portuguese) [skip ci]

Currently translated at 77.9% (563 of 722 strings)

Translated using Weblate (Hungarian) [skip ci]

Currently translated at 100.0% (722 of 722 strings)

Co-authored-by: Csaba <csab0825@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: Will Segatto <segatto.w@gmail.com>
Co-authored-by: bison529 <abshalsh@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ar/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt_BR/
Translation: Servarr/Readarr

Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: Csaba <csab0825@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Will Segatto <segatto.w@gmail.com>
Co-authored-by: bison529 <abshalsh@gmail.com>
2021-08-11 19:45:36 -05:00
ta264
8a074c61f0 Fixed: Allow repeated import attempts until downloaded files appear
(cherry picked from commit 9f1d4446e82e9c5efde3d0339be2f7dde40ba1ac)
2021-08-04 21:11:21 +01:00
ta264
8dd6049603 Fixed: Don't mark downloads as failed if no files found 2021-08-04 21:09:20 +01:00
ta264
9249f0ca5d Fixed: ArgumentNullException importing against a newly added edition with no series links
- Fixes Sentry READARR-2CY

(cherry picked from commit 4eebd4f2050ca646869b657bb365e11b1eea4d0c)
2021-08-03 21:48:49 +01:00
ta264
4712fedb0e New: Refresh books added to match existing files
Fixes #1146

(cherry picked from commit 40c99fb67587b5890d4d2a3a3af1d61034598e1f)
2021-08-03 21:48:44 +01:00
ta264
d8d09c2517 Fixed: Books added to match existing files have correct monitored status
(cherry picked from commit c98b22723aa8bf0bba2ce9f5b9ec74608c354751)
2021-08-03 21:48:37 +01:00
ta264
59c1bf0b1f Fixed: Prevent books being added with AuthorMetadataId 0
(cherry picked from commit 0c227d0f21e3803c6293fd5988e48ea010483cad)
2021-08-03 21:48:28 +01:00
bakerboy448
1571ef4172 git updates [skip ci] 2021-08-01 21:24:30 +01:00
Mark McDowall
60866f4af6 Fixed: Peers filtering in Interactive Search results
(cherry picked from commit dca2cfcecd543ef93d9cb3735fefb7dbc2277107)
2021-08-01 21:23:39 +01:00
ta264
4541d3d3b0 Fixed: Parse search results using edition titles also
Fixes #1154
2021-07-30 19:51:21 +01:00
Alex Thomson
9150f6889f Remove duplicate call to DeleteTorrent
(cherry picked from commit 94417402d8364e435c35365a75278914d5405465)
2021-07-27 16:45:58 +01:00
ta264
474699b67d Fixed: Error refreshing author if manually added book edition has been removed from Goodreads
Fixes Sentry READARR-Z6
2021-07-26 22:02:30 +01:00
ta264
2a05112d7d Fixed: Set correct titleslug for a book 2021-07-26 22:00:16 +01:00
ta264
c1a846dd2b Fixed: Detect more variations of series book naming 2021-07-26 21:21:45 +01:00
ta264
1f22cae4f8 Fixed: Import highest quality file first, not largest size 2021-07-26 21:12:49 +01:00
ta264
b1e92e7f73 Fixed: Computing most common author now we have multiple authors 2021-07-27 07:06:06 +01:00
ta264
85e945430b Fixed: Read multiple authors from audio tags 2021-07-27 07:06:06 +01:00
ta264
2e5a9b8dd4 Fixed: Don't try to audio tag ebook files 2021-07-27 07:06:06 +01:00
ta264
fcd5005502 Fixed: Default naming scheme includes PartNumber for new databases also 2021-07-22 21:00:45 +01:00
ta264
331ef56e9a Update frontend packages 2021-07-22 20:37:43 +01:00
ta264
19549098a7 Fixed: Reinstate position in series table 2021-07-22 20:32:35 +01:00
ta264
848b183ab8 Fixed: Column settings for series table 2021-07-22 20:25:02 +01:00
Weblate
6adadc0ade Translated using Weblate (Japanese) [skip ci]
Currently translated at 66.2% (476 of 718 strings)

Translated using Weblate (Catalan) [skip ci]

Currently translated at 1.5% (11 of 718 strings)

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

Currently translated at 99.8% (717 of 718 strings)

Translated using Weblate (Portuguese) [skip ci]

Currently translated at 78.1% (561 of 718 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 74.0% (532 of 718 strings)

Translated using Weblate (Arabic) [skip ci]

Currently translated at 66.4% (477 of 718 strings)

Added translation using Weblate (Chinese (Min Nan)) [skip ci]

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

Currently translated at 64.7% (465 of 718 strings)

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Sean <zhangshuyan@fuji.waseda.jp>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ar/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ja/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/zh_CN/
Translation: Servarr/Readarr
2021-07-22 20:54:47 +01:00
bakerboy448
9ee1b5482a Update bug report template [skip ci]
(cherry picked from commit 4659a8366d8a1565890d3b72442bd35c6eb8176e)
2021-07-22 20:50:21 +01:00
bakerboy448
ae88bc30e1 Fixed: Provider Wiki Links (supported-X => supported#X) 2021-07-22 20:49:48 +01:00
ta264
af9f8a9a18 Fixed: Tidy up the Author / Book files table
Closes #1089
2021-07-22 20:35:01 +01:00
ta264
71a34c7650 Remove unused frontend stuff 2021-07-22 20:35:01 +01:00
ta264
7f8dc3d2b4 New: Optionally display authors as LastName, FirstName in index
Fixes #1062
2021-07-22 20:35:01 +01:00
ta264
332997aefe Clean up sort menu 2021-07-22 20:35:01 +01:00
ta264
0a20188508 Fixed: Bad Author -> Book lazy lookup 2021-07-20 21:41:57 +01:00
ta264
493ce1b20c Fixed: Deleting multiple books at once from author page 2021-07-20 21:41:57 +01:00
ta264
b3dd116d27 Fixed: Deleting author removes books from Calibre
Fixes #1144
2021-07-20 21:41:57 +01:00
Mark McDowall
ca7ba125d2 Fixed: Remove selected in queue
(cherry picked from commit 4ed5fefcc6e362cb5c62ec639ee64571c97f9b5b)
2021-07-20 19:31:28 +01:00
Mark McDowall
1a3bb381b1 Fixed: Queue refresh closing manual import from queue if items change
(cherry picked from commit e9818b9982d868648d714a37527f1b066486c5df)
2021-07-20 19:31:28 +01:00
Mark McDowall
8d6e0c6bc3 Fixed: Queue refresh closing manual import from queue if items change
(cherry picked from commit f5d690aa7b703e6fc0cd7eeced177a28cfed4962)
2021-07-20 19:31:28 +01:00
Taloth Saldono
6cb2bf6b5f Fixed post-install update check not running
(cherry picked from commit eea6be459d5dbfafb9a5285046282c25c4697242)
2021-07-20 19:31:28 +01:00
ta264
e791f22333 Fixed: Don't redirect //api route to homepage 2021-07-20 16:34:18 +01:00
ta264
eaa1578c65 Fixed: Error trying to write calibre tags when calibre not enabled 2021-07-20 16:34:18 +01:00
Weblate
e0236e781a Translated using Weblate (French) [skip ci]
Currently translated at 66.0% (474 of 718 strings)

Translated using Weblate (Catalan) [skip ci]

Currently translated at 0.2% (2 of 718 strings)

Translated using Weblate (Vietnamese) [skip ci]

Currently translated at 66.2% (476 of 718 strings)

Translated using Weblate (Korean) [skip ci]

Currently translated at 66.2% (476 of 718 strings)

Translated using Weblate (Hungarian) [skip ci]

Currently translated at 100.0% (718 of 718 strings)

Translated using Weblate (Greek) [skip ci]

Currently translated at 66.2% (476 of 718 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 73.9% (531 of 718 strings)

Translated using Weblate (Danish) [skip ci]

Currently translated at 66.2% (476 of 718 strings)

Translated using Weblate (Czech) [skip ci]

Currently translated at 66.2% (476 of 718 strings)

Translated using Weblate (Bulgarian) [skip ci]

Currently translated at 66.2% (476 of 718 strings)

Translated using Weblate (Spanish) [skip ci]

Currently translated at 66.5% (478 of 718 strings)

Translated using Weblate (Dutch) [skip ci]

Currently translated at 66.5% (478 of 718 strings)

Added translation using Weblate (Catalan) [skip ci]

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Csaba <csab0825@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: dtalens <databio@gmail.com>
Co-authored-by: foXaCe <foxace66@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/bg/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/cs/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/da/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/el/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ko/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/nl/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/vi/
Translation: Servarr/Readarr
2021-07-16 12:05:32 +01:00
Mark McDowall
92a9b5b451 Fixed: Unable to close indexer category select input on mobile
Closes #4296

(cherry picked from commit e42d1af5ff8f3eb987195caa7ec8a0bbaf4a00c3)

# Conflicts:
#	frontend/src/Components/Form/EnhancedSelectInput.js
2021-07-16 12:04:02 +01:00
Mark McDowall
226ad22748 Author: Mark McDowall <mark@mcdowall.ca>
Author date:	6 months ago (1/7/2021 1:01:30 AM)
Committer:		PearsonFlyer <PearsonFlyer@github.com>
Commit date:	19 minutes ago (7/9/2021 3:21:25 PM)
Commit hash:	0a104a9cf8a1c5421a0beed9120bfc84fac896a0
Child:			Commit index
Parent:			4f986de3

New: Allow quality size limits to be closer together

(cherry picked from commit 8a3027fa7c99af21a56ac1cfe9a5a0846de9c474)
(cherry picked from commit ef5d1b29467ea24d6721e54aec4b35062ab72e4f)
Contained in branches:
qual_size_limits
Contained in no tag

Derives from tag: v0.7.1.1381 + 815 commits
2021-07-16 12:02:23 +01:00
ta264
fe942524a2 Frontend package updates 2021-07-14 21:55:24 +01:00
ta264
8917b61ea9 Bump to .NET 5.0.8 and upgrade backend packages 2021-07-14 21:53:40 +01:00
ta264
60a49e3a03 Fixed: Error getting candidates if parsed author is null 2021-07-14 21:44:33 +01:00
bakerboy448
b8a3f09891 Fixed: Notifiarr Health Issue Level
ref Sonarr 5938c38bc3a76d1f1e105fb54d5d7f59aa207278

(cherry picked from commit 6f0a2de5053ccb859b4ffbe1e84b4f3e0f7ef9c9)
2021-07-14 21:10:33 -05:00
bakerboy448
6e7f0deef5 Update PULL_REQUEST_TEMPLATE.md [skip ci] (#1127) 2021-07-10 15:24:55 -05:00
PearsonFlyer
4f986de366 Fixed: Add 'FilterAuthor' token and update manual import text box 2021-07-08 21:49:22 -04:00
Weblate
4bf658e239 Translated using Weblate (Portuguese (Brazil)) [skip ci]
Currently translated at 100.0% (717 of 717 strings)

Translated using Weblate (Portuguese) [skip ci]

Currently translated at 75.8% (544 of 717 strings)

Translated using Weblate (Hungarian) [skip ci]

Currently translated at 100.0% (717 of 717 strings)

Translated using Weblate (Finnish) [skip ci]

Currently translated at 66.3% (476 of 717 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 73.9% (530 of 717 strings)

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Csaba <csab0825@gmail.com>
Co-authored-by: Lizandra Candido da Silva <lizandra.c.s@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt_BR/
Translation: Servarr/Readarr
2021-07-07 23:10:04 -04:00
servarr[bot]
45d0e20608 New: Add Size column to Activity: Queue (#1116)
* New: Add Size column to Activity: Queue

(cherry picked from commit 43cd1032487743c72fe0503a293343b8811def4d)

* fixup! Lint

Co-authored-by: Nathaniel Peiffer <nathaniel@peiffer.com.au>
Co-authored-by: Qstick <qstick@gmail.com>
2021-07-04 14:50:35 -04:00
PearsonFlyer
438b75e8cf Fixed: "Profile" to "Indexer" on Clone Button (
(cherry picked from commit 058ab4b4a8
2021-07-04 07:47:58 -05:00
Servarr
d590769607 Translated using Weblate (Portuguese (Brazil)) [skip ci] (#1107)
Currently translated at 98.3% (704 of 716 strings)

Translated using Weblate (Portuguese) [skip ci]

Currently translated at 72.2% (517 of 716 strings)

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

Currently translated at 98.1% (703 of 716 strings)

Translated using Weblate (Portuguese) [skip ci]

Currently translated at 70.2% (503 of 716 strings)

Translated using Weblate (Portuguese) [skip ci]

Currently translated at 69.6% (498 of 715 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 71.8% (514 of 715 strings)

Co-authored-by: Lizandra Candido da Silva <lizandra.c.s@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: reloxx <reloxx@interia.pl>
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt_BR/
Translation: Servarr/Readarr

Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: Lizandra Candido da Silva <lizandra.c.s@gmail.com>
Co-authored-by: reloxx <reloxx@interia.pl>
2021-07-04 07:44:53 -05:00
Hugo Cortes
104d65b4ea fix: add SortName to author name regex validation 2021-07-04 13:21:15 +01:00
bakerboy448
25cb29e325 sync contributing from radarr [skip ci] (#1112)
* Update contributing.md Github docs URL [skip ci]

Closes #845

(cherry picked from commit 4e81b330061a758ec8ad37dbe648694187226687)

* sync contributing from radarr [skip ci]
2021-07-04 02:34:19 -04:00
Qstick
d3f9474eab PublishEvent after StartupContext to try fix integration tests 2021-07-04 02:25:09 -04:00
Mark McDowall
d5a74e7064 Return max tooltip width
Fixes #602

(cherry picked from commit fe0d8bb7da27e0f34b5db166ee54033f292b1006)
2021-07-04 01:33:05 -04:00
Mark McDowall
80ba57d4b5 Fix tooltip max width on larger screens
Fixes #510

(cherry picked from commit f4f2a6f5fc14244f9acf8186cbacda7f9c1e0481)
2021-07-04 01:32:57 -04:00
Mark McDowall
9fe1663267 Fixed: Episode history details tooltip jumping around
Fixes #503

(cherry picked from commit 796c5e8b6b9e2ba2b97c6144f64a756e76a947a9)
2021-07-04 01:32:29 -04:00
Qstick
0d860de88a Fixed: Tooltips overflowing the screen width
Fixes #430
Fixes #432

(cherry picked from commit 0a66e86cccc29d7fef6da7876b3b761deb414648)
2021-07-04 01:27:39 -04:00
Taloth Saldono
38a6553654 Added IsTorrentLoaded to tests
Fixes #911

(cherry picked from commit 7272c5b7fcada0b346e1dd72fb2d1caa6b6e4c63)
2021-07-04 00:49:27 -04:00
Taloth Saldono
916391edc3 Fixed: Qbittorrent api errors when only one of two seed criteria was configured
closes #907

(cherry picked from commit 652d44722b96a7a830ec45fe83260ddcecc525a7)
2021-07-04 00:48:26 -04:00
Taloth Saldono
ac36675c6e Fixed: Setting seed criteria while torrent is still being loaded by qbittorrent
closes #896

(cherry picked from commit 67e97f7aee761d19af6fe1a086691a9934635a6d)
2021-07-04 00:44:42 -04:00
bakerboy448
d76f8e715d Fixed flaky test.
(cherry picked from commit f846e0c031d74914d3a02626597df583422164e0)
Closes #304
2021-07-04 00:24:21 -04:00
bakerboy448
27e799b624 Log contents on api errors during tests.
(cherry picked from commit f2e1b4e43549695afacee5c87cca368e8fa30905)

Closes #295
2021-07-04 00:24:21 -04:00
Mark McDowall
d34e588588 New: Queue status icon is purple when download is waiting to import or importing
Fixed: Time Left on Queue won't show when completed
Queue status/timeleft improvements

Closes #281

(cherry picked from commit 910de6d94a4482e82e295153e01c299460af2d2d)
2021-07-04 00:24:21 -04:00
Mark McDowall
1be94da583 New: Don't close manual import when clicking outside the modal
Closes #278

(cherry picked from commit fd608fd4113bd1d6fde42bca4d9879f826a8c6a9)
2021-07-04 00:24:21 -04:00
rg9400
4066aa1472 Fixed: Indicate unchecking Replace Illegal Characters will remove them
Closes #251
2021-07-04 00:24:21 -04:00
beyondmeat
050dd67972 Fixed: Empty list message for System: Events
(cherry picked from commit a23639e62ee5e2106831c10d51b6a4d6ba569fdc)

Closes #159
2021-07-04 00:24:21 -04:00
bakerboy448
ed1935c85d fixup! Update wiki links 2021-07-04 00:24:21 -04:00
Qstick
b625bd00ea fix import sort in appActions 2021-07-04 00:17:48 -04:00
Qstick
a7c71c2093 fix wiki fragment for PackageGlobalMessageCheck 2021-07-04 00:15:46 -04:00
Qstick
a6774eed6e fixup LocalizationService in PackageGlobalMessageCheck.cs 2021-07-04 00:07:24 -04:00
Qstick
a1f740646f Fixed: Database migration failure when database was manually repaired in a certain way
Fixes #903
2021-07-03 23:53:09 -04:00
Taloth Saldono
759b78e816 Added mechanism for package maintainers to produce a health check error.
Fixes #859

(cherry picked from commit 7da02c236aa03e6aef011130526040c1cb8399fc)
(cherry picked from commit 024000275df3b2d3b884c2c2fbf0b86bd36a631a)
2021-07-03 23:50:05 -04:00
Taloth Saldono
740e0edc04 Added update check early in startup if the package requested a post-install update check 2021-07-03 23:47:56 -04:00
Mark McDowall
46fa7e80a0 Fixed: Restoring a backup with a different API didn't reload properly
Fixes #853

(cherry picked from commit 13ff2d4c70bc564525842c31d184127a3934e178)
2021-07-03 23:20:47 -04:00
Mark McDowall
45aa744b0f Fixed: Removal of previous service
Fixes #851

(cherry picked from commit cd28af98eed831e00a400e66b652e6a8d6f9c442)
2021-07-03 23:19:18 -04:00
Qstick
3e72770ec5 Handle 303 and 307 redirects in Http Requests
Fixes #849
2021-07-03 23:08:43 -04:00
Qstick
529ffa8864 Revert "Fixed: Corrupt image files when downloading from redirecting Url"
This reverts commit 79dfd8f14d.
2021-07-03 23:08:38 -04:00
servarr[bot]
99a2e1f0fa Fixed: Refresh queue count when navigating Activity: Queue
(cherry picked from commit 0a2b109a3fe101e260b623d0768240ef8b7a47ae)

Co-authored-by: Mark McDowall <mark@mcdowall.ca>
Closes #975
2021-07-03 20:04:57 -05:00
Taloth Saldono
9ddd08b0de Increased max redirects from 3 to 5
closes #3449

(cherry picked from commit d421ff973692a35d55e3773b2dc82e0a0d717546)
2021-07-03 19:19:27 -04:00
Taloth Saldono
79dfd8f14d Fixed: Corrupt image files when downloading from redirecting Url
(cherry picked from commit e28b2e83284f689d3620d8d394ef35fdfd55646f)
Closes #108
2021-07-03 19:19:27 -04:00
Mark McDowall
db885a5111 Fixed: Manual import from queue showing error when download name failed to parse
(cherry picked from commit 079a0b56c3e124616fef6e2f81c19f67c13acb96)

Closes #67
2021-07-03 19:19:27 -04:00
Qstick
b23e225271 Update wiki links 2021-07-03 14:55:53 -04:00
Qstick
68dd6bc98e Align version header with others
Fixes #865
Fixes #866
2021-07-03 14:36:51 -04:00
Qstick
966e9f43f1 Fixed: 'iso-8859-2' is not a supported encoding name 2021-07-03 14:13:49 -04:00
Mark McDowall
45671c89f9 Fixed: Show feed URL if incorrect mime type is found
Fixes #571
Fixes #572

(cherry picked from commit fa2e70d571cc7658611a0c51b8603247a22e6a2e)
2021-07-03 14:00:20 -04:00
Mark McDowall
8ad917e94b New: Warning when combining preferred words with a specific indexer
Fixes #534

(cherry picked from commit fae38a107f738eff148271499b571b93ed192e84)
2021-07-03 13:59:12 -04:00
Qstick
3de0df2162 Fixed: Root folder custom filter in Mass Editor
Fixes #260

Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>
2021-07-03 13:52:48 -04:00
Taloth Saldono
e4225aa2c2 Fixed enter in modal confirmation dialogs
Fixes #463
Fixes #464

(cherry picked from commit 930742ae2c69a530afe60f76a5824f2722540df8)
2021-07-03 13:45:12 -04:00
Qstick
a877c5b25d Fixed: Can ignore queue items with unknown book 2021-07-03 13:45:12 -04:00
Qstick
1f06c4f4e2 Fixed: Tooltip for existing author/book on add new item 2021-07-03 13:45:12 -04:00
Mark McDowall
c31bbb63fb Fix checkingUP qbit status unit test
Fixes #227
2021-07-03 13:45:12 -04:00
Mark McDowall
92715ac850 Fixed: Treated checkingUP status from Qbit as queued in case it fails to validate
Fixes #220

Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>
2021-07-03 13:45:12 -04:00
Qstick
cbf382625f Fixed: Preferred word can't have a term that is empty or only spaces
Fixes #218

Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>
2021-07-03 13:45:12 -04:00
Mark McDowall
e6250bfe0f New: Don't forcibly retest indexers/download clients/connections on save if previously enabled
Fixes #448

(cherry picked from commit b2b1600ebe7f022a3248ea12b69553e2d51a3a7c)
2021-07-03 13:45:11 -04:00
Qstick
ca00b8a3c7 New: Handle missingFiles status from qBit
Fixes #442

(cherry picked from commit 9a2cee3104b1e8d32f2df68d3ca75967aba41868)
2021-07-03 13:45:11 -04:00
Mark McDowall
39b2326bc5 Fixed: Replace : with _ when getting output path from Transmission
Fixes #433

(cherry picked from commit 0f792f9eb9517a4165a54d7c4551f4f68822d18e)
2021-07-03 13:45:11 -04:00
PearsonFlyer
907b7dc429 New: Add Readarr list sync
Closes #438
2021-07-03 12:34:48 -05:00
PearsonFlyer
9a78c8b512 Fixed: Compatibility with the new Download Station API 2021-07-03 06:55:48 -05:00
Servarr
5dc328346c Translated using Weblate (Portuguese (Brazil)) [skip ci] (#1092)
Currently translated at 98.3% (703 of 715 strings)

Translated using Weblate (Portuguese) [skip ci]

Currently translated at 69.3% (496 of 715 strings)

Translated using Weblate (Portuguese) [skip ci]

Currently translated at 69.3% (496 of 715 strings)

Translated using Weblate (Portuguese) [skip ci]

Currently translated at 69.3% (496 of 715 strings)

Translated using Weblate (Portuguese) [skip ci]

Currently translated at 69.2% (495 of 715 strings)

Translated using Weblate (Hungarian) [skip ci]

Currently translated at 100.0% (715 of 715 strings)

Co-authored-by: Csaba <csab0825@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Lizandra Candido da Silva <lizandra.c.s@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt_BR/
Translation: Servarr/Readarr

Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: Csaba <csab0825@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Lizandra Candido da Silva <lizandra.c.s@gmail.com>
2021-07-03 06:55:00 -05:00
Taloth Saldono
79bd4728bf Removed extraneous enum hints in dropdown
(cherry picked from commit 91fe47ef31249f23c19a553df569ef6451e6ca5d)
2021-07-02 21:18:54 -04:00
bakerboy448
eb26b38f2c New: Replace SmtpClient with Mailkit
Closes #723
2021-07-02 21:16:05 -04:00
Taloth Saldono
811c84a845 Multiple Email Address
Fixes #854
Fixes #884
Fixes #951
Fixes #954

(cherry picked from commit a8b6f70be1860aa502795f0dd30299c87d54dbbe)
2021-07-02 21:16:05 -04:00
cicomalieran
214fa4c06e Fixed: Parsing RSS with null values
(cherry picked from commit 8175f19442273e13517b2d507e7a4c33587f1b15)
(cherry picked from commit 6842c561ea36d1d2661cb87c517d6c155d65c4d3)

Closes #982
2021-07-02 21:16:05 -04:00
Skyler Mäntysaari
fc714182ad New: Mailgun connection
(cherry picked from commit 55752a6c6213c1d83d347ba0f6870aa6c1cc0770)
(cherry picked from commit 0b60ca68fcb5778d7b9eb1ae23e298458b4ab98d)
closes #981
closes #980
2021-07-02 21:16:05 -04:00
PearsonFlyer
7c96ab88d1 Really ignore ResizeObserver loop errors 2021-07-02 19:34:47 -04:00
bakerboy448
d6de4fc41f fix concurrency so runs don't cancel [skip ci] 2021-07-01 22:05:57 -04:00
PearsonFlyer
33b4ed44de Fixed: Corrected Naming Examples 2021-07-01 18:55:31 -05:00
ta264
81b12a7441 Fixed: Log files should not be cached 2021-07-01 16:22:57 +01:00
Qstick
8406dbe49d Prevent sync jobs from running in parallel
[skip ci]
2021-06-29 21:52:33 -04:00
servarr[bot]
cbaf973eeb New: Translate Activity Queue & Rename Timeleft to Time Left
New: Translate Activity Queue

(cherry picked from radarr commit 7d644aa54430eb6712e294956e35c5601077e398)
add some missing keys/fixups as well

Co-authored-by: bakerboy448 <55419169+bakerboy448@users.noreply.github.com>
2021-06-28 20:34:40 -05:00
bakerboy448
44711d7585 add wiki link to bug template [skip ci]
(cherry picked from commit 15a99ab650ce2d5ca9e21a58847bf9f7307299ea)

Closes #1085
2021-06-28 20:11:59 -05:00
Mark McDowall
c00d760cb0 Fix spelling of separated
(cherry picked from commit a4dea0aa62a6c0eb78c89d9ac2e80548fbceb615)

Closes #944
2021-06-28 20:11:59 -05:00
bakerboy448
9ad580effa Git template update [skip ci]
* FR template update [skip ci]

* PR Template update [skip ci]

Closes #1022

(cherry picked from commit ec3dbea7fc592801bf4e42e17e14ea4a66bed46e)
2021-06-28 20:11:59 -05:00
Qstick
2acc3f4584 Fixed: NZBGet Settings hint mentions Sabnzbd
closes #1044

(cherrypicked from Sonarr 2ad4e21aadbb2b6c94e4af529b2329e224ce4f8e)
2021-06-28 20:11:59 -05:00
Robin Dadswell
3fac1c23b2 Fix: Consistent SSL option for Download Clients
Closes #873

(cherrypicked from Sonarr 85f4cbe94c6f00352e0d4a38f337fb9417d3032b)
2021-06-28 20:11:59 -05:00
Qstick
a596a1fe9a Create azuresync.yml 2021-06-26 22:20:58 -04:00
Jake Soenneker
1835edcb67 New: Manual Import rejection column is sortable
(cherry picked from commit 2f366bc3b7274200ff9d0bf1aa96408dc92206f3)
2021-06-26 16:46:56 -04:00
Weblate
f928e2c3a8 Translated using Weblate (Portuguese) [skip ci]
Currently translated at 70.5% (496 of 703 strings)

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

Currently translated at 0.1% (1 of 703 strings)

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

Currently translated at 65.8% (463 of 703 strings)

Translated using Weblate (Portuguese) [skip ci]

Currently translated at 70.5% (496 of 703 strings)

Translated using Weblate (Vietnamese) [skip ci]

Currently translated at 66.0% (464 of 703 strings)

Translated using Weblate (Turkish) [skip ci]

Currently translated at 66.0% (464 of 703 strings)

Translated using Weblate (Thai) [skip ci]

Currently translated at 66.0% (464 of 703 strings)

Translated using Weblate (Swedish) [skip ci]

Currently translated at 66.0% (464 of 703 strings)

Translated using Weblate (Russian) [skip ci]

Currently translated at 66.0% (464 of 703 strings)

Translated using Weblate (Romanian) [skip ci]

Currently translated at 66.0% (464 of 703 strings)

Translated using Weblate (Polish) [skip ci]

Currently translated at 66.0% (464 of 703 strings)

Translated using Weblate (Korean) [skip ci]

Currently translated at 66.0% (464 of 703 strings)

Translated using Weblate (Japanese) [skip ci]

Currently translated at 66.0% (464 of 703 strings)

Translated using Weblate (Italian) [skip ci]

Currently translated at 65.8% (463 of 703 strings)

Translated using Weblate (Icelandic) [skip ci]

Currently translated at 66.0% (464 of 703 strings)

Translated using Weblate (Hindi) [skip ci]

Currently translated at 66.0% (464 of 703 strings)

Translated using Weblate (Hebrew) [skip ci]

Currently translated at 66.0% (464 of 703 strings)

Translated using Weblate (French) [skip ci]

Currently translated at 67.4% (474 of 703 strings)

Translated using Weblate (Finnish) [skip ci]

Currently translated at 66.0% (464 of 703 strings)

Translated using Weblate (Greek) [skip ci]

Currently translated at 66.0% (464 of 703 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 73.1% (514 of 703 strings)

Translated using Weblate (Danish) [skip ci]

Currently translated at 66.0% (464 of 703 strings)

Translated using Weblate (Czech) [skip ci]

Currently translated at 66.0% (464 of 703 strings)

Translated using Weblate (Bulgarian) [skip ci]

Currently translated at 66.0% (464 of 703 strings)

Translated using Weblate (Arabic) [skip ci]

Currently translated at 66.1% (465 of 703 strings)

Translated using Weblate (Spanish) [skip ci]

Currently translated at 66.2% (466 of 703 strings)

Translated using Weblate (Dutch) [skip ci]

Currently translated at 66.1% (465 of 703 strings)

Added translation using Weblate (Chinese (Simplified)) [skip ci]

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Lizandra Candido da Silva <lizandra.c.s@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: angelsky11 <angelsky11@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ar/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/bg/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/cs/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/da/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/el/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/he/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/hi/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/is/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ja/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ko/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/nl/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pl/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ro/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ru/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/sv/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/th/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/tr/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/vi/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/zh_CN/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/zh_Hans/
Translation: Servarr/Readarr
2021-06-26 16:42:32 -04:00
Qstick
e48ed1806c Update Discord Notification Job
[skip ci]
2021-06-26 16:37:26 -04:00
Robin Dadswell
2f13fe0760 New: Added Prowlarr Donation link 2021-06-22 12:00:56 +01:00
RobinDadswell
d01645052d fixups 2021-06-22 11:18:53 +01:00
Mark McDowall
d822523394 Fixed broken tests
(cherry picked from commit 16156192c5f1abd929bcd825186b9f153507a46e)
2021-06-22 11:18:53 +01:00
Mark McDowall
0ffc44f3da Pull Sonarr commit 'Fixed: Removing completed download from SABnzbd'
(cherry picked from c669be317fffa252d59851e9a8ca9e56032a01fb)
2021-06-22 11:18:53 +01:00
Evan J
5fff24bf69 Update login.html
(cherry picked from commit e8f58eb9be583639909c0ac9b3dc3b40db8c7a53)
2021-06-11 14:38:57 +01:00
Servarr
a34853c754 Translations update from Weblate (#1056)
* Translated using Weblate (Hungarian) [skip ci]

Currently translated at 100.0% (695 of 695 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/hu/

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

Currently translated at 100.0% (695 of 695 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt_BR/

* Added translation using Weblate (Chinese (Traditional) (zh_TW)) [skip ci]

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

Currently translated at 100.0% (695 of 695 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt_BR/

* Translated using Weblate (Hungarian) [skip ci]

Currently translated at 100.0% (703 of 703 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/hu/

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

Currently translated at 100.0% (703 of 703 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt_BR/

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

Currently translated at 64.8% (456 of 703 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/zh_CN/

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

Currently translated at 100.0% (703 of 703 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt_BR/

* Translated using Weblate (French) [skip ci]

Currently translated at 66.0% (464 of 703 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/fr/

* Translated using Weblate (German) [skip ci]

Currently translated at 71.6% (504 of 703 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/de/

* Translated using Weblate (Portuguese) [skip ci]

Currently translated at 66.7% (469 of 703 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt/

Co-authored-by: Csaba <csab0825@gmail.com>
Co-authored-by: Lizandra Candido da Silva <lizandra.c.s@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: muihiuwev <muihiuwev@outlook.com>
Co-authored-by: Simon Willcock <simon.willcock@kogan.com.au>
Co-authored-by: doob187 <amderkum@gmail.com>
2021-06-11 14:38:35 +01:00
Taloth Saldono
cc13f7126c Make it clearer that Maximum size is the global limit.
(cherry picked from commit a848e575cd37eb3cc421a66fc6b4bbfb26782d8e)
2021-06-11 14:38:07 +01:00
Robin Dadswell
218a82998a Fixed: Real IP logging when IPv4 is mapped as IPv6 2021-06-11 14:36:48 +01:00
ta264
ee81ad2add Fixed: Bad login redirect using a reverse proxy
(cherry picked from commit b0f04bb9d79a9f9f0021d179ea7273998be7cab3)
2021-06-11 14:36:15 +01:00
ta264
648a41ed7b Fixed: RSS sync paging back too far for some indexers
(cherry picked from commit 7fcee7173450fc24f7733ea907b0886c1aa7d735)
2021-06-11 14:36:15 +01:00
ta264
eb9b9d57ed Fixed: Error on bulk delete from queue 2021-06-11 14:36:15 +01:00
ta264
3ab29eee60 Fixed: Reinstate total book count in author stats 2021-06-11 14:36:15 +01:00
ta264
fe13823b43 Fixed: Incorrectly looking up books by EditionId 2021-06-11 14:36:15 +01:00
ta264
13d8554e7e New: More book title naming tokens 2021-06-11 14:36:15 +01:00
ta264
4d840d6f43 New: PartNumber and PartCount naming tokens 2021-06-11 14:36:15 +01:00
ta264
a0e2747004 New: More granular book year naming tokens 2021-06-11 14:36:15 +01:00
ta264
c484a29099 Clean up naming tokens page 2021-06-11 14:36:15 +01:00
ta264
23772ce312 New: Author SortName token 2021-06-11 14:36:15 +01:00
ta264
63cfec517d Bump to .NET 5.0.7 and upgrade packages 2021-06-11 14:36:15 +01:00
ta264
e1465f5336 Fixed: Renaming multi-part books 2021-06-11 14:36:15 +01:00
ta264
7fda41c18b New: Better matching of books with subtitles 2021-06-11 14:36:15 +01:00
ta264
aa45bc3938 New: Neater filling of author images to aspect ratio 2021-06-11 14:36:15 +01:00
ta264
2ca55ae729 Fixed: Remove useless Banners view 2021-06-11 14:36:15 +01:00
ta264
977c4e653b Adjust default quality profiles 2021-05-28 06:49:08 +01:00
Mark McDowall
c052363368 Fix webpack memory leak when copying HTML files
(cherry picked from commit 2804a961cb457cc94d3eaa1fe8ee2f71d9d1261c)
2021-05-28 06:49:08 +01:00
ta264
9fb7a1051e Rename MP3-320 to MP3 2021-05-28 06:49:08 +01:00
ta264
3abda061ba New: Detect audio vs text from newznab categories 2021-05-28 06:49:08 +01:00
ta264
065f03a01a Add M4B and Unknown Audio qualities 2021-05-28 06:49:08 +01:00
ta264
f6a04f7890 New: Basic audiobook support 2021-05-28 06:49:08 +01:00
ta264
62928b227b Fixed: Better detection of part books and sets 2021-05-28 06:49:08 +01:00
Robin Dadswell
c93870ff60 New: Indexer Categories no longer an advanced option (#1052) 2021-05-23 23:45:22 +01:00
Robin Dadswell
0bcad2e57b Fixed: Root Folder Downloads check giving errors when RuTorrent is used (#1051)
* Fixed: Root Folder Downloads check giving errors when RuTorrent is used

* removed unnecessary if statement from RemotePathMappingCheck
2021-05-23 23:41:16 +01:00
Robin Dadswell
6acd42e82b Show User Agent in System->Tasks for externally triggered commands (#1047)
* Show User Agent in System->Tasks for externally triggered commands

(cherry picked from commit fe8f319f7bfdadb7218b6313ada6cae1d2a35ad8)

* Fix ESLint

(cherry picked from commit c3837c9f7b50534e3eafe1d9fbaf360fee4588b7)

* fixup

Co-authored-by: Taloth Saldono <Taloth@users.noreply.github.com>
Co-authored-by: Mark McDowall <mark@mcdowall.ca>
2021-05-23 20:52:14 +01:00
servarr[bot]
8711c5d824 New: Remove completed downloads from disk when removing from SABnzbd
(cherry picked from commit ac8283d7339b3d9e8ccf70f3d1ff031d1b0a71d1)

Fixes #947

Co-authored-by: Mark McDowall <mark@mcdowall.ca>
2021-05-16 23:05:18 +01:00
Servarr
ba6b52c4c9 Translations update from Weblate (#1015)
* Translated using Weblate (Hungarian) [skip ci]

Currently translated at 100.0% (692 of 692 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/hu/

* Translated using Weblate (Italian) [skip ci]

Currently translated at 66.6% (461 of 692 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/it/

* Translated using Weblate (Dutch) [skip ci]

Currently translated at 66.9% (463 of 692 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/nl/

* Added translation using Weblate (Chinese (Traditional)) [skip ci]

* Translated using Weblate (Danish) [skip ci]

Currently translated at 66.9% (463 of 692 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/da/

* Deleted translation using Weblate (Chinese (Traditional)) [skip ci]

* Translated using Weblate (Hungarian) [skip ci]

Currently translated at 100.0% (694 of 694 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/hu/

* Translated using Weblate (German) [skip ci]

Currently translated at 68.7% (478 of 695 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/de/

* Translated using Weblate (Russian) [skip ci]

Currently translated at 66.6% (463 of 695 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ru/

Co-authored-by: Csaba <csab0825@gmail.com>
Co-authored-by: memnos <fabrassi@gmail.com>
Co-authored-by: ProjectHydra31 <kay@timmerman.io>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: lechuck <theghostpirate@gmail.com>
Co-authored-by: Qstick <qstick@gmail.com>
Co-authored-by: reloxx <reloxx@interia.pl>
Co-authored-by: kingii98 <konoff2@gmail.com>
2021-05-15 09:13:22 +01:00
ta264
96db74494a Fixed: Sort authors by lastname, firstname 2021-05-15 08:51:35 +01:00
ta264
62221c2a7f Don't run build for weblate PRs
[common]
2021-05-13 21:16:40 +01:00
nitsua
80b0c594b5 Add a donations section to System for each arr
(cherry picked from commit 1b34244143)
2021-05-13 21:44:18 +01:00
nitsua
6612dab547 Adjust CSS so titles are wrap instead of truncate
(cherry picked from commit d7e91f39b4)
2021-05-13 21:44:02 +01:00
Robin Dadswell
292aacc766 New: Localization support on Health Checks 2021-05-14 10:32:10 +01:00
Robin Dadswell
a4755631c3 New: Health Check for Downloads to Root Folder
removed using localization

updated ShouldBeWarning to include wikifragment check

fixed linting issues

slight tidy up
2021-05-14 10:32:10 +01:00
bakerboy448
c5dcb22c01 New: DiscordNotifier is now Notifiarr
Fixes #1014
2021-05-14 10:30:24 +01:00
bakerboy448
1db7ee5111 Fixed: Cleanse Tracker Announce Keys from logs
Fixes #844
2021-05-14 10:30:24 +01:00
bakerboy448
90d610b33a Fixed: Cleanse Notifiarr APIKey from logs
fixes #937
2021-05-14 10:30:24 +01:00
ta264
2984e2e1ca Fixed: Entity too large with big calibre library and digest authentication
Fixes #840
2021-05-13 21:27:16 +01:00
ta264
36080d4665 Fixed: Jumpbar after going back to artist index page 2021-05-13 21:15:11 +01:00
ta264
93f0f33e84 Fixed: restoring scroll position when going back to index page 2021-05-13 21:15:11 +01:00
ta264
129591de61 Revert "Ignore update test temporarily"
This reverts commit fd291aeb96.
2021-05-13 19:55:14 +01:00
ta264
3767c830d5 Fixed: Better detection of existing files 2021-05-13 19:55:14 +01:00
ta264
774180262b Better tracking of CalibreId 2021-05-13 19:55:14 +01:00
ta264
dc843ec63e Fixed: Handle filename changes when retagging with calibre 2021-05-13 19:55:14 +01:00
ta264
bfb42929a2 Fixed: SeriesBookLink housekeeping task 2021-05-13 19:55:14 +01:00
ta264
be09385c9d Fixed: Null reference processing failed import for unknown book 2021-05-13 19:55:14 +01:00
ta264
3c3f3a4d90 Use custom coverlet 2021-05-13 19:55:14 +01:00
ta264
222236bbde Update sentry 2021-05-13 19:55:14 +01:00
ta264
85f93eba98 Update nuget packages, dotnet 5.0.6 2021-05-13 19:55:14 +01:00
ta264
4181334d06 No clean 2021-05-13 19:55:14 +01:00
ta264
d1ed249039 More stringent cache key 2021-05-13 19:55:14 +01:00
ta264
0416b47b69 Remove the backend change optimization 2021-05-13 19:55:14 +01:00
ta264
d7f92daf08 Speed up upload, don't wait on non-windows builds 2021-05-13 19:55:14 +01:00
ta264
a146f6d223 Cache nuget packages 2021-05-13 19:55:14 +01:00
ta264
8864b6b2c8 Run coverage on linux 2021-05-13 19:55:14 +01:00
Qstick
1dff396b9e Fix lint 2021-05-11 21:40:36 +01:00
ta264
a28595887a Update signalr, connected react router, webpack, mini-css-extract 2021-05-10 22:34:15 +01:00
Mark McDowall
bdbbcd7fac Updated react-dnd and added touch support
Fixed: Drag and drop on mobile devices
Closes ##4429
2021-05-10 22:24:22 +01:00
ta264
d668bd5277 Update redux and react-redux 2021-05-10 22:24:22 +01:00
ta264
651808497f Update react-addons-shallow-compare, react-autosuggest, react-focus-lock, react-lazyload, react-slider and react-tabs 2021-05-10 22:24:22 +01:00
ta264
ebdc51b821 Updated react and react-dom packages 2021-05-10 22:24:22 +01:00
ta264
755068a44e Upgrade fontawesome, sentry, classnames, clipboard, filesize, fuse.js, jquery, lodash, mobile-detect, moment, qs, core-js 2021-05-10 22:24:22 +01:00
Mark McDowall
3f5668705c Update postcss packages 2021-05-10 22:24:22 +01:00
ta264
9571c992df Update linter packages 2021-05-10 22:24:22 +01:00
ta264
7b3f7bb582 Upgrade babel packages 2021-05-10 22:24:22 +01:00
Qstick
ab1928ee95 Update to webpack 5, remove gulp
Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>
(cherry picked from commit 4ef2174226a0210f756f180dded8567d659589e2)
(cherry picked from commit 06730363c0fe1e2bf376122f50943fbf90ab60e8)
(cherry picked from commit 533f1a61d52cc5d2b7c879de4b2291dbad833cbf)
2021-05-10 22:24:22 +01:00
Mark McDowall
7d4c92cc96 Fixed files that were using incorrect imports
(cherry picked from commit a3bb2f1c32fc1e0c49d0d1fe24c04940453f5431)
(cherry picked from commit 9ebdc5364c69971fde5a0c854a2d46d6b027fd5f)
2021-05-10 22:20:27 +01:00
ta264
00e4555736 New: Add min pages and ignored terms to metadata profiles 2021-05-10 21:54:50 +01:00
servarr[bot]
23142a59d7 New: Add rel="noreferrer" to all external links
* New: Add rel="noreferrer" to all external links

(cherry picked from commit c722e9112496062313d09df16b169873f910f2a1)

* Update Link.js

Co-authored-by: Mark McDowall <mark@mcdowall.ca>
Co-authored-by: Qstick <qstick@gmail.com>
2021-05-10 23:48:38 -04:00
Qstick
5dfd8d1a50 Github workflow for Issue lock and Support bot 2021-05-08 17:44:38 -04:00
Robin Dadswell
f45cc29816 Fixed: Import Lists provider message in UI 2021-05-08 15:40:56 -04:00
ta264
fd291aeb96 Ignore update test temporarily 2021-05-07 19:41:49 +01:00
ta264
11577b6db9 Fixed: Identification failing if book metadata has no authors 2021-05-07 18:54:33 +01:00
ta264
146fe04cce Fix bulk queue and blacklisk endpoints 2021-05-05 21:23:15 +01:00
bakerboy448
4a7b14fa39 Update indexer category help text … (and make cats advanced)
closes #979

(cherrypicked from sonarr 8d2d9078ff8f6daf50aef2dded3f96dae93252cc)
2021-05-05 09:30:24 +01:00
bakerboy448
8748b18ae9 discord link fix 2021-05-05 09:29:55 +01:00
bakerboy448
3b84b5da1d update bug template [skip ci]
closes #919
2021-05-05 09:29:31 +01:00
Anonymous
d57ef9805d Translated using Weblate (French) [skip ci]
Currently translated at 67.0% (464 of 692 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/fr/
2021-05-01 20:37:27 -04:00
Anonymous
54f336f3fd Translated using Weblate (Polish) [skip ci]
Currently translated at 66.9% (463 of 692 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pl/
2021-05-01 20:37:27 -04:00
Anonymous
7a129a4f89 Translated using Weblate (Vietnamese) [skip ci]
Currently translated at 66.9% (463 of 692 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/vi/
2021-05-01 20:37:27 -04:00
Anonymous
877f40116a Translated using Weblate (Chinese (Simplified) (zh_CN)) [skip ci]
Currently translated at 66.0% (457 of 692 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/zh_CN/
2021-05-01 20:37:27 -04:00
Anonymous
aa043a53b1 Translated using Weblate (Arabic) [skip ci]
Currently translated at 67.0% (464 of 692 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ar/
2021-05-01 20:37:27 -04:00
Anonymous
51e25b2a3c Translated using Weblate (Korean) [skip ci]
Currently translated at 66.9% (463 of 692 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ko/
2021-05-01 20:37:27 -04:00
Anonymous
99cedbf96e Translated using Weblate (Swedish) [skip ci]
Currently translated at 66.9% (463 of 692 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/sv/
2021-05-01 20:37:27 -04:00
Anonymous
97e6a353fa Translated using Weblate (Romanian) [skip ci]
Currently translated at 66.9% (463 of 692 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ro/
2021-05-01 20:37:27 -04:00
Qstick
5996f4d000 Translated using Weblate (Spanish) [skip ci]
Currently translated at 67.0% (464 of 692 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/es/
2021-05-01 20:37:27 -04:00
Anonymous
2067f655bd Translated using Weblate (Spanish) [skip ci]
Currently translated at 67.0% (464 of 692 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/es/
2021-05-01 20:37:27 -04:00
Anonymous
3798ff19e5 Translated using Weblate (Japanese) [skip ci]
Currently translated at 66.9% (463 of 692 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ja/
2021-05-01 20:37:27 -04:00
Anonymous
273680aed6 Translated using Weblate (German) [skip ci]
Currently translated at 67.0% (464 of 692 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/de/
2021-05-01 20:37:27 -04:00
Anonymous
2421c57bac Translated using Weblate (Icelandic) [skip ci]
Currently translated at 66.9% (463 of 692 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/is/
2021-05-01 20:37:27 -04:00
Anonymous
d6d41ac20d Translated using Weblate (Hindi) [skip ci]
Currently translated at 66.9% (463 of 692 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/hi/
2021-05-01 20:37:27 -04:00
Anonymous
5de68ad8d4 Translated using Weblate (Hebrew) [skip ci]
Currently translated at 66.9% (463 of 692 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/he/
2021-05-01 20:37:27 -04:00
Anonymous
089e327596 Translated using Weblate (Italian) [skip ci]
Currently translated at 66.6% (461 of 692 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/it/
2021-05-01 20:37:27 -04:00
Anonymous
bddf4d9801 Translated using Weblate (Russian) [skip ci]
Currently translated at 66.9% (463 of 692 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ru/
2021-05-01 20:37:27 -04:00
Anonymous
88a8f33bdb Translated using Weblate (Bulgarian) [skip ci]
Currently translated at 66.9% (463 of 692 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/bg/
2021-05-01 20:37:27 -04:00
Anonymous
a2668edabf Translated using Weblate (Czech) [skip ci]
Currently translated at 66.9% (463 of 692 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/cs/
2021-05-01 20:37:27 -04:00
Anonymous
c435b3853b Translated using Weblate (Portuguese) [skip ci]
Currently translated at 66.6% (461 of 692 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt/
2021-05-01 20:37:27 -04:00
Anonymous
c226abf184 Translated using Weblate (Turkish) [skip ci]
Currently translated at 66.9% (463 of 692 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/tr/
2021-05-01 20:37:27 -04:00
Anonymous
ca5fbf7cc3 Translated using Weblate (Danish) [skip ci]
Currently translated at 66.9% (463 of 692 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/da/
2021-05-01 20:37:27 -04:00
Anonymous
395bb7cacf Translated using Weblate (Thai) [skip ci]
Currently translated at 66.9% (463 of 692 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/th/
2021-05-01 20:37:27 -04:00
Anonymous
13e06ffcfd Translated using Weblate (Hungarian) [skip ci]
Currently translated at 88.4% (612 of 692 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/hu/
2021-05-01 20:37:27 -04:00
Csaba
4b3bb051a2 Translated using Weblate (Hungarian) [skip ci]
Currently translated at 88.4% (612 of 692 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/hu/
2021-05-01 20:37:27 -04:00
Anonymous
68a7417760 Translated using Weblate (Finnish) [skip ci]
Currently translated at 66.9% (463 of 692 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/fi/
2021-05-01 20:37:27 -04:00
Anonymous
1deb9d576f Translated using Weblate (Dutch) [skip ci]
Currently translated at 66.9% (463 of 692 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/nl/
2021-05-01 20:37:27 -04:00
Anonymous
3fa656433c Translated using Weblate (Greek) [skip ci]
Currently translated at 66.9% (463 of 692 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/el/
2021-05-01 20:37:27 -04:00
Anonymous
a1e90bef2e Translated using Weblate (Portuguese (Brazil)) [skip ci]
Currently translated at 66.7% (462 of 692 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt_BR/
2021-05-01 20:37:27 -04:00
Qstick
63b8dcc2e3 Consistent node ver between build_frontend and lint_frontend 2021-04-30 00:20:55 -04:00
Anonymous
12588e8e08 Translated using Weblate (Vietnamese) [skip ci]
Currently translated at 65.7% (455 of 692 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/vi/
2021-04-30 02:09:28 +00:00
Weblate
aab35b1a48 Added translation using Weblate (Chinese (Simplified) (zh_CN)) [skip ci] 2021-04-30 02:02:48 +00:00
Weblate
0792e7c016 Added translation using Weblate (Portuguese (Brazil)) [skip ci] 2021-04-30 02:01:45 +00:00
Weblate
ed12e2e534 Added translation using Weblate (Portuguese) [skip ci] 2021-04-30 02:00:55 +00:00
Anonymous
5cd8574792 Translated using Weblate (Korean) [skip ci]
Currently translated at 65.7% (455 of 692 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ko/
2021-04-30 01:58:29 +00:00
Anonymous
2c5c7789dc Translated using Weblate (Italian) [skip ci]
Currently translated at 65.3% (452 of 692 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/it/
2021-04-30 01:55:27 +00:00
Anonymous
bbcc26f489 Translated using Weblate (Hungarian) [skip ci]
Currently translated at 65.8% (456 of 692 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/hu/
2021-04-30 01:53:00 +00:00
Qstick
d61106aee8 Added translation using Weblate (Vietnamese) [skip ci] 2021-04-30 01:52:37 +00:00
Qstick
c7b11a83b9 Added translation using Weblate (Turkish) [skip ci] 2021-04-30 01:51:58 +00:00
Qstick
1a1d99f206 Added translation using Weblate (Thai) [skip ci] 2021-04-30 01:51:05 +00:00
Anonymous
ed44f83e27 Translated using Weblate (Arabic) [skip ci]
Currently translated at 66.9% (463 of 692 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ar/
2021-04-30 01:50:13 +00:00
Qstick
e2f380df25 Added translation using Weblate (Swedish) [skip ci] 2021-04-30 01:50:11 +00:00
Qstick
d2e2f68cf9 Added translation using Weblate (Russian) [skip ci] 2021-04-30 01:49:31 +00:00
Qstick
694cd1b178 Added translation using Weblate (Romanian) [skip ci] 2021-04-30 01:49:01 +00:00
Qstick
5b1277daff Added translation using Weblate (Polish) [skip ci] 2021-04-30 01:48:30 +00:00
Qstick
4b31a143a9 Added translation using Weblate (Korean) [skip ci] 2021-04-30 01:47:57 +00:00
Qstick
36f718dde5 Added translation using Weblate (Japanese) [skip ci] 2021-04-30 01:47:18 +00:00
Qstick
82f477c239 Added translation using Weblate (Italian) [skip ci] 2021-04-30 01:46:47 +00:00
Qstick
c5e51248d2 Added translation using Weblate (Icelandic) [skip ci] 2021-04-30 01:46:12 +00:00
Qstick
d4fb6824b6 Added translation using Weblate (Hungarian) [skip ci] 2021-04-30 01:45:32 +00:00
Qstick
cb3cdd6980 Added translation using Weblate (Hindi) [skip ci] 2021-04-30 01:44:59 +00:00
Anonymous
d441385a74 Translated using Weblate (Greek) [skip ci]
Currently translated at 66.0% (457 of 692 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/el/
2021-04-30 01:42:29 +00:00
Qstick
1b680d9faa Added translation using Weblate (Hebrew) [skip ci] 2021-04-30 01:42:10 +00:00
Qstick
0d6119a804 Added translation using Weblate (French) [skip ci] 2021-04-30 01:41:24 +00:00
Anonymous
c26b787b6f Translated using Weblate (Arabic) [skip ci]
Currently translated at 66.9% (463 of 692 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ar/
2021-04-30 01:38:27 +00:00
Qstick
482815629b Added translation using Weblate (Finnish) [skip ci] 2021-04-30 01:38:25 +00:00
Qstick
19ad139cf8 Added translation using Weblate (Greek) [skip ci] 2021-04-30 01:37:54 +00:00
Qstick
c18f41e81c Added translation using Weblate (German) [skip ci] 2021-04-30 01:37:23 +00:00
Anonymous
6826ff1d4b Translated using Weblate (Arabic) [skip ci]
Currently translated at 66.0% (457 of 692 strings)

Translation: Servarr/Readarr
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ar/
2021-04-30 01:34:45 +00:00
Qstick
22a17201ff Added translation using Weblate (Danish) [skip ci] 2021-04-30 01:34:28 +00:00
Qstick
ddf5ec5f66 Added translation using Weblate (Czech) [skip ci] 2021-04-30 01:33:16 +00:00
Qstick
26cd77f1c5 Added translation using Weblate (Bulgarian) [skip ci] 2021-04-30 01:32:25 +00:00
Qstick
20e1874787 Added translation using Weblate (Arabic) [skip ci] 2021-04-30 01:31:50 +00:00
Qstick
a85d25cb82 Added translation using Weblate (Spanish) [skip ci] 2021-04-30 01:23:15 +00:00
Qstick
afb9f3809f Added translation using Weblate (Dutch) 2021-04-29 12:17:51 +00:00
nitsua
d87bf5ae63 Localization framework 2021-04-29 08:58:43 +01:00
ta264
144134446d Fail build on BSD integration test fails
(cherry picked from commit aa07f3039e039387a54acabed2acdcd7d6d4830d)
2021-04-27 20:07:18 +01:00
ta264
23f2bbc700 Don't start integration tests too soon
(cherry picked from commit b284f40716269dc4f641323b8293f40dfda8a424)
(cherry picked from commit d549975d96f04cc6b197d719d8389110cb24b8e6)
2021-04-27 20:07:00 +01:00
ta264
a8388e12c1 Remove legacy code that accessed config.xml without a lock
(cherry picked from commit 7a4adea14ae18a5204226237eded56005a76893e)
(cherry picked from commit ba9aab1640358b4097997b6cd32e2edc36a5f696)
2021-04-27 20:02:40 +01:00
bakerboy448
4f40ad0480 New: ISO 8601 date format in log files
Closes #985
2021-04-24 22:43:03 -04:00
ta264
27bc97a1a6 Reinstate missing login mapper 2021-04-21 21:44:47 +01:00
ta264
73f81465e9 Fixed: Forms login page uses urlbase for logo
(cherry picked from commit e0f30c3eaeab7d863b4b4104a9f0d501bd693f69)
2021-04-20 21:58:20 +01:00
ta264
a8c91f2bc8 Fixed: Forms login with urlbase
(cherry picked from commit 811a9d4c6123643e0a2ae26c1ccf06717cb5f47b)
2021-04-20 21:58:11 +01:00
ta264
4b0586bd3d Fixed: UI not updating on upgrade
(cherry picked from commit d566c1efd42f9a94c524db311e8fa99bc6e0323f)
2021-04-20 21:57:24 +01:00
ta264
8f3f90d407 Tidy conversion to aspnetcore
(cherry picked from commit 490f6e2e6aa3f220cc98f257a3ca3b2bea48fb80)
2021-04-20 21:21:42 +01:00
ta264
47b23417e0 Fixed: Memory leak
Explicitly register concrete types as transient

(cherry picked from commit f097d30b095d89681eb1aede2e88c4fdefcab516)
2021-04-20 21:21:32 +01:00
ta264
5a9d75857d Fixed: Rogue scrollbar on large screens 2021-04-12 21:30:44 +01:00
ta264
2691cb3fce Fixed: Misaligned Book/Author details on large screens 2021-04-12 21:14:02 +01:00
ta264
9d77337726 Fixed: Retriggering marquee titles 2021-04-12 21:11:15 +01:00
ta264
5192c76717 New: Swipe left/right to navigate authors/books on mobile 2021-04-12 19:49:32 +01:00
ta264
f884a2689a Rework marquee 2021-04-12 19:49:32 +01:00
ta264
5714f1c913 Fix prop validation 2021-04-12 19:49:32 +01:00
ta264
a84725f867 Fixed: Author/Book overview overflows
Bump react-measure to v2.5.2
2021-04-12 19:49:32 +01:00
ta264
106a1c339b New: Scroll long book titles 2021-04-12 19:49:32 +01:00
ta264
72de94308b Fixed: Setting file dates
Fixes #940
2021-04-12 19:49:32 +01:00
ta264
400f77584d New: Add details and delete buttons to file editor table 2021-04-12 19:49:32 +01:00
ta264
427f76fbe0 Fixed: Better formatting of the author books page 2021-04-12 19:49:32 +01:00
ta264
8a7765c855 Fixed: Only pick up supported formats from calibre 2021-04-12 19:49:32 +01:00
ta264
fea34add4b New: Support kepub (as epub) 2021-04-12 19:49:32 +01:00
ta264
399ee8d2e7 Fixed: Book files disappearing 2021-04-12 19:49:32 +01:00
ta264
3940d4aa28 Fixed: Run import identification even for unparsable releases 2021-04-12 19:49:32 +01:00
ta264
f0742e3750 Fixed: File change history appearing against wrong book 2021-04-12 19:49:32 +01:00
ta264
41f5f0f2d4 New: Search for new editions from goodreads when identifying 2021-04-12 19:49:32 +01:00
ta264
c1f2ea6c8a Fixed: Don't distort author images in search bar results 2021-04-12 19:49:32 +01:00
ta264
2d7aa20448 New: Auto rescan on remote path mapping change for Calibre 2021-04-12 19:49:32 +01:00
ta264
9be948b7cc Fixed: Parse series for search results 2021-04-12 19:49:32 +01:00
ta264
110e867bd3 New: Show book file details in interactive import and unmapped files 2021-04-12 19:49:32 +01:00
ta264
9f37b1c484 New: Get more candidates and include ISBN/ASIN in distance calculation 2021-04-12 19:49:32 +01:00
ta264
d078dacaab New: Cache searches for 5 days 2021-04-12 19:49:32 +01:00
ta264
996841db45 Fixed: Slow initial author load 2021-04-12 19:49:32 +01:00
ta264
404da4ae22 Fixed: Handle parsing books with multiple authors properly 2021-04-12 19:49:32 +01:00
ta264
fa25324463 Fixed: Refreshing / Deleting Series 2021-04-12 19:49:32 +01:00
ta264
652fdae7d9 New: Use ISBN / ASIN in preference to goodreads id 2021-04-12 19:49:32 +01:00
ta264
6a61702a91 Fixed: Ensure correct book edition is in the database before importing book 2021-04-12 19:49:32 +01:00
ta264
8bc44f2a29 Fixed: Don't accidentally remove book editions when refreshing a book 2021-04-12 19:49:32 +01:00
ta264
8ec13f5ead Fixed: Better aggregation of calibre data 2021-04-12 19:49:32 +01:00
ta264
f584d2d8d2 New: Allow keeping calibre in sync with goodreads 2021-04-12 19:49:32 +01:00
ta264
7072b913a6 New: Allow retagging book files with calibre 2021-04-12 19:49:32 +01:00
ta264
e29b0c318e Fixed: Prevent renaming calibre files 2021-04-12 19:49:32 +01:00
ta264
dd341ef1e1 Fixed: Disable calibre duplicate check when adding new books 2021-04-12 19:49:32 +01:00
Jared Gesser
2bea1965c6 fix spelling, fix punctuation 2021-04-11 20:39:30 +01:00
njordan
0252617730 Add support for Flood 2021-04-07 13:19:44 +01:00
Robin Dadswell
f6e87858a8 New: Added logo to loading page 2021-04-07 12:05:03 +01:00
Mark McDowall
6fa56b8873 Fixed: Interactive import modal horizontal scrolling on Firefox mobile
(cherry picked from commit 6c505937dacfa82e965adaaac407c888a1caacce)
2021-04-02 00:24:32 -04:00
bakerboy448
c749a660e7 Fixed: Debatable typos in Naming Modal
(cherry picked from commit f2f1039c5ed5fdf42683d64a777cdac410e45fd6)
2021-03-28 19:22:47 -04:00
bakerboy448
e6992da18c Fixed: Cleanse Goodreads Token and Token Secret from Log Files 2021-03-23 12:54:03 +00:00
ta264
80e8d5e5e7 Secret Dev Settings Page 2021-03-22 21:34:39 +00:00
Taloth Saldono
61fdb6eba2 Fixed: Unnecessary idle cpu usage
(cherry picked from commit 5a69801877eb72899dd9867c39a1b88b7114fe5b)
(cherry picked from commit 4eb6cb9dae)
2021-03-22 21:34:38 +00:00
ta264
98611c7d02 New: Release parser improvements 2021-03-22 21:28:14 +00:00
ta264
ad2b3e5cc5 Fix tests 2021-03-19 19:28:58 +00:00
ta264
34bd1a5876 New: Warn if user tries to connect to a calibre-web server 2021-03-18 22:38:52 +00:00
ta264
b652cf9563 New: Support for deleting books from calibre 2021-03-18 21:54:07 +00:00
ta264
fa459ea7ac Fixed: Cutoff delete button in unmapped files 2021-03-17 21:03:33 +00:00
ta264
acb6fc01b3 Fixed: Gracefully handle Goodreads search error
Fixes #897
2021-03-17 21:35:42 +00:00
ta264
1e0e8adc77 More mono cleanup 2021-03-17 21:30:57 +00:00
ta264
35ab21ab04 Fixed: Marking history as failed 2021-03-17 21:25:06 +00:00
Taloth Saldono
d61daeac8e Generalized RateLimit logic to all indexers based on indexer id 2021-03-16 21:52:21 +00:00
Taloth Saldono
c8c37435be Fixed: Jackett indexer search performance 2021-03-16 21:52:21 +00:00
ta264
a6f8391f40 Fix deleting providers 2021-03-16 21:52:21 +00:00
ta264
025cb04035 Fixed: FolderWritable check for CIFS shares mounted in Unix
See https://github.com/dotnet/runtime/issues/42790

Implemented workaround in https://github.com/dotnet/runtime/issues/42790#issuecomment-700362617
2021-03-15 23:33:19 -04:00
Qstick
3fc60dc56d Run Analysis on Linux main build (leaving in failed state to test)
(cherry picked from commit be40a0d7381278c3225e9faa0230cb1dcceeb794)
2021-03-12 12:55:48 +00:00
ta264
f5b2acdbdf New: .NET 5.0.4 2021-03-12 12:55:48 +00:00
Mark McDowall
9a0b247c8f Use createHandleActions for adding/removing commands so itemMap is synced properly
(cherry picked from commit 99be6a7e4065b77c910df6444a468fedc23e90cc)
2021-03-12 12:55:48 +00:00
ta264
8c50b866ff Fixed: Adding book from list 2021-03-12 12:55:48 +00:00
ta264
d6170dbfed New: Use native dotnet host and DryIoc 2021-03-12 12:55:48 +00:00
ta264
58ddbcd77e New: Use ASP.NET Core instead of Nancy 2021-03-12 12:55:48 +00:00
ta264
d348232e0d Unused 2021-03-12 12:55:48 +00:00
ta264
940da91ca4 Disable new warning in 5.0.200
[common]
2021-03-12 12:55:48 +00:00
ta264
543fe6729a More mono cleanup 2021-03-12 12:55:48 +00:00
ta264
6bcede5064 Fix formatting 2021-03-12 12:55:48 +00:00
Taloth Saldono
fbfbe4a931 Cleanse more /home/username scenarios
(cherry picked from commit 23047623ee89944260b6073813ff1f4e5223be71)
2021-02-27 17:28:18 +00:00
Qstick
5a0d52aef9 Update Discord link on MoreInfo page 2021-02-26 12:42:04 -05:00
ta264
2bf86248af Fixed: Ensure SSL cert exists before saving config
Trap missing certificate exception to avoid bootloop

(cherry picked from commit 78c7372a0d64e15734b14b0ca9852ae7c0a47132)
2021-02-25 04:34:42 +00:00
Qstick
96cb26050b Update Readme Discord Link [skip ci] 2021-02-24 21:54:18 -05:00
ta264
32833b5fc4 Fixed: Parsing [book] by [author] 2021-02-12 19:47:15 +00:00
ta264
1cdcfe25c0 Fixed: Improve parser when release has colons in title 2021-02-12 19:41:18 +00:00
ta264
c61315b90e Fixed: Restart button in UI
Fixes #633
2021-02-11 22:06:16 +00:00
ta264
d22ca1fe4f Fixed: Adding book where the same author appears twice
Fixes #815
2021-02-12 16:04:15 +00:00
ta264
791bba471f Fixed: Trying to get book details from filename when already obtained from tags 2021-02-12 16:04:15 +00:00
ta264
446a0591db Fixed: Duplicates in wanted page 2021-02-12 16:04:15 +00:00
ta264
69773db77a Fixed: Errors converting to book resource 2021-02-12 16:04:15 +00:00
ta264
d51af026fb Move test harness packages to Directory.Build.props 2021-02-12 16:04:15 +00:00
ta264
fb130fd0e9 New: Drop mono support 2021-02-12 16:04:15 +00:00
ta264
760de88e7c New: .NET 5 support for FreeBSD 11+ 2021-02-12 16:04:15 +00:00
ta264
4a1b2af535 New: Log out body for bad API requests 2021-02-12 16:04:15 +00:00
ta264
5cc0331c75 Fixed: Adding indexers from presets 2021-02-12 16:04:15 +00:00
ta264
d3e8c7e0c9 New: Use System.Text.Json for Nancy and SignalR 2021-02-12 16:04:15 +00:00
Qstick
16b3817202 Fixed: Don't ignore default Boolean in db serialization 2021-02-12 16:04:15 +00:00
ta264
eaf46b0550 Hack: ignore wonky depedencies in signalR js client 2021-02-12 16:04:15 +00:00
ta264
da1686b53c New: Build with NET5 2021-02-12 16:04:15 +00:00
Mark McDowall
52337350d9 Fixed: Restoring backup from zip file on disk
(cherry picked from commit 5960035d5d660a923e11b0300833b60c64271522)
2021-02-08 13:02:52 -05:00
Mark McDowall
faf8fbbc2a Update column properties when restoring persisted state
(cherry picked from commit 653db8290e0a7737348d911d322c4218c3b5b677)
2021-02-07 20:41:40 -05:00
Mark McDowall
e6ceafe0b7 Fixed: Table column order resetting after refresh
#4297

(cherry picked from commit 044cb563a6488c16916ea7617d1f91404330b06f)
2021-02-07 15:35:17 -05:00
Qstick
cf42e02586 Fixed: Settings fields being altered during save
(cherry picked from commit dd61480d60e067e851982b0cc98f03f752b80673)
2021-02-07 10:15:28 -05:00
Qstick
93eca6a749 Fix DownloadStation integration in DSM 7
(cherry picked from commit b0753ab153a79203de10a928e99fcec5b6a7c895)
2021-02-07 09:20:54 -05:00
bakerboy448
d7813c2255 bump chrome driver from 86 to 88
[common]
2021-02-06 16:05:31 -05:00
bakerboy448
239240768b update FR template [skip ci] 2021-02-06 11:23:49 -05:00
Taloth Saldono
36b8df87d2 Fixed: Validation of new qbittorrent max-ratio action config
(cherry picked from commit d1c3ae17491726320c58561548a21d83dae7fe7d)
2021-02-04 23:31:25 -05:00
Qstick
7c14bd1c80 Add crossorigin use-credentials attribute to manifest tag
(cherry picked from commit 70e4324a7c6a78e893a5c135cdfdedbb2398b892)
2021-02-04 23:24:11 -05:00
bakerboy448
fd81ca86db New: Update all wiki links to point to the Servarr Wiki 2021-02-03 22:41:59 -05:00
Qstick
42262877b0 Quick fix for Queue sort by Author SortName
Signed-off-by: bakerboy448 <55419169+bakerboy448@users.noreply.github.com>
2021-01-30 18:11:14 -05:00
Mark McDowall
843e46f890 New: Renamed Quick Import to Move Automatically 2021-01-30 15:07:59 -05:00
bakerboy448
5ae4899ff2 update bug template [skip ci]
Closes #751
2021-01-30 15:07:19 -05:00
Qstick
bc4aed17a2 Revert "Fix GoodReads Search Test, New First Book"
This reverts commit c8263fd856.
2021-01-30 13:38:23 -05:00
Qstick
8adf67ed5a Fixed: Prevent Bookshelf error if items is undefined 2021-01-30 13:14:30 -05:00
Qstick
7cc9a67b74 Fixed: PendingRelese deletes wrong value on author delete 2021-01-28 23:43:19 -05:00
Qstick
c8263fd856 Fix GoodReads Search Test, New First Book 2021-01-28 23:43:19 -05:00
ta264
d7cdbbecc8 Fixed: Set musl status at compile time 2021-01-28 23:43:19 -05:00
ta264
64e2f6457d Fixed: Goodreads bookshelves not shown after authentication 2021-01-28 23:43:19 -05:00
Qstick
93ba5ade9e Cleanup Conflicts in Sonarr/Lidarr Pulls
Co-Authored-By: Robin Dadswell <19610103+RobinDadswell@users.noreply.github.com>
2021-01-28 23:43:19 -05:00
ta264
ffc12656ee Add SortKey validation
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
1e735da9f1 Fixed: False Positives for RemotePath check with Deluge
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Mark McDowall
96072e61e0 Fixed: Show TLS errors in UI when testing download clients
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
b05b8c9e7a Resource missing from Gotify call
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
f73b9491ad Gotify token as query parameter
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
7842acc76e Convert Notifications from RestSharp to HttpClient
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
ad11ef9d2a Fixed: Manual Import Fails on failed Import Items
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Taloth Saldono
70c572534a Fixed binary execute permissions for osx and Radarr
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Taloth Saldono
4236afe850 Fixed disk permission tests
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Taloth Saldono
1ff5d814f4 New: Displaying folder-based permissions in UI rather than file-based permissions and with selectable sane presets
Fixed: Preserve setgid when applying unix permissions
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Taloth Saldono
7921a228ad Readded 0 cat to the end of the Newznab list
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
3af8051e3c Improve use of All() for Path related queries
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
cf0439d4c5 Mass Editor size and options
Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
5176bdc786 Fixed: Size on disk sorting and display
Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Mark McDowall
0c8ad37a8f New: Differentiate between short term and long term (more than 6 hours) indexer failures
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
4fe6029be7 Fixed: (Windows) clean up extraneous files in build folder during installation
Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Mark McDowall
05bc9f11ee New: Bulk remove from Blacklist
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
267bdb4cdf New: Show .net version in UI
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Mark McDowall
6d9126bca4 Fixed: Cleanse account and passwd from Download Station URLs
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Mark McDowall
8853f1cfb3 Fixed: Webhooks using lower case event types (in the future this could change)
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Mark McDowall
5afe37e929 New: Health events for Webhooks
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
755fec154b Fixed: Failing file copy when running in docker on synology with btrfs
Co-Authored-By: Taloth <Taloth@users.noreply.github.com>
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Taloth Saldono
2d1573251b Fixed: Regression causing updater to fail (manual update required if on 3.0.3.971, see forums)
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Taloth Saldono
da5cdd6661 Fixed: Dataloss when moving series folder to root folder with only different casing
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Taloth
7f64162a7a New: Newznab/Torznab categories dropdown with indexer provided category names
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Taloth Saldono
b4289664dc Handle ratelimit api response for newznab caps endpoint on certain newznab indexers that have caps behind the apikey
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
4fb13a64b1 Fixed: Preview rename tip wording
Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
a06ceeb31e Fixed: Artist/Album navigation buttons hidden with some titles
Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
18a9f69f60 Fixed: Links and already added icons overflowing on add artist/album search results
Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Taloth Saldono
36685edd49 Fixed: Exception when parsing Quality in release title with colon
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
e4ca35d2d2 Fixed: Long paths overflowing in artist history
Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Mark McDowall
c534ab570f Don't process queue item without details
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Mark McDowall
1f88450045 Fixed: Show more information in UI when testing SAB fails in some cases
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Ryan
b15ab3ae27 Fixed: Typo/unclear text in backup retention
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Taloth Saldono
360e68a793 Remove stacktrace if hardlink resulted in EXDEV.
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Taloth Saldono
4aebf02d14 Fixed: Performance of symbolic link detection and infinite recursion
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Taloth Saldono
7002628514 New: Fast copy using reflink on btrfs volumes
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Taloth Saldono
4af4d45873 Fixed: Removed hardlink-based transactional file transfer logic (instead relying on explicit copy+delete for cifs)
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
fe85e18a62 Fixed: Sorting of queue by artist title when unknown items are included
Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
4d2781d128 Moved Windows-only Permission function to Lidarr.Windows
Co-Authored-By: Taloth <Taloth@users.noreply.github.com>
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
5a49fb9a14 fix modifiers for various classes
Co-Authored-By: Taloth <Taloth@users.noreply.github.com>
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Mark McDowall
5ca32a7e84 Fixed: Indexer being disabled due to download client rejecting it
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Taloth Saldono
d6634e7da1 Added PrivacyLevel option to FieldDefinition for later usage
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Taloth Saldono
a6ec2f5367 Added MultiSelect input control for provider settings
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Taloth Saldono
459dcc2ed6 New: Added FileList.io indexer support
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Arthur Bols
acd5796d87 New: Removed chown and simplified chmod options for linux/osx
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Taloth Saldono
e18f4bb71c Allow inline markdown in the changelog for linking to wiki
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
051af8a9a6 Fixed: Not removing seeded download if it was manual imported in some cases
Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Mark McDowall
47f9572f83 Fixed: Rejections custom filter for Interactive Search (now Rejections Count)
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
4ca774182a Improve root folder health check
Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Skyler Mäntysaari
53527c518b New: SendGrid Notifications
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
84ff9abf44 Fixed: Added .org to website url filtering in parser
Co-Authored-By: Taloth <Taloth@users.noreply.github.com>
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
ceef604201 Fixed recursion issue when emptying recycle bin
Co-Authored-By: Taloth <Taloth@users.noreply.github.com>
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
6b8d2a60a7 Fixed: Tag details list series in alphabetical order
Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
3b656e05a2 Added UserAgent to api request trace log
Co-Authored-By: Taloth <Taloth@users.noreply.github.com>
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
a9e03ed1cc New: Add DownloadClient and DownloadId to Webhook notifications
Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
bb504ec275 Clarify that Post-Import Category torrents are not monitored by Sonarr.
Co-Authored-By: Taloth <Taloth@users.noreply.github.com>
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
19a496c31c Fixed: Windows installer won't create shortcut if unchecked
Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Taloth Saldono
db51254827 Improved error message when nzb download contains an newznab error instead
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
24ab9768e9 Fixed: Ended overlay on artist posters
Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
79cff81ffd Rename FilterFiles to FilterPaths
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
8d43d5d7b0 Fixed: Queue not always clearing checked items when updated
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
97e6240177 Fixed: Remove website post fix before parsing
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Taloth Saldono
371ef929f3 Linting error
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
ebcde8f602 Fix Release Push log statement
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Jacob
ea4044f237 New: Added option to filter Release Profile to a specific indexer
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Mark McDowall
739ebf25c0 New: Clone indexer button
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
0c6a51c7f7 Fixed: Manual Import sorting by quality
Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Mark McDowall
4fcc463d6a Fixed: Prompt to restart after resetting API key
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
0d8c259237 Fixed: Sorting by track count
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Taloth Saldono
6943cc0011 Added Norwegian Bokmal alias
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Taloth Saldono
3a5752f3cc Fixed: Representation of episode start time when not starting at the full hour in am/pm notation
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
7e00dd731c Fixed: RestClient does not use global proxy settings
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Mark McDowall
bb66af7185 New: Limit recent folders in Manual import to 10 and descending order
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Mark McDowall
16b2458903 Fix proptype warning for id of EnhancedSelectInputOption
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Mark McDowall
d33d27a55f Remove website prefixes with dashes in URL
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Mark McDowall
1e7efbe3d6 Fixed: Details for episode history flashing on mobile devices
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Fossil
230198c1e7 Remove PFMonkey.com from Presets
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
d803847342 Fixed: Test All not clearing health error
Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
7693593230 Improved some log messages
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
f36eee0dc2 Fixed: Delete files from Artist Mass Editor not actually deleting files
Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Taloth Saldono
0db2f38dfe Tiny fix in test, left-over from my on-windows test.
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Taloth Saldono
c58be51a03 Fixed: File imports on cloud drives slow due to transaction logic
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
7ea1bf71dd Fixed: Use Proxy for MediaCovers and Metadata
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Mark McDowall
1d6749ef52 Fixed: Set permissions on extra and subtitle files
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Mark McDowall
9216fe28d0 Fixed: Include releases that failed to parse in search results
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
649ecd94ea New: Event Driven HealthCheck Support
Co-Authored-By: Taloth <Taloth@users.noreply.github.com>
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
634153b658 Fixed: Disregard Real when user disabled proper preference
Co-Authored-By: Taloth <Taloth@users.noreply.github.com>
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
3101544484 Simplify ManualImportModule null check
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
ff40d82ef1 Fixed: Edge case where import fails due to DB relationship mismatch
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
d4383d4180 Fixed: Improved failed series search messaging
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
72314c4388 Fixed: Manage Tracks not showing whether language/quality meets cutoff
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
17b5187729 Fixed: Delay profile being ignored for non-revision upgrades
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
e30c078962 Remove unnecessary usings
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
d808934cf4 Remove Dotnet Framework Version Checks
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
nitsua
b3b4955fb2 New: Add label to disk usage progress bar
(cherry picked from commit 7c8ac300777583cb93d9deeed1328bcffaef555c)
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Qstick
4765236940 Catchup Linting
Signed-off-by: Robin Dadswell <robin@dadswell.email>
2021-01-28 23:43:19 -05:00
Mark McDowall
32a49083e7 New: Show health warning if system time is off expected time 2021-01-28 23:43:19 -05:00
Qstick
9c096aae10 Fixed: Performance issue when scanning large root folder 2021-01-28 23:43:19 -05:00
Dyson Parkes
90b59a56e1 Update MonitorToggleButton.js
Fix toggle monitored state tooltip spelling.
2021-01-28 23:43:19 -05:00
Qstick
134523247c Misc UI Cleanup 2021-01-28 23:43:19 -05:00
Qstick
e5ba8af3ce Fixed: Styling issues in Quality Profile and Release Profiles 2021-01-28 23:43:19 -05:00
Qstick
10fd15b50a Fixed: Tag inputs respect non-QWERTY layouts 2021-01-28 23:43:19 -05:00
Qstick
dd93531432 Fixed: Deleting row from middle of filter builder leading to error 2021-01-28 23:43:19 -05:00
bakerboy448
762a085f9a Fixed: Rotating mobile device when modal is open won't reset modal 2021-01-28 23:43:19 -05:00
Qstick
8d63da1cfb Fixed: Toolbar button collapsing includes separator 2021-01-28 23:43:19 -05:00
Qstick
7a95cedbad New: Indicator when Filter Applied 2021-01-28 23:43:19 -05:00
ta264
44d73f3e7e New: Warn if UI won't update due to SignalR errors 2021-01-28 23:43:19 -05:00
Taloth Saldono
786247e9bc Added Plex url to cleanser 2021-01-28 23:43:19 -05:00
Taloth Saldono
c152cc2517 Fixed typo in Cleanse IP 2021-01-28 23:43:19 -05:00
Taloth Saldono
3d86e29972 Cleanse remote IP Address from trace log file 2021-01-28 23:43:19 -05:00
Taloth Saldono
e3c239e848 Cleanse getnzb url 2021-01-28 23:43:19 -05:00
1792 changed files with 100758 additions and 35243 deletions

View File

@@ -19,10 +19,10 @@ indent_size = 4
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
dotnet_style_qualification_for_field = false:warning
dotnet_style_qualification_for_property = false:warning
dotnet_style_qualification_for_method = false:warning
dotnet_style_qualification_for_event = false:warning
# Indentation preferences
csharp_indent_block_contents = true
@@ -32,10 +32,6 @@ 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 = _
@@ -110,13 +106,13 @@ dotnet_diagnostic.SA1643.severity = none
dotnet_diagnostic.SA1648.severity = none
dotnet_diagnostic.SA1649.severity = none
dotnet_diagnostic.SA1651.severity = none
dotnet_diagnostic.SX1101.severity = warning
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
@@ -163,10 +159,16 @@ 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.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
@@ -175,12 +177,14 @@ 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.CA1801.severity = suggestion
dotnet_diagnostic.CA1802.severity = suggestion
dotnet_diagnostic.CA1805.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
@@ -210,6 +214,7 @@ 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
@@ -255,6 +260,8 @@ 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

View File

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

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

@@ -0,0 +1,75 @@
name: Bug Report
description: 'Report a new bug, if you are not 100% certain this is a bug please go to our Reddit or Discord first'
labels: ['Type: Bug', 'Status: Needs Triage']
body:
- type: checkboxes
attributes:
label: Is there an existing issue for this?
description: Please search to see if an open or closed issue already exists for the bug you encountered. If a bug exists and is closed note that it may only be fixed in an unstable branch.
options:
- label: I have searched the existing open and closed issues
required: true
- type: textarea
attributes:
label: Current Behavior
description: A concise description of what you're experiencing.
validations:
required: true
- type: textarea
attributes:
label: Expected Behavior
description: A concise description of what you expected to happen.
validations:
required: true
- type: textarea
attributes:
label: Steps To Reproduce
description: Steps to reproduce the behavior.
placeholder: |
1. In this environment...
2. With this config...
3. Run '...'
4. See error...
validations:
required: false
- type: textarea
attributes:
label: Environment
description: |
examples:
- **OS**: Ubuntu 20.04
- **Readarr**: Readarr 0.1.0.432
- **Docker Install**: Yes
- **Using Reverse Proxy**: No
- **Browser**: Firefox 90 (If UI related)
- **Database**: Sqlite 3.36.0
value: |
- OS:
- Readarr:
- Docker Install:
- Using Reverse Proxy:
- Browser:
- Database:
render: markdown
validations:
required: true
- type: dropdown
attributes:
label: What branch are you running?
options:
- Master
- Develop
- Nightly
- Other (This issue will be closed)
validations:
required: true
- type: textarea
attributes:
label: Trace Logs?
description: |
Trace Logs (https://wiki.servarr.com/readarr/troubleshooting#logging-and-log-files)
***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.
Additionally, any additional info? Screenshots? References? Anything that will give us more context about the issue you are encountering!
validations:
required: true

View File

@@ -1,7 +1,7 @@
blank_issues_enabled: false
contact_links:
- name: Support via Discord
url: https://discord.gg/rkEXY2Rbgn
url: https://readarr.com/discord
about: Chat with users and devs on support and setup related topics.
- name: Support via Reddit
url: https://reddit.com/r/Readarr

View File

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

View File

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

View File

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

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

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

21
.github/workflows/lock.yml vendored Normal file
View File

@@ -0,0 +1,21 @@
name: 'Lock threads'
on:
workflow_dispatch:
schedule:
- cron: '0 0 * * *'
jobs:
lock:
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@v2
with:
github-token: ${{ github.token }}
issue-lock-inactive-days: '90'
issue-exclude-created-before: ''
issue-exclude-labels: ''
issue-lock-labels: ''
issue-lock-comment: ''
issue-lock-reason: 'resolved'
process-only: ''

21
.github/workflows/support.yml vendored Normal file
View File

@@ -0,0 +1,21 @@
name: 'Support requests'
on:
issues:
types: [labeled, unlabeled, reopened]
jobs:
support:
runs-on: ubuntu-latest
steps:
- uses: dessant/support-requests@v2
with:
github-token: ${{ github.token }}
support-label: 'Type: Support'
issue-comment: >
:wave: @{issue-author}, we use the issue tracker exclusively
for bug reports and feature requests. However, this issue appears
to be a support request. Please hop over onto our [Discord](https://readarr.com/discord)
or [Subreddit](https://reddit.com/r/readarr)
close-issue: true
lock-issue: false

View File

@@ -1,5 +0,0 @@
{
"files.associations": {
"*.yaml": "home-assistant"
}
}

132
CODE_OF_CONDUCT.md Normal file
View File

@@ -0,0 +1,132 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, caste, color, religion, or sexual
identity and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the overall
community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or advances of
any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email address,
without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
<development@readarr.com>.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series of
actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or permanent
ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within the
community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.1, available at
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
Community Impact Guidelines were inspired by
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
For answers to common questions about this code of conduct, see the FAQ at
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
[https://www.contributor-covenant.org/translations][translations].
[homepage]: https://www.contributor-covenant.org
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations

View File

@@ -1,49 +1,13 @@
# How to Contribute #
# How to Contribute
We're always looking for people to help make Readarr even better, there are a number of ways to contribute.
## Documentation ##
Setup guides, FAQ, the more information we have on the [wiki](https://wiki.servarr.com/Readarr) the better.
This file has been moved to the wiki for the latest details please see the [contributing wiki page](https://wiki.servarr.com/readarr/contributing).
## Development ##
## Documentation
### Tools required ###
- Visual Studio 2019 or higher (https://www.visualstudio.com/vs/). The community version is free and works (https://www.visualstudio.com/downloads/).
- HTML/Javascript editor of choice (VS Code/Sublime Text/Webstorm/Atom/etc)
- [Git](https://git-scm.com/downloads)
- [NodeJS](https://nodejs.org/en/download/) (Node 10.X.X or higher)
- [Yarn](https://yarnpkg.com/)
- .NET Core 3.1.
Setup guides, [FAQ](https://wiki.servarr.com/readarr/faq), the more information we have on the [wiki](https://wiki.servarr.com/readarr) the better.
### Getting started ###
## Development
1. Fork Readarr
2. Clone the repository into your development machine. [*info*](https://help.github.com/articles/working-with-repositories)
3. Install the required Node Packages `yarn install`
4. Start gulp to monitor your dev environment for any changes that need post processing using `yarn start` command.
5. Build the project in Visual Studio, Setting startup project to `Readarr.Console` and framework to `netcoreapp31`
6. Debug the project in Visual Studio
7. Open http://localhost:8787
### Contributing Code ###
- If you're adding a new, already requested feature, please comment on [Github Issues](https://github.com/Readarr/Readarr/issues "Github Issues") so work is not duplicated (If you want to add something not already on there, please talk to us first)
- Rebase from Readarr's develop branch, don't merge
- Make meaningful commits, or squash them
- Feel free to make a pull request before work is complete, this will let us see where its at and make comments/suggest improvements
- Reach out to us on the discord if you have any questions
- Add tests (unit/integration)
- Commit with *nix line endings for consistency (We checkout Windows and commit *nix)
- One feature/bug fix per pull request to keep things clean and easy to understand
- Use 4 spaces instead of tabs, this is the default for VS 2019 and WebStorm (to my knowledge)
### Pull Requesting ###
- Only make pull requests to develop, never master, if you make a PR to master we'll comment on it and close it
- You're probably going to get some comments or questions from us, they will be to ensure consistency and maintainability
- We'll try to respond to pull requests as soon as possible, if its been a day or two, please reach out to us, we may have missed it
- Each PR should come from its own [feature branch](http://martinfowler.com/bliki/FeatureBranch.html) not develop in your fork, it should have a meaningful branch name (what is being added/fixed)
- new-feature (Good)
- fix-bug (Good)
- patch (Bad)
- develop (Bad)
If you have any questions about any of this, please let us know.
See the [Wiki Page](https://wiki.servarr.com/readarr/contributing)

View File

@@ -1,52 +1,68 @@
# Readarr
[![Build Status](https://dev.azure.com/Readarr/Readarr/_apis/build/status/Readarr.Readarr?branchName=develop)](https://dev.azure.com/Readarr/Readarr/_build/latest?definitionId=1&branchName=develop)
[![Docker Pulls](https://img.shields.io/docker/pulls/hotio/readarr)](https://hub.docker.com/r/hotio/readarr)
[![Backers on Open Collective](https://opencollective.com/readarr/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/readarr/sponsors/badge.svg)](#sponsors)
[![Translated](https://translate.servarr.com/widgets/servarr/-/readarr/svg-badge.svg)](https://translate.servarr.com/engage/readarr/?utm_source=widget)
[![Docker Pulls](https://img.shields.io/docker/pulls/hotio/readarr)](https://wiki.servarr.com/readarr/installation#docker)
[![Donors on Open Collective](https://opencollective.com/Readarr/backers/badge.svg)](#backers)
[![Sponsors on Open Collective](https://opencollective.com/Readarr/sponsors/badge.svg)](#sponsors)
[![Mega Sponsors on Open Collective](https://opencollective.com/Readarr/megasponsors/badge.svg)](#mega-sponsors)
### Readarr is in early stages of development, alpha/beta binary builds are not yet available. Use of any test builds isn't recommend, and may have detrimental effects on your library.
### Readarr is currently in beta testing and is generally still in a work in progress. Features may be broken, incomplete, or cause spontaneous combustion
Readarr is a ebook (and maybe eventually magazine/audiobook) collection manager for Usenet and BitTorrent users. It can monitor multiple RSS feeds for new books from your favorite authors and will grab, sort and rename them.
Readarr is an ebook and audiobook collection manager for Usenet and BitTorrent users. It can monitor multiple RSS feeds for new books from your favorite authors and will grab, sort, and rename them.
Note that only one type of a given book is supported. If you want both an audiobook and ebook of a given book you will need multiple instances.
## Major Features Include:
## Major Features Include
* Can watch for better quality of the ebooks and audiobooks you have and do an automatic upgrade. *e.g. from PDF to AZW3*
* Support for major platforms: Windows, Linux, macOS, Raspberry Pi, etc.
* Automatically detects new books.
* Can scan your existing library and download any missing books.
* Automatically detects new books
* Can scan your existing library and download any missing books
* Automatic failed download handling will try another release if one fails
* Manual search so you can pick any release or to see why a release was not downloaded automatically
* Advanced customization for profiles, such that Readarr will always download the copy you want
* Fully configurable book renaming
* Full integration with SABnzbd and NZBGet
* Full integration with Calibre (add to library, conversion)
* SABnzbd, NZBGet, QBittorrent, Deluge, rTorrent, Transmission, uTorrent, and other download clients are supported and integrated
* Full integration with Calibre (add to library, conversion) (Requires Calibre Content Server)
* And a beautiful UI
## Support
[![Discord](https://img.shields.io/badge/discord-chat-7289DA.svg?maxAge=60)](https://discord.gg/rkEXY2Rbgn)
[![GitHub](https://img.shields.io/badge/github-issues-red.svg?maxAge=60)](https://github.com/Readarr/Readarr/issues)
[![Wiki](https://img.shields.io/badge/servarr-wiki-181717.svg?maxAge=60)](https://wiki.servarr.com/Readarr)
[![Wiki](https://img.shields.io/badge/servarr-wiki-181717.svg?maxAge=60)](https://wiki.servarr.com/readarr)
[![Discord](https://img.shields.io/badge/discord-chat-7289DA.svg?maxAge=60)](https://readarr.com/discord)
[![Reddit](https://img.shields.io/badge/reddit-discussion-FF4500.svg?maxAge=60)](https://www.reddit.com/r/readarr)
## Contributors
Note: GitHub Issues are for Bugs and Feature Requests Only
This project exists thanks to all the people who contribute. [Contribute](CONTRIBUTING.md).
<a href="https://github.com/Readarr/Readarr/graphs/contributors"><img src="https://opencollective.com/Readarr/contributors.svg?width=890&button=false" /></a>
[![GitHub - Bugs and Feature Requests Only](https://img.shields.io/badge/github-issues-red.svg?maxAge=60)](https://github.com/Readarr/Readarr/issues)
## Contributors & Developers
[API Documentation](https://readarr.com/docs/api/)
This project exists thanks to all the people who contribute.
- [Contribute (GitHub)](CONTRIBUTING.md)
- [Contribution (Wiki Article)](https://wiki.servarr.com/readarr/contributing)
[![Contributors List](https://opencollective.com/Readarr/contributors.svg?width=890&button=false)](https://github.com/Readarr/Readarr/graphs/contributors)
## Backers
Thank you to all our backers! 🙏 [Become a backer](https://opencollective.com/readarr#backer)
Thank you to all our backers! 🙏 [Become a backer](https://opencollective.com/Readarr#backer)
<img src="https://opencollective.com/readarr/backers.svg?width=890"></a>
[![Backers List](https://opencollective.com/Readarr/backers.svg?width=890)](https://opencollective.com/Readarr#backer)
## Sponsors
Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [Become a sponsor](https://opencollective.com/readarr#sponsor)
<img src="https://opencollective.com/readarr/sponsors.svg?width=890"></a>
[![Sponsors List](https://opencollective.com/Readarr/sponsors.svg?width=890)](https://opencollective.com/readarr#sponsor)
## Mega Sponsors
<img src="https://opencollective.com/readarr/tiers/mega-sponsor.svg?width=890"></a>
[![Mega Sponsors List](https://opencollective.com/Readarr/tiers/mega-sponsor.svg?width=890)](https://opencollective.com/readarr#mega-sponsor)
### License
* [GNU GPL v3](http://www.gnu.org/licenses/gpl.html)
* Copyright 2010-2021
* Copyright 2010-2022

8
SECURITY.md Normal file
View File

@@ -0,0 +1,8 @@
# Security Policy
## Reporting a Vulnerability
Please report (suspected) security vulnerabilities on Discord (preferred) to
any of the Servarr Dev role holders (red names) or via email: development@servarr.com. 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.

File diff suppressed because it is too large Load Diff

168
build.sh
View File

@@ -1,4 +1,4 @@
#! /bin/bash
#! /usr/bin/env bash
set -e
outputFolder='_output'
@@ -27,6 +27,25 @@ UpdateVersionNumber()
fi
}
EnableExtraPlatformsInSDK()
{
SDK_PATH=$(dotnet --list-sdks | grep -P '6\.\d\.\d+' | head -1 | sed 's/\(6\.[0-9]*\.[0-9]*\).*\[\(.*\)\]/\2\/\1/g')
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;linux-x86/' $BUNDLEDVERSIONS
fi
}
EnableExtraPlatforms()
{
if grep -qv freebsd-x64 src/Directory.Build.props; then
sed -i'' -e "s^<RuntimeIdentifiers>\(.*\)</RuntimeIdentifiers>^<RuntimeIdentifiers>\1;freebsd-x64;linux-x86</RuntimeIdentifiers>^g" src/Directory.Build.props
fi
}
LintUI()
{
ProgressStart 'ESLint'
@@ -57,9 +76,6 @@ Build()
platform=Posix
fi
dotnet clean $slnFile -c Debug
dotnet clean $slnFile -c Release
if [[ -z "$RID" || -z "$FRAMEWORK" ]];
then
dotnet msbuild -restore $slnFile -p:Configuration=Release -p:Platform=$platform -t:PublishAllRids
@@ -77,11 +93,11 @@ YarnInstall()
ProgressEnd 'yarn install'
}
RunGulp()
RunWebpack()
{
ProgressStart 'Running gulp'
yarn run build --production
ProgressEnd 'Running gulp'
ProgressStart 'Running webpack'
yarn run build --env production
ProgressEnd 'Running webpack'
}
PackageFiles()
@@ -120,7 +136,7 @@ PackageLinux()
echo "Adding Readarr.Mono to UpdatePackage"
cp $folder/Readarr.Mono.* $folder/Readarr.Update
if [ "$framework" = "netcoreapp3.1" ]; then
if [ "$framework" = "net6.0" ]; then
cp $folder/Mono.Posix.NETStandard.* $folder/Readarr.Update
cp $folder/libMonoPosixHelper.* $folder/Readarr.Update
fi
@@ -131,17 +147,13 @@ PackageLinux()
PackageMacOS()
{
local framework="$1"
local runtime="$2"
ProgressStart "Creating MacOS Package for $framework"
ProgressStart "Creating MacOS Package for $framework $runtime"
local folder=$artifactsFolder/macos/$framework/Readarr
local folder=$artifactsFolder/$runtime/$framework/Readarr
PackageFiles "$folder" "$framework" "osx-x64"
if [ "$framework" = "net462" ]; then
echo "Adding Startup script"
cp macOS/Readarr $folder
fi
PackageFiles "$folder" "$framework" "$runtime"
echo "Removing Service helpers"
rm -f $folder/ServiceUninstall.*
@@ -152,7 +164,7 @@ PackageMacOS()
echo "Adding Readarr.Mono to UpdatePackage"
cp $folder/Readarr.Mono.* $folder/Readarr.Update
if [ "$framework" = "netcoreapp3.1" ]; then
if [ "$framework" = "net6.0" ]; then
cp $folder/Mono.Posix.NETStandard.* $folder/Readarr.Update
cp $folder/libMonoPosixHelper.* $folder/Readarr.Update
fi
@@ -163,10 +175,11 @@ PackageMacOS()
PackageMacOSApp()
{
local framework="$1"
local runtime="$2"
ProgressStart "Creating macOS App Package for $framework"
ProgressStart "Creating macOS App Package for $framework $runtime"
local folder=$artifactsFolder/macos-app/$framework
local folder="$artifactsFolder/$runtime-app/$framework"
rm -rf $folder
mkdir -p $folder
@@ -174,7 +187,7 @@ PackageMacOSApp()
mkdir -p $folder/Readarr.app/Contents/MacOS
echo "Copying Binaries"
cp -r $artifactsFolder/macos/$framework/Readarr/* $folder/Readarr.app/Contents/MacOS
cp -r $artifactsFolder/$runtime/$framework/Readarr/* $folder/Readarr.app/Contents/MacOS
echo "Removing Update Folder"
rm -r $folder/Readarr.app/Contents/MacOS/Readarr.Update
@@ -186,12 +199,13 @@ PackageWindows()
{
local framework="$1"
local runtime="$2"
ProgressStart "Creating Windows Package for $framework"
ProgressStart "Creating $runtime Package for $framework"
local folder=$artifactsFolder/$runtime/$framework/Readarr
PackageFiles "$folder" "$framework" "$runtime"
cp -r $outputFolder/$framework-windows/$runtime/publish/* $folder
echo "Removing Readarr.Mono"
rm -f $folder/Readarr.Mono.*
@@ -201,7 +215,7 @@ PackageWindows()
echo "Adding Readarr.Windows to UpdatePackage"
cp $folder/Readarr.Windows.* $folder/Readarr.Update
ProgressEnd 'Creating Windows Package'
ProgressEnd "Creating $runtime Package for $framework"
}
Package()
@@ -213,19 +227,45 @@ Package()
IFS='-' read -ra SPLIT <<< "$runtime"
case "${SPLIT[0]}" in
linux)
linux|freebsd*)
PackageLinux "$framework" "$runtime"
;;
win)
PackageWindows "$framework" "$runtime"
;;
osx)
PackageMacOS "$framework"
PackageMacOSApp "$framework"
PackageMacOS "$framework" "$runtime"
PackageMacOSApp "$framework" "$runtime"
;;
esac
}
BuildInstaller()
{
local framework="$1"
local runtime="$2"
./_inno/ISCC.exe setup/readarr.iss "//DFramework=$framework" "//DRuntime=$runtime"
}
InstallInno()
{
ProgressStart "Installing portable Inno Setup"
rm -rf _inno
curl -s --output innosetup.exe "https://files.jrsoftware.org/is/6/innosetup-${INNOVERSION:-6.2.0}.exe"
mkdir _inno
./innosetup.exe //portable=1 //silent //currentuser //dir=.\\_inno
rm innosetup.exe
ProgressEnd "Installed portable Inno Setup"
}
RemoveInno()
{
rm -rf _inno
}
PackageTests()
{
local framework="$1"
@@ -257,7 +297,10 @@ if [ $# -eq 0 ]; then
BACKEND=YES
FRONTEND=YES
PACKAGES=YES
INSTALLER=NO
LINT=YES
ENABLE_EXTRA_PLATFORMS=NO
ENABLE_EXTRA_PLATFORMS_IN_SDK=NO
fi
while [[ $# -gt 0 ]]
@@ -269,6 +312,14 @@ case $key in
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
@@ -287,6 +338,10 @@ case $key in
PACKAGES=YES
shift # past argument
;;
--installer)
INSTALLER=YES
shift # past argument
;;
--lint)
LINT=YES
shift # past argument
@@ -306,18 +361,31 @@ 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 "netcoreapp3.1" "win-x64"
PackageTests "netcoreapp3.1" "win-x86"
PackageTests "netcoreapp3.1" "linux-x64"
PackageTests "netcoreapp3.1" "linux-musl-x64"
PackageTests "netcoreapp3.1" "osx-x64"
PackageTests "net462" "linux-x64"
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"
PackageTests "net6.0" "linux-x86"
fi
else
PackageTests "$FRAMEWORK" "$RID"
fi
@@ -326,7 +394,7 @@ fi
if [ "$FRONTEND" = "YES" ];
then
YarnInstall
RunGulp
RunWebpack
fi
if [ "$LINT" = "YES" ];
@@ -345,16 +413,30 @@ then
if [[ -z "$RID" || -z "$FRAMEWORK" ]];
then
Package "netcoreapp3.1" "win-x64"
Package "netcoreapp3.1" "win-x86"
Package "netcoreapp3.1" "linux-x64"
Package "netcoreapp3.1" "linux-musl-x64"
Package "netcoreapp3.1" "linux-arm64"
Package "netcoreapp3.1" "linux-musl-arm64"
Package "netcoreapp3.1" "linux-arm"
Package "netcoreapp3.1" "osx-x64"
Package "net462" "linux-x64"
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" "linux-musl-arm"
Package "net6.0" "osx-x64"
Package "net6.0" "osx-arm64"
if [ "$ENABLE_EXTRA_PLATFORMS" = "YES" ];
then
Package "net6.0" "freebsd-x64"
Package "net6.0" "linux-x86"
fi
else
Package "$FRAMEWORK" "$RID"
fi
fi
if [ "$INSTALLER" = "YES" ];
then
InstallInno
BuildInstaller "net6.0" "win-x64"
BuildInstaller "net6.0" "win-x86"
RemoveInno
fi

5
debian/changelog vendored
View File

@@ -1,5 +0,0 @@
nzbdrone {version} {branch}; urgency=low
* Automatic Release.
-- NzbDrone <contact@nzbdrone.com> Mon, 26 Aug 2013 00:00:00 -0700

1
debian/compat vendored
View File

@@ -1 +0,0 @@
8

12
debian/control vendored
View File

@@ -1,12 +0,0 @@
Section: web
Priority: optional
Maintainer: Sonarr <contact@nzbdrone.com>
Source: nzbdrone
Homepage: https://readarr.com
Vcs-Git: git@github.com:readarr/Readarr.git
Vcs-Browser: https://github.com/readarr/Readarr
Package: nzbdrone
Architecture: all
Depends: libmono-cil-dev (>= 3.2), sqlite3 (>= 3.7), mediainfo (>= 0.7.52)
Description: Readarr is a music collection manager

24
debian/copyright vendored
View File

@@ -1,24 +0,0 @@
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: nzbdrone
Source: https://github.com/readarr/Readarr
Files: *
Copyright: 2010-2016 Readarr <hello@readarr.com>
License: GPL-3.0+
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
.
This package is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
.
On Debian systems, the complete text of the GNU General
Public License version 3 can be found in "/usr/share/common-licenses/GPL-3".

1
debian/install vendored
View File

@@ -1 +0,0 @@
nzbdrone_bin/* opt/NzbDrone

13
debian/rules vendored
View File

@@ -1,13 +0,0 @@
#!/usr/bin/make -f
# -*- makefile -*-
# Sample debian/rules that uses debhelper.
# This file was originally written by Joey Hess and Craig Small.
# As a special exception, when this file is copied by dh-make into a
# dh-make output file, you may use that output file without restriction.
# This special exception was added by Craig Small in version 0.37 of dh-make.
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
%:
dh $@

View File

@@ -6,8 +6,10 @@ const dirs = fs
.map((dirent) => dirent.name)
.join('|');
const frontendFolder = __dirname;
module.exports = {
parser: 'babel-eslint',
parser: '@babel/eslint-parser',
env: {
browser: true,
@@ -25,6 +27,9 @@ module.exports = {
parserOptions: {
ecmaVersion: 6,
sourceType: 'module',
babelOptions: {
configFile: `${frontendFolder}/babel.config.js`,
},
ecmaFeatures: {
modules: true,
impliedStrict: true
@@ -34,6 +39,7 @@ module.exports = {
plugins: [
'filenames',
'react',
'react-hooks',
'simple-import-sort',
'import'
],
@@ -271,7 +277,7 @@ module.exports = {
// ImportSort
'simple-import-sort/sort': 'error',
'simple-import-sort/imports': 'error',
'import/newline-after-import': 'error',
// React
@@ -303,13 +309,15 @@ module.exports = {
'react/react-in-jsx-scope': 2,
'react/self-closing-comp': 2,
'react/sort-comp': 2,
'react/jsx-wrap-multilines': 2
'react/jsx-wrap-multilines': 2,
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'error'
},
overrides: [
{
files: ['*.js'],
rules: {
'simple-import-sort/sort': [
'simple-import-sort/imports': [
'error',
{
groups: [

View File

@@ -0,0 +1,270 @@
const path = require('path');
const webpack = require('webpack');
const FileManagerPlugin = require('filemanager-webpack-plugin');
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');
module.exports = (env) => {
const uiFolder = 'UI';
const frontendFolder = path.join(__dirname, '..');
const srcFolder = path.join(frontendFolder, 'src');
const isProduction = !!env.production;
const isProfiling = isProduction && !!env.profile;
const inlineWebWorkers = 'no-fallback';
const distFolder = path.resolve(frontendFolder, '..', '_output', uiFolder);
console.log('Source Folder:', srcFolder);
console.log('Output Folder:', distFolder);
console.log('isProduction:', isProduction);
console.log('isProfiling:', isProfiling);
const config = {
mode: isProduction ? 'production' : 'development',
devtool: isProduction ? 'source-map' : 'eval-source-map',
stats: {
children: false
},
watchOptions: {
ignored: /node_modules/
},
entry: {
index: 'index.js'
},
resolve: {
modules: [
srcFolder,
path.join(srcFolder, 'Shims'),
'node_modules'
],
alias: {
jquery: 'jquery/src/jquery'
},
fallback: {
buffer: false,
http: false,
https: false,
url: false,
util: false,
net: false
}
},
output: {
path: distFolder,
publicPath: '/',
filename: '[name].js',
sourceMapFilename: '[file].map'
},
optimization: {
moduleIds: 'deterministic',
chunkIds: 'named',
splitChunks: {
chunks: 'initial',
name: 'vendors'
}
},
performance: {
hints: false
},
plugins: [
new webpack.DefinePlugin({
__DEV__: !isProduction,
'process.env.NODE_ENV': isProduction ? JSON.stringify('production') : JSON.stringify('development')
}),
new MiniCssExtractPlugin({
filename: 'Content/styles.css'
}),
new HtmlWebpackPlugin({
template: 'frontend/src/index.ejs',
filename: 'index.html',
publicPath: '/'
}),
new FileManagerPlugin({
events: {
onEnd: {
copy: [
// HTML
{
source: 'frontend/src/*.html',
destination: distFolder
},
// Fonts
{
source: 'frontend/src/Content/Fonts/*.*',
destination: path.join(distFolder, 'Content/Fonts')
},
// Icon Images
{
source: 'frontend/src/Content/Images/Icons/*.*',
destination: path.join(distFolder, 'Content/Images/Icons')
},
// Images
{
source: 'frontend/src/Content/Images/*.*',
destination: path.join(distFolder, 'Content/Images')
},
// Robots
{
source: 'frontend/src/Content/robots.txt',
destination: path.join(distFolder, 'Content/robots.txt')
}
]
}
}
}),
new LiveReloadPlugin()
],
resolveLoader: {
modules: [
'node_modules',
'frontend/build/webpack/'
]
},
module: {
rules: [
{
test: /\.worker\.js$/,
use: {
loader: 'worker-loader',
options: {
filename: '[name].js',
inline: inlineWebWorkers
}
}
},
{
test: /\.js?$/,
exclude: /(node_modules|JsLibraries)/,
use: [
{
loader: 'babel-loader',
options: {
configFile: `${frontendFolder}/babel.config.js`,
envName: isProduction ? 'production' : 'development',
presets: [
[
'@babel/preset-env',
{
modules: false,
loose: true,
debug: false,
useBuiltIns: 'entry',
corejs: 3
}
]
]
}
}
]
},
// CSS Modules
{
test: /\.css$/,
exclude: /(node_modules|globals.css)/,
use: [
{ loader: MiniCssExtractPlugin.loader },
{
loader: 'css-loader',
options: {
importLoaders: 1,
modules: {
localIdentName: '[name]/[local]/[hash:base64:5]'
}
}
},
{
loader: 'postcss-loader',
options: {
postcssOptions: {
config: 'frontend/postcss.config.js'
}
}
}
]
},
// Global styles
{
test: /\.css$/,
include: /(node_modules|globals.css)/,
use: [
'style-loader',
{
loader: 'css-loader'
}
]
},
// Fonts
{
test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
use: [
{
loader: 'url-loader',
options: {
limit: 10240,
mimetype: 'application/font-woff',
emitFile: false,
name: 'Content/Fonts/[name].[ext]'
}
}
]
},
{
test: /\.(ttf|eot|eot?#iefix|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
use: [
{
loader: 'file-loader',
options: {
emitFile: false,
name: 'Content/Fonts/[name].[ext]'
}
}
]
}
]
}
};
if (isProfiling) {
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
}
})
];
}
return config;
};

View File

@@ -1,18 +0,0 @@
const gulp = require('gulp');
require('./clean');
require('./copy');
require('./webpack');
gulp.task('build',
gulp.series('clean',
gulp.parallel(
'webpack',
'copyHtml',
'copyFonts',
'copyImages',
'copyRobots'
)
)
);

View File

@@ -1,8 +0,0 @@
const gulp = require('gulp');
const del = require('del');
const paths = require('./helpers/paths');
gulp.task('clean', () => {
return del([paths.dest.root]);
});

View File

@@ -1,42 +0,0 @@
const path = require('path');
const gulp = require('gulp');
const print = require('gulp-print').default;
const cache = require('gulp-cached');
const livereload = require('gulp-livereload');
const paths = require('./helpers/paths.js');
gulp.task('copyHtml', () => {
return gulp.src(paths.src.html, { base: paths.src.root })
.pipe(cache('copyHtml'))
.pipe(print())
.pipe(gulp.dest(paths.dest.root))
.pipe(livereload());
});
gulp.task('copyFonts', () => {
return gulp.src(
path.join(paths.src.fonts, '**', '*.*'), { base: paths.src.root }
)
.pipe(cache('copyFonts'))
.pipe(print())
.pipe(gulp.dest(paths.dest.root))
.pipe(livereload());
});
gulp.task('copyImages', () => {
return gulp.src(
path.join(paths.src.images, '**', '*.*'), { base: paths.src.root }
)
.pipe(cache('copyImages'))
.pipe(print())
.pipe(gulp.dest(paths.dest.root))
.pipe(livereload());
});
gulp.task('copyRobots', () => {
return gulp.src(paths.src.robots, { base: paths.src.root })
.pipe(cache('copyRobots'))
.pipe(print())
.pipe(gulp.dest(paths.dest.root))
.pipe(livereload());
});

View File

@@ -1,5 +0,0 @@
require('./build.js');
require('./clean.js');
require('./copy.js');
require('./watch.js');
require('./webpack.js');

View File

@@ -1,6 +0,0 @@
const colors = require('ansi-colors');
module.exports = function errorHandler(error) {
console.log(colors.red(`Error (${error.plugin}): ${error.message}`));
this.emit('end');
};

View File

@@ -1,24 +0,0 @@
const root = './frontend/src';
const paths = {
src: {
root,
html: `${root}/*.html`,
scripts: `${root}/**/*.js`,
content: `${root}/Content/`,
fonts: `${root}/Content/Fonts/`,
images: `${root}/Content/Images/`,
robots: `${root}/Content/robots.txt`,
exclude: {
libs: `!${root}/JsLibraries/**`
}
},
dest: {
root: './_output/UI/',
content: './_output/UI/Content/',
fonts: './_output/UI/Content/Fonts/',
images: './_output/UI/Content/Images/'
}
};
module.exports = paths;

View File

@@ -1,19 +0,0 @@
const gulp = require('gulp');
const livereload = require('gulp-livereload');
const gulpWatch = require('gulp-watch');
const paths = require('./helpers/paths.js');
require('./copy.js');
require('./webpack.js');
function watch() {
livereload.listen({ start: true });
gulp.task('webpackWatch')();
gulpWatch(paths.src.html, gulp.series('copyHtml'));
gulpWatch(`${paths.src.fonts}**/*.*`, gulp.series('copyFonts'));
gulpWatch(`${paths.src.images}**/*.*`, gulp.series('copyImages'));
gulpWatch(paths.src.robots, gulp.series('copyRobots'));
}
gulp.task('watch', gulp.series('build', watch));

View File

@@ -1,271 +0,0 @@
const gulp = require('gulp');
const webpackStream = require('webpack-stream');
const livereload = require('gulp-livereload');
const path = require('path');
const webpack = require('webpack');
const errorHandler = require('./helpers/errorHandler');
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const HtmlWebpackPluginHtmlTags = require('html-webpack-plugin/lib/html-tags');
const TerserPlugin = require('terser-webpack-plugin');
const uiFolder = 'UI';
const frontendFolder = path.join(__dirname, '..');
const srcFolder = path.join(frontendFolder, 'src');
const isProduction = process.argv.indexOf('--production') > -1;
const isProfiling = isProduction && process.argv.indexOf('--profile') > -1;
const inlineWebWorkers = 'no-fallback';
const distFolder = path.resolve(frontendFolder, '..', '_output', uiFolder);
console.log('Source Folder:', srcFolder);
console.log('Output Folder:', distFolder);
console.log('isProduction:', isProduction);
console.log('isProfiling:', isProfiling);
const cssVarsFiles = [
'../src/Styles/Variables/colors',
'../src/Styles/Variables/dimensions',
'../src/Styles/Variables/fonts',
'../src/Styles/Variables/animations',
'../src/Styles/Variables/zIndexes'
].map(require.resolve);
// Override the way HtmlWebpackPlugin injects the scripts
// TODO: Find a better way to get these paths without
HtmlWebpackPlugin.prototype.injectAssetsIntoHtml = function(html, assets, assetTags) {
const head = assetTags.headTags.map((v) => {
const href = v.attributes.href
.replace('\\', '/')
.replace('%5C', '/');
v.attributes = { rel: 'stylesheet', type: 'text/css', href: `/${href}` };
return HtmlWebpackPluginHtmlTags.htmlTagObjectToString(v, this.options.xhtml);
});
const body = assetTags.bodyTags.map((v) => {
v.attributes = { src: `/${v.attributes.src}` };
return HtmlWebpackPluginHtmlTags.htmlTagObjectToString(v, this.options.xhtml);
});
return html
.replace('<!-- webpack bundles head -->', head.join('\r\n '))
.replace('<!-- webpack bundles body -->', body.join('\r\n '));
};
const plugins = [
new OptimizeCssAssetsPlugin({}),
new webpack.DefinePlugin({
__DEV__: !isProduction,
'process.env.NODE_ENV': isProduction ? JSON.stringify('production') : JSON.stringify('development')
}),
new MiniCssExtractPlugin({
filename: path.join('Content', 'styles.css')
}),
new HtmlWebpackPlugin({
template: 'frontend/src/index.html',
filename: 'index.html'
})
];
const config = {
mode: isProduction ? 'production' : 'development',
devtool: '#source-map',
stats: {
children: false
},
watchOptions: {
ignored: /node_modules/
},
entry: {
index: 'index.js'
},
resolve: {
modules: [
srcFolder,
path.join(srcFolder, 'Shims'),
'node_modules'
],
alias: {
jquery: 'jquery/src/jquery'
}
},
output: {
path: distFolder,
filename: '[name].js',
sourceMapFilename: '[file].map'
},
optimization: {
chunkIds: 'named',
splitChunks: {
chunks: 'initial'
}
},
performance: {
hints: false
},
plugins,
resolveLoader: {
modules: [
'node_modules',
'frontend/gulp/webpack/'
]
},
module: {
rules: [
{
test: /\.worker\.js$/,
use: {
loader: 'worker-loader',
options: {
filename: '[name].js',
inline: inlineWebWorkers
}
}
},
{
test: /\.js?$/,
exclude: /(node_modules|JsLibraries)/,
use: [
{
loader: 'babel-loader',
options: {
configFile: `${frontendFolder}/babel.config.js`,
envName: isProduction ? 'production' : 'development',
presets: [
[
'@babel/preset-env',
{
modules: false,
loose: true,
debug: false,
useBuiltIns: 'entry',
corejs: 3
}
]
]
}
}
]
},
// CSS Modules
{
test: /\.css$/,
exclude: /(node_modules|globals.css)/,
use: [
{ loader: MiniCssExtractPlugin.loader },
{
loader: 'css-loader',
options: {
importLoaders: 1,
modules: {
localIdentName: '[name]/[local]/[hash:base64:5]'
}
}
},
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
config: {
ctx: {
cssVarsFiles
},
path: 'frontend/postcss.config.js'
}
}
}
]
},
// Global styles
{
test: /\.css$/,
include: /(node_modules|globals.css)/,
use: [
'style-loader',
{
loader: 'css-loader'
}
]
},
// Fonts
{
test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
use: [
{
loader: 'url-loader',
options: {
limit: 10240,
mimetype: 'application/font-woff',
emitFile: false,
name: 'Content/Fonts/[name].[ext]'
}
}
]
},
{
test: /\.(ttf|eot|eot?#iefix|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
use: [
{
loader: 'file-loader',
options: {
emitFile: false,
name: 'Content/Fonts/[name].[ext]'
}
}
]
}
]
}
};
if (isProfiling) {
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
}
})
];
}
gulp.task('webpack', () => {
return webpackStream(config)
.pipe(gulp.dest('_output/UI'));
});
gulp.task('webpackWatch', () => {
config.watch = true;
return webpackStream(config, webpack)
.on('error', errorHandler)
.pipe(gulp.dest('_output/UI'))
.on('error', errorHandler)
.pipe(livereload())
.on('error', errorHandler);
});

View File

@@ -1,23 +1,32 @@
const reload = require('require-nocache')(module);
module.exports = (ctx, configPath, options) => {
const config = {
plugins: {
'postcss-mixins': {
mixinsDir: [
'frontend/src/Styles/Mixins'
]
},
'postcss-simple-vars': {
variables: () =>
ctx.options.cssVarsFiles.reduce((acc, vars) => {
return Object.assign(acc, reload(vars));
}, {})
},
'postcss-color-function': {},
'postcss-nested': {}
}
};
const cssVarsFiles = [
'./src/Styles/Variables/colors',
'./src/Styles/Variables/dimensions',
'./src/Styles/Variables/fonts',
'./src/Styles/Variables/animations',
'./src/Styles/Variables/zIndexes'
].map(require.resolve);
return config;
const mixinsFiles = [
'frontend/src/Styles/Mixins/cover.css',
'frontend/src/Styles/Mixins/linkOverlay.css',
'frontend/src/Styles/Mixins/scroller.css',
'frontend/src/Styles/Mixins/truncate.css'
];
module.exports = {
plugins: [
['postcss-mixins', {
mixinsFiles
}],
['postcss-simple-vars', {
variables: () =>
cssVarsFiles.reduce((acc, vars) => {
return Object.assign(acc, reload(vars));
}, {})
}],
'postcss-color-function',
'postcss-nested'
]
};

View File

@@ -1,130 +0,0 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import PageContent from 'Components/Page/PageContent';
import PageContentBodyConnector from 'Components/Page/PageContentBodyConnector';
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 { align, icons } from 'Helpers/Props';
import BlacklistRowConnector from './BlacklistRowConnector';
class Blacklist extends Component {
//
// Render
render() {
const {
isFetching,
isPopulated,
isAuthorFetching,
isAuthorPopulated,
error,
items,
columns,
totalRecords,
isClearingBlacklistExecuting,
onClearBlacklistPress,
...otherProps
} = this.props;
const isAllPopulated = isPopulated && isAuthorPopulated;
const isAnyFetching = isFetching || isAuthorFetching;
return (
<PageContent title="Blacklist">
<PageToolbar>
<PageToolbarSection>
<PageToolbarButton
label="Clear"
iconName={icons.CLEAR}
isSpinning={isClearingBlacklistExecuting}
onPress={onClearBlacklistPress}
/>
</PageToolbarSection>
<PageToolbarSection alignContent={align.RIGHT}>
<TableOptionsModalWrapper
{...otherProps}
columns={columns}
>
<PageToolbarButton
label="Options"
iconName={icons.TABLE}
/>
</TableOptionsModalWrapper>
</PageToolbarSection>
</PageToolbar>
<PageContentBodyConnector>
{
isAnyFetching && !isAllPopulated &&
<LoadingIndicator />
}
{
!isAnyFetching && !!error &&
<div>Unable to load blacklist</div>
}
{
isAllPopulated && !error && !items.length &&
<div>
No history blacklist
</div>
}
{
isAllPopulated && !error && !!items.length &&
<div>
<Table
columns={columns}
{...otherProps}
>
<TableBody>
{
items.map((item) => {
return (
<BlacklistRowConnector
key={item.id}
columns={columns}
{...item}
/>
);
})
}
</TableBody>
</Table>
<TablePager
totalRecords={totalRecords}
isFetching={isFetching}
{...otherProps}
/>
</div>
}
</PageContentBodyConnector>
</PageContent>
);
}
}
Blacklist.propTypes = {
isAuthorFetching: PropTypes.bool.isRequired,
isAuthorPopulated: PropTypes.bool.isRequired,
isFetching: PropTypes.bool.isRequired,
isPopulated: PropTypes.bool.isRequired,
error: PropTypes.object,
items: PropTypes.arrayOf(PropTypes.object).isRequired,
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
totalRecords: PropTypes.number,
isClearingBlacklistExecuting: PropTypes.bool.isRequired,
onClearBlacklistPress: PropTypes.func.isRequired
};
export default Blacklist;

View File

@@ -0,0 +1,242 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
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 { 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 {
//
// Lifecycle
constructor(props, context) {
super(props, context);
this.state = {
allSelected: false,
allUnselected: false,
lastToggled: null,
selectedState: {},
isConfirmRemoveModalOpen: false,
items: props.items
};
}
componentDidUpdate(prevProps) {
const {
items
} = this.props;
if (hasDifferentItems(prevProps.items, items)) {
this.setState((state) => {
return {
...removeOldSelectedState(state, getRemovedItems(prevProps.items, items)),
items
};
});
return;
}
}
//
// Control
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 });
}
//
// Render
render() {
const {
isFetching,
isPopulated,
isAuthorFetching,
isAuthorPopulated,
error,
items,
columns,
totalRecords,
isRemoving,
isClearingBlocklistExecuting,
onClearBlocklistPress,
...otherProps
} = this.props;
const isAllPopulated = isPopulated && isAuthorPopulated;
const isAnyFetching = isFetching || isAuthorFetching;
const {
allSelected,
allUnselected,
selectedState,
isConfirmRemoveModalOpen
} = this.state;
const selectedIds = this.getSelectedIds();
return (
<PageContent title={translate('Blocklist')}>
<PageToolbar>
<PageToolbarSection>
<PageToolbarButton
label={translate('RemoveSelected')}
iconName={icons.REMOVE}
isDisabled={!selectedIds.length}
isSpinning={isRemoving}
onPress={this.onRemoveSelectedPress}
/>
<PageToolbarButton
label={translate('Clear')}
iconName={icons.CLEAR}
isSpinning={isClearingBlocklistExecuting}
onPress={onClearBlocklistPress}
/>
</PageToolbarSection>
<PageToolbarSection alignContent={align.RIGHT}>
<TableOptionsModalWrapper
{...otherProps}
columns={columns}
>
<PageToolbarButton
label={translate('Options')}
iconName={icons.TABLE}
/>
</TableOptionsModalWrapper>
</PageToolbarSection>
</PageToolbar>
<PageContentBody>
{
isAnyFetching && !isAllPopulated &&
<LoadingIndicator />
}
{
!isAnyFetching && !!error &&
<div>
{translate('UnableToLoadBlocklist')}
</div>
}
{
isAllPopulated && !error && !items.length &&
<div>
{translate('NoHistoryBlocklist')}
</div>
}
{
isAllPopulated && !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>
<TablePager
totalRecords={totalRecords}
isFetching={isFetching}
{...otherProps}
/>
</div>
}
</PageContentBody>
<ConfirmModal
isOpen={isConfirmRemoveModalOpen}
kind={kinds.DANGER}
title={translate('RemoveSelected')}
message={translate('RemoveSelectedMessageText')}
confirmLabel={translate('RemoveSelected')}
onConfirm={this.onRemoveSelectedConfirmed}
onCancel={this.onConfirmRemoveModalClose}
/>
</PageContent>
);
}
}
Blocklist.propTypes = {
isAuthorFetching: PropTypes.bool.isRequired,
isAuthorPopulated: PropTypes.bool.isRequired,
isFetching: PropTypes.bool.isRequired,
isPopulated: PropTypes.bool.isRequired,
error: PropTypes.object,
items: PropTypes.arrayOf(PropTypes.object).isRequired,
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
totalRecords: PropTypes.number,
isRemoving: PropTypes.bool.isRequired,
isClearingBlocklistExecuting: PropTypes.bool.isRequired,
onRemoveSelected: PropTypes.func.isRequired,
onClearBlocklistPress: PropTypes.func.isRequired
};
export default Blocklist;

View File

@@ -4,34 +4,34 @@ import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import * as commandNames from 'Commands/commandNames';
import withCurrentPage from 'Components/withCurrentPage';
import * as blacklistActions from 'Store/Actions/blacklistActions';
import * as blocklistActions from 'Store/Actions/blocklistActions';
import { executeCommand } from 'Store/Actions/commandActions';
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
import { registerPagePopulator, unregisterPagePopulator } from 'Utilities/pagePopulator';
import Blacklist from './Blacklist';
import Blocklist from './Blocklist';
function createMapStateToProps() {
return createSelector(
(state) => state.blacklist,
(state) => state.blocklist,
(state) => state.authors,
createCommandExecutingSelector(commandNames.CLEAR_BLACKLIST),
(blacklist, authors, isClearingBlacklistExecuting) => {
createCommandExecutingSelector(commandNames.CLEAR_BLOCKLIST),
(blocklist, authors, isClearingBlocklistExecuting) => {
return {
isAuthorFetching: authors.isFetching,
isAuthorPopulated: authors.isPopulated,
isClearingBlacklistExecuting,
...blacklist
isClearingBlocklistExecuting,
...blocklist
};
}
);
}
const mapDispatchToProps = {
...blacklistActions,
...blocklistActions,
executeCommand
};
class BlacklistConnector extends Component {
class BlocklistConnector extends Component {
//
// Lifecycle
@@ -39,27 +39,27 @@ class BlacklistConnector extends Component {
componentDidMount() {
const {
useCurrentPage,
fetchBlacklist,
gotoBlacklistFirstPage
fetchBlocklist,
gotoBlocklistFirstPage
} = this.props;
registerPagePopulator(this.repopulate);
if (useCurrentPage) {
fetchBlacklist();
fetchBlocklist();
} else {
gotoBlacklistFirstPage();
gotoBlocklistFirstPage();
}
}
componentDidUpdate(prevProps) {
if (prevProps.isClearingBlacklistExecuting && !this.props.isClearingBlacklistExecuting) {
this.props.gotoBlacklistFirstPage();
if (prevProps.isClearingBlocklistExecuting && !this.props.isClearingBlocklistExecuting) {
this.props.gotoBlocklistFirstPage();
}
}
componentWillUnmount() {
this.props.clearBlacklist();
this.props.clearBlocklist();
unregisterPagePopulator(this.repopulate);
}
@@ -67,45 +67,49 @@ class BlacklistConnector extends Component {
// Control
repopulate = () => {
this.props.fetchBlacklist();
this.props.fetchBlocklist();
}
//
// Listeners
onFirstPagePress = () => {
this.props.gotoBlacklistFirstPage();
this.props.gotoBlocklistFirstPage();
}
onPreviousPagePress = () => {
this.props.gotoBlacklistPreviousPage();
this.props.gotoBlocklistPreviousPage();
}
onNextPagePress = () => {
this.props.gotoBlacklistNextPage();
this.props.gotoBlocklistNextPage();
}
onLastPagePress = () => {
this.props.gotoBlacklistLastPage();
this.props.gotoBlocklistLastPage();
}
onPageSelect = (page) => {
this.props.gotoBlacklistPage({ page });
this.props.gotoBlocklistPage({ page });
}
onRemoveSelected = (ids) => {
this.props.removeBlocklistItems({ ids });
}
onSortPress = (sortKey) => {
this.props.setBlacklistSort({ sortKey });
this.props.setBlocklistSort({ sortKey });
}
onTableOptionChange = (payload) => {
this.props.setBlacklistTableOption(payload);
this.props.setBlocklistTableOption(payload);
if (payload.pageSize) {
this.props.gotoBlacklistFirstPage();
this.props.gotoBlocklistFirstPage();
}
}
onClearBlacklistPress = () => {
this.props.executeCommand({ name: commandNames.CLEAR_BLACKLIST });
onClearBlocklistPress = () => {
this.props.executeCommand({ name: commandNames.CLEAR_BLOCKLIST });
}
//
@@ -113,37 +117,39 @@ class BlacklistConnector extends Component {
render() {
return (
<Blacklist
<Blocklist
onFirstPagePress={this.onFirstPagePress}
onPreviousPagePress={this.onPreviousPagePress}
onNextPagePress={this.onNextPagePress}
onLastPagePress={this.onLastPagePress}
onPageSelect={this.onPageSelect}
onRemoveSelected={this.onRemoveSelected}
onSortPress={this.onSortPress}
onTableOptionChange={this.onTableOptionChange}
onClearBlacklistPress={this.onClearBlacklistPress}
onClearBlocklistPress={this.onClearBlocklistPress}
{...this.props}
/>
);
}
}
BlacklistConnector.propTypes = {
BlocklistConnector.propTypes = {
useCurrentPage: PropTypes.bool.isRequired,
isClearingBlacklistExecuting: PropTypes.bool.isRequired,
isClearingBlocklistExecuting: PropTypes.bool.isRequired,
items: PropTypes.arrayOf(PropTypes.object).isRequired,
fetchBlacklist: PropTypes.func.isRequired,
gotoBlacklistFirstPage: PropTypes.func.isRequired,
gotoBlacklistPreviousPage: PropTypes.func.isRequired,
gotoBlacklistNextPage: PropTypes.func.isRequired,
gotoBlacklistLastPage: PropTypes.func.isRequired,
gotoBlacklistPage: PropTypes.func.isRequired,
setBlacklistSort: PropTypes.func.isRequired,
setBlacklistTableOption: PropTypes.func.isRequired,
clearBlacklist: PropTypes.func.isRequired,
fetchBlocklist: PropTypes.func.isRequired,
gotoBlocklistFirstPage: PropTypes.func.isRequired,
gotoBlocklistPreviousPage: PropTypes.func.isRequired,
gotoBlocklistNextPage: PropTypes.func.isRequired,
gotoBlocklistLastPage: PropTypes.func.isRequired,
gotoBlocklistPage: PropTypes.func.isRequired,
removeBlocklistItems: PropTypes.func.isRequired,
setBlocklistSort: PropTypes.func.isRequired,
setBlocklistTableOption: PropTypes.func.isRequired,
clearBlocklist: PropTypes.func.isRequired,
executeCommand: PropTypes.func.isRequired
};
export default withCurrentPage(
connect(createMapStateToProps, mapDispatchToProps)(BlacklistConnector)
connect(createMapStateToProps, mapDispatchToProps)(BlocklistConnector)
);

View File

@@ -8,8 +8,9 @@ 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 BlacklistDetailsModal extends Component {
class BlocklistDetailsModal extends Component {
//
// Render
@@ -39,19 +40,19 @@ class BlacklistDetailsModal 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 BlacklistDetailsModal extends Component {
{
!!message &&
<DescriptionListItem
title="Message"
title={translate('Message')}
data={message}
/>
}
@@ -77,7 +78,7 @@ class BlacklistDetailsModal extends Component {
}
}
BlacklistDetailsModal.propTypes = {
BlocklistDetailsModal.propTypes = {
isOpen: PropTypes.bool.isRequired,
sourceTitle: PropTypes.string.isRequired,
protocol: PropTypes.string.isRequired,
@@ -86,4 +87,4 @@ BlacklistDetailsModal.propTypes = {
onModalClose: PropTypes.func.isRequired
};
export default BlacklistDetailsModal;
export default BlocklistDetailsModal;

View File

@@ -5,12 +5,14 @@ import BookQuality from 'Book/BookQuality';
import IconButton from 'Components/Link/IconButton';
import RelativeDateCellConnector from 'Components/Table/Cells/RelativeDateCellConnector';
import TableRowCell from 'Components/Table/Cells/TableRowCell';
import TableSelectCell from 'Components/Table/Cells/TableSelectCell';
import TableRow from 'Components/Table/TableRow';
import { icons, kinds } from 'Helpers/Props';
import BlacklistDetailsModal from './BlacklistDetailsModal';
import styles from './BlacklistRow.css';
import translate from 'Utilities/String/translate';
import BlocklistDetailsModal from './BlocklistDetailsModal';
import styles from './BlocklistRow.css';
class BlacklistRow extends Component {
class BlocklistRow extends Component {
//
// Lifecycle
@@ -39,6 +41,7 @@ class BlacklistRow extends Component {
render() {
const {
id,
author,
sourceTitle,
quality,
@@ -46,7 +49,9 @@ class BlacklistRow extends Component {
protocol,
indexer,
message,
isSelected,
columns,
onSelectedChange,
onRemovePress
} = this.props;
@@ -56,6 +61,12 @@ class BlacklistRow extends Component {
return (
<TableRow>
<TableSelectCell
id={id}
isSelected={isSelected}
onSelectedChange={onSelectedChange}
/>
{
columns.map((column) => {
const {
@@ -67,7 +78,7 @@ class BlacklistRow extends Component {
return null;
}
if (name === 'authors.sortName') {
if (name === 'authorMetadata.sortName') {
return (
<TableRowCell key={name}>
<AuthorNameLink
@@ -131,7 +142,7 @@ class BlacklistRow extends Component {
/>
<IconButton
title="Remove from blacklist"
title={translate('RemoveFromBlocklist')}
name={icons.REMOVE}
kind={kinds.DANGER}
onPress={onRemovePress}
@@ -144,7 +155,7 @@ class BlacklistRow extends Component {
})
}
<BlacklistDetailsModal
<BlocklistDetailsModal
isOpen={this.state.isDetailsModalOpen}
sourceTitle={sourceTitle}
protocol={protocol}
@@ -158,7 +169,7 @@ class BlacklistRow extends Component {
}
BlacklistRow.propTypes = {
BlocklistRow.propTypes = {
id: PropTypes.number.isRequired,
author: PropTypes.object.isRequired,
sourceTitle: PropTypes.string.isRequired,
@@ -167,8 +178,10 @@ BlacklistRow.propTypes = {
protocol: PropTypes.string.isRequired,
indexer: PropTypes.string,
message: PropTypes.string,
isSelected: PropTypes.bool.isRequired,
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
onSelectedChange: PropTypes.func.isRequired,
onRemovePress: PropTypes.func.isRequired
};
export default BlacklistRow;
export default BlocklistRow;

View File

@@ -1,8 +1,8 @@
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { removeFromBlacklist } from 'Store/Actions/blacklistActions';
import { removeBlocklistItem } from 'Store/Actions/blocklistActions';
import createAuthorSelector from 'Store/Selectors/createAuthorSelector';
import BlacklistRow from './BlacklistRow';
import BlocklistRow from './BlocklistRow';
function createMapStateToProps() {
return createSelector(
@@ -18,9 +18,9 @@ function createMapStateToProps() {
function createMapDispatchToProps(dispatch, props) {
return {
onRemovePress() {
dispatch(removeFromBlacklist({ id: props.id }));
dispatch(removeBlocklistItem({ id: props.id }));
}
};
}
export default connect(createMapStateToProps, createMapDispatchToProps)(BlacklistRow);
export default connect(createMapStateToProps, createMapDispatchToProps)(BlocklistRow);

View File

@@ -9,6 +9,7 @@ import Link from 'Components/Link/Link';
import { icons } from 'Helpers/Props';
import formatDateTime from 'Utilities/Date/formatDateTime';
import formatAge from 'Utilities/Number/formatAge';
import translate from 'Utilities/String/translate';
import styles from './HistoryDetails.css';
function getDetailedList(statusMessages) {
@@ -77,14 +78,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}
/>
}
@@ -93,7 +94,7 @@ function HistoryDetails(props) {
!!releaseGroup &&
<DescriptionListItem
descriptionClassName={styles.description}
title="Release Group"
title={translate('ReleaseGroup')}
data={releaseGroup}
/>
}
@@ -114,7 +115,7 @@ function HistoryDetails(props) {
{
!!downloadClient &&
<DescriptionListItem
title="Download Client"
title={translate('DownloadClient')}
data={downloadClient}
/>
}
@@ -122,7 +123,7 @@ function HistoryDetails(props) {
{
!!downloadId &&
<DescriptionListItem
title="Grab ID"
title={translate('GrabID')}
data={downloadId}
/>
}
@@ -130,7 +131,7 @@ function HistoryDetails(props) {
{
!!indexer &&
<DescriptionListItem
title="Age (when grabbed)"
title={translate('AgeWhenGrabbed')}
data={formatAge(age, ageHours, ageMinutes)}
/>
}
@@ -138,7 +139,7 @@ function HistoryDetails(props) {
{
!!publishedDate &&
<DescriptionListItem
title="Published Date"
title={translate('PublishedDate')}
data={formatDateTime(publishedDate, shortDateFormat, timeFormat, { includeSeconds: true })}
/>
}
@@ -155,14 +156,14 @@ function HistoryDetails(props) {
<DescriptionList>
<DescriptionListItem
descriptionClassName={styles.description}
title="Name"
title={translate('Name')}
data={sourceTitle}
/>
{
!!message &&
<DescriptionListItem
title="Message"
title={translate('Message')}
data={message}
/>
}
@@ -180,7 +181,7 @@ function HistoryDetails(props) {
<DescriptionList>
<DescriptionListItem
descriptionClassName={styles.description}
title="Name"
title={translate('Name')}
data={sourceTitle}
/>
@@ -188,7 +189,7 @@ function HistoryDetails(props) {
!!droppedPath &&
<DescriptionListItem
descriptionClassName={styles.description}
title="Source"
title={translate('Source')}
data={droppedPath}
/>
}
@@ -197,7 +198,7 @@ function HistoryDetails(props) {
!!importedPath &&
<DescriptionListItem
descriptionClassName={styles.description}
title="Imported To"
title={translate('ImportedTo')}
data={importedPath}
/>
}
@@ -214,13 +215,13 @@ function HistoryDetails(props) {
switch (reason) {
case 'Manual':
reasonMessage = 'File was deleted by via UI';
reasonMessage = translate('FileWasDeletedByViaUI');
break;
case 'MissingFromDisk':
reasonMessage = 'Readarr was unable to find the file on disk so it was removed';
reasonMessage = translate('MissingFromDisk');
break;
case 'Upgrade':
reasonMessage = 'File was deleted to import an upgrade';
reasonMessage = translate('FileWasDeletedByUpgrade');
break;
default:
reasonMessage = '';
@@ -229,12 +230,12 @@ function HistoryDetails(props) {
return (
<DescriptionList>
<DescriptionListItem
title="Name"
title={translate('Name')}
data={sourceTitle}
/>
<DescriptionListItem
title="Reason"
title={translate('Reason')}
data={reasonMessage}
/>
</DescriptionList>
@@ -250,12 +251,12 @@ function HistoryDetails(props) {
return (
<DescriptionList>
<DescriptionListItem
title="Source Path"
title={translate('SourcePath')}
data={sourcePath}
/>
<DescriptionListItem
title="Destination Path"
title={translate('DestinationPath')}
data={path}
/>
</DescriptionList>
@@ -271,7 +272,7 @@ function HistoryDetails(props) {
return (
<DescriptionList>
<DescriptionListItem
title="Path"
title={translate('Path')}
data={sourceTitle}
/>
{
@@ -286,7 +287,7 @@ function HistoryDetails(props) {
})
}
<DescriptionListItem
title="Existing tags scrubbed"
title={translate('ExistingTagsScrubbed')}
data={tagsScrubbed === 'True' ? <Icon name={icons.CHECK} /> : <Icon name={icons.REMOVE} />}
/>
</DescriptionList>
@@ -301,14 +302,14 @@ function HistoryDetails(props) {
return (
<DescriptionList>
<DescriptionListItem
title="Name"
title={translate('Name')}
data={sourceTitle}
/>
{
!!statusMessages &&
<DescriptionListItem
title="Import failures"
title={translate('ImportFailures')}
data={getDetailedList(JSON.parse(statusMessages))}
/>
}
@@ -332,14 +333,14 @@ function HistoryDetails(props) {
return (
<DescriptionList>
<DescriptionListItem
title="Name"
title={translate('Name')}
data={sourceTitle}
/>
{
!!indexer &&
<DescriptionListItem
title="Indexer"
title={translate('Indexer')}
data={indexer}
/>
}
@@ -347,7 +348,7 @@ function HistoryDetails(props) {
{
!!releaseGroup &&
<DescriptionListItem
title="Release Group"
title={translate('ReleaseGroup')}
data={releaseGroup}
/>
}
@@ -368,7 +369,7 @@ function HistoryDetails(props) {
{
!!downloadClient &&
<DescriptionListItem
title="Download Client"
title={translate('DownloadClient')}
data={downloadClient}
/>
}
@@ -376,7 +377,7 @@ function HistoryDetails(props) {
{
!!downloadId &&
<DescriptionListItem
title="Grab ID"
title={translate('GrabID')}
data={downloadId}
/>
}
@@ -384,7 +385,7 @@ function HistoryDetails(props) {
{
!!indexer &&
<DescriptionListItem
title="Age (when grabbed)"
title={translate('AgeWhenGrabbed')}
data={formatAge(age, ageHours, ageMinutes)}
/>
}
@@ -392,7 +393,7 @@ function HistoryDetails(props) {
{
!!publishedDate &&
<DescriptionListItem
title="Published Date"
title={translate('PublishedDate')}
data={formatDateTime(publishedDate, shortDateFormat, timeFormat, { includeSeconds: true })}
/>
}
@@ -409,14 +410,14 @@ function HistoryDetails(props) {
<DescriptionList>
<DescriptionListItem
descriptionClassName={styles.description}
title="Name"
title={translate('Name')}
data={sourceTitle}
/>
{
!!message &&
<DescriptionListItem
title="Message"
title={translate('Message')}
data={message}
/>
}
@@ -428,7 +429,7 @@ function HistoryDetails(props) {
<DescriptionList>
<DescriptionListItem
descriptionClassName={styles.description}
title="Name"
title={translate('Name')}
data={sourceTitle}
/>
</DescriptionList>

View File

@@ -3,7 +3,7 @@ import React, { Component } from 'react';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import FilterMenu from 'Components/Menu/FilterMenu';
import PageContent from 'Components/Page/PageContent';
import PageContentBodyConnector from 'Components/Page/PageContentBodyConnector';
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';
@@ -12,32 +12,11 @@ import TableBody from 'Components/Table/TableBody';
import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper';
import TablePager from 'Components/Table/TablePager';
import { align, icons } from 'Helpers/Props';
import hasDifferentItems from 'Utilities/Object/hasDifferentItems';
import translate from 'Utilities/String/translate';
import HistoryRowConnector from './HistoryRowConnector';
class History extends Component {
//
// Lifecycle
shouldComponentUpdate(nextProps) {
// Don't update when fetching has completed if items have changed,
// before books start fetching or when books start fetching.
if (
(
this.props.isFetching &&
nextProps.isPopulated &&
hasDifferentItems(this.props.items, nextProps.items)
) ||
(!this.props.isBooksFetching && nextProps.isBooksFetching)
) {
return false;
}
return true;
}
//
// Render
@@ -66,11 +45,11 @@ class History extends Component {
const hasError = error || booksError;
return (
<PageContent title="History">
<PageContent title={translate('History')}>
<PageToolbar>
<PageToolbarSection>
<PageToolbarButton
label="Refresh"
label={translate('Refresh')}
iconName={icons.REFRESH}
isSpinning={isFetching}
onPress={onFirstPagePress}
@@ -83,7 +62,7 @@ class History extends Component {
columns={columns}
>
<PageToolbarButton
label="Options"
label={translate('Options')}
iconName={icons.TABLE}
/>
</TableOptionsModalWrapper>
@@ -98,7 +77,7 @@ class History extends Component {
</PageToolbarSection>
</PageToolbar>
<PageContentBodyConnector>
<PageContentBody>
{
isFetchingAny && !isAllPopulated &&
<LoadingIndicator />
@@ -106,7 +85,9 @@ class History extends Component {
{
!isFetchingAny && hasError &&
<div>Unable to load history</div>
<div>
{translate('UnableToLoadHistory')}
</div>
}
{
@@ -149,7 +130,7 @@ class History extends Component {
/>
</div>
}
</PageContentBodyConnector>
</PageContentBody>
</PageContent>
);
}

View File

@@ -3,10 +3,7 @@ import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import withCurrentPage from 'Components/withCurrentPage';
import { clearBooks, fetchBooks } from 'Store/Actions/bookActions';
import * as historyActions from 'Store/Actions/historyActions';
import hasDifferentItems from 'Utilities/Object/hasDifferentItems';
import selectUniqueIds from 'Utilities/Object/selectUniqueIds';
import { registerPagePopulator, unregisterPagePopulator } from 'Utilities/pagePopulator';
import History from './History';
@@ -29,9 +26,7 @@ function createMapStateToProps() {
}
const mapDispatchToProps = {
...historyActions,
fetchBooks,
clearBooks
...historyActions
};
class HistoryConnector extends Component {
@@ -55,21 +50,9 @@ class HistoryConnector extends Component {
}
}
componentDidUpdate(prevProps) {
if (hasDifferentItems(prevProps.items, this.props.items)) {
const bookIds = selectUniqueIds(this.props.items, 'bookId');
if (bookIds.length) {
this.props.fetchBooks({ bookIds });
} else {
this.props.clearBooks();
}
}
}
componentWillUnmount() {
unregisterPagePopulator(this.repopulate);
this.props.clearHistory();
this.props.clearBooks();
}
//
@@ -150,9 +133,7 @@ HistoryConnector.propTypes = {
setHistorySort: PropTypes.func.isRequired,
setHistoryFilter: PropTypes.func.isRequired,
setHistoryTableOption: PropTypes.func.isRequired,
clearHistory: PropTypes.func.isRequired,
fetchBooks: PropTypes.func.isRequired,
clearBooks: PropTypes.func.isRequired
clearHistory: PropTypes.func.isRequired
};
export default withCurrentPage(

View File

@@ -23,8 +23,6 @@ function getIconName(eventType) {
return icons.RETAG;
case 'bookImportIncomplete':
return icons.DOWNLOADED;
case 'downloadImported':
return icons.DOWNLOADED;
case 'downloadIgnored':
return icons.IGNORE;
default:
@@ -61,8 +59,6 @@ function getTooltip(eventType, data) {
return 'Book file tags updated';
case 'bookImportIncomplete':
return 'Files downloaded but not all could be imported';
case 'downloadImported':
return 'Download completed and successfully imported';
case 'downloadIgnored':
return 'Book Download Ignored';
default:

View File

@@ -93,7 +93,7 @@ class HistoryRow extends Component {
);
}
if (name === 'authors.sortName') {
if (name === 'authorMetadata.sortName') {
return (
<TableRowCell key={name}>
<AuthorNameLink

View File

@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import PageContent from 'Components/Page/PageContent';
import PageContentBodyConnector from 'Components/Page/PageContentBodyConnector';
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';
@@ -13,7 +13,9 @@ import TableBody from 'Components/Table/TableBody';
import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper';
import TablePager from 'Components/Table/TablePager';
import { align, icons } 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';
@@ -30,30 +32,21 @@ class Queue extends Component {
constructor(props, context) {
super(props, context);
this._shouldBlockRefresh = false;
this.state = {
allSelected: false,
allUnselected: false,
lastToggled: null,
selectedState: {},
isPendingSelected: false,
isConfirmRemoveModalOpen: false
isConfirmRemoveModalOpen: false,
items: props.items
};
}
shouldComponentUpdate(nextProps) {
// Don't update when fetching has completed if items have changed,
// before books start fetching or when books start fetching.
if (
this.props.isFetching &&
nextProps.isPopulated &&
hasDifferentItems(this.props.items, nextProps.items) &&
nextProps.items.some((e) => e.bookId)
) {
return false;
}
if (!this.props.isBooksFetching && nextProps.isBooksFetching) {
shouldComponentUpdate() {
if (this._shouldBlockRefresh) {
return false;
}
@@ -61,9 +54,22 @@ class Queue extends Component {
}
componentDidUpdate(prevProps) {
if (hasDifferentItems(prevProps.items, this.props.items)) {
const {
items,
isFetching,
isBooksFetching
} = this.props;
if (
(!isBooksFetching && prevProps.isBooksFetching) ||
(!isFetching && prevProps.isFetching) ||
(hasDifferentItems(prevProps.items, items) && !items.some((e) => e.bookId))
) {
this.setState((state) => {
return removeOldSelectedState(state, prevProps.items);
return {
...removeOldSelectedState(state, getRemovedItems(prevProps.items, items)),
items
};
});
return;
@@ -89,6 +95,10 @@ class Queue extends Component {
//
// Listeners
onQueueRowModalOpenOrClose = (isOpen) => {
this._shouldBlockRefresh = isOpen;
}
onSelectAllChange = ({ value }) => {
this.setState(selectAll(this.state.selectedState, value));
}
@@ -104,15 +114,19 @@ class Queue extends Component {
}
onRemoveSelectedPress = () => {
this.setState({ isConfirmRemoveModalOpen: true });
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 });
}
@@ -124,7 +138,6 @@ class Queue extends Component {
isFetching,
isPopulated,
error,
items,
isAuthorFetching,
isAuthorPopulated,
isBooksFetching,
@@ -144,7 +157,8 @@ class Queue extends Component {
allUnselected,
selectedState,
isConfirmRemoveModalOpen,
isPendingSelected
isPendingSelected,
items
} = this.state;
const isRefreshing = isFetching || isAuthorFetching || isBooksFetching || isRefreshMonitoredDownloadsExecuting;
@@ -155,11 +169,11 @@ class Queue extends Component {
const disableSelectedActions = selectedCount === 0;
return (
<PageContent title="Queue">
<PageContent title={translate('Queue')}>
<PageToolbar>
<PageToolbarSection>
<PageToolbarButton
label="Refresh"
label={translate('Refresh')}
iconName={icons.REFRESH}
isSpinning={isRefreshing}
onPress={onRefreshPress}
@@ -168,7 +182,7 @@ class Queue extends Component {
<PageToolbarSeparator />
<PageToolbarButton
label="Grab Selected"
label={translate('GrabSelected')}
iconName={icons.DOWNLOAD}
isDisabled={disableSelectedActions || !isPendingSelected}
isSpinning={isGrabbing}
@@ -176,7 +190,7 @@ class Queue extends Component {
/>
<PageToolbarButton
label="Remove Selected"
label={translate('RemoveSelected')}
iconName={icons.REMOVE}
isDisabled={disableSelectedActions}
isSpinning={isRemoving}
@@ -193,14 +207,14 @@ class Queue extends Component {
optionsComponent={QueueOptionsConnector}
>
<PageToolbarButton
label="Options"
label={translate('Options')}
iconName={icons.TABLE}
/>
</TableOptionsModalWrapper>
</PageToolbarSection>
</PageToolbar>
<PageContentBodyConnector>
<PageContentBody>
{
isRefreshing && !isAllPopulated &&
<LoadingIndicator />
@@ -209,14 +223,14 @@ class Queue extends Component {
{
!isRefreshing && hasError &&
<div>
Failed to load Queue
{translate('FailedToLoadQueue')}
</div>
}
{
isPopulated && !hasError && !items.length &&
isAllPopulated && !hasError && !items.length &&
<div>
Queue is empty
{translate('QueueIsEmpty')}
</div>
}
@@ -243,6 +257,7 @@ class Queue extends Component {
columns={columns}
{...item}
onSelectedChange={this.onSelectedChange}
onQueueRowModalOpenOrClose={this.onQueueRowModalOpenOrClose}
/>
);
})
@@ -257,7 +272,7 @@ class Queue extends Component {
/>
</div>
}
</PageContentBodyConnector>
</PageContentBody>
<RemoveQueueItemsModal
isOpen={isConfirmRemoveModalOpen}
@@ -269,6 +284,17 @@ class Queue extends Component {
return !!(item && item.authorId && item.bookId);
})
)}
allPending={isConfirmRemoveModalOpen && (
selectedIds.every((id) => {
const item = items.find((i) => i.id === id);
if (!item) {
return false;
}
return item.status === 'delay' || item.status === 'downloadClientUnavailable';
})
)}
onRemovePress={this.onRemoveSelectedConfirmed}
onModalClose={this.onConfirmRemoveModalClose}
/>

View File

@@ -4,12 +4,9 @@ import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import * as commandNames from 'Commands/commandNames';
import withCurrentPage from 'Components/withCurrentPage';
import { clearBooks, fetchBooks } from 'Store/Actions/bookActions';
import { executeCommand } from 'Store/Actions/commandActions';
import * as queueActions from 'Store/Actions/queueActions';
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
import hasDifferentItems from 'Utilities/Object/hasDifferentItems';
import selectUniqueIds from 'Utilities/Object/selectUniqueIds';
import { registerPagePopulator, unregisterPagePopulator } from 'Utilities/pagePopulator';
import Queue from './Queue';
@@ -37,8 +34,6 @@ function createMapStateToProps() {
const mapDispatchToProps = {
...queueActions,
fetchBooks,
clearBooks,
executeCommand
};
@@ -51,6 +46,7 @@ class QueueConnector extends Component {
const {
useCurrentPage,
fetchQueue,
fetchQueueStatus,
gotoQueueFirstPage
} = this.props;
@@ -61,19 +57,11 @@ class QueueConnector extends Component {
} else {
gotoQueueFirstPage();
}
fetchQueueStatus();
}
componentDidUpdate(prevProps) {
if (hasDifferentItems(prevProps.items, this.props.items)) {
const bookIds = selectUniqueIds(this.props.items, 'bookId');
if (bookIds.length) {
this.props.fetchBooks({ bookIds });
} else {
this.props.clearBooks();
}
}
if (
this.props.includeUnknownAuthorItems !==
prevProps.includeUnknownAuthorItems
@@ -84,8 +72,6 @@ class QueueConnector extends Component {
componentWillUnmount() {
unregisterPagePopulator(this.repopulate);
this.props.clearQueue();
this.props.clearBooks();
}
//
@@ -171,6 +157,7 @@ QueueConnector.propTypes = {
items: PropTypes.arrayOf(PropTypes.object).isRequired,
includeUnknownAuthorItems: PropTypes.bool.isRequired,
fetchQueue: PropTypes.func.isRequired,
fetchQueueStatus: PropTypes.func.isRequired,
gotoQueueFirstPage: PropTypes.func.isRequired,
gotoQueuePreviousPage: PropTypes.func.isRequired,
gotoQueueNextPage: PropTypes.func.isRequired,
@@ -181,8 +168,6 @@ QueueConnector.propTypes = {
clearQueue: PropTypes.func.isRequired,
grabQueueItems: PropTypes.func.isRequired,
removeQueueItems: PropTypes.func.isRequired,
fetchBooks: PropTypes.func.isRequired,
clearBooks: PropTypes.func.isRequired,
executeCommand: PropTypes.func.isRequired
};

View File

@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
import React from 'react';
import Icon from 'Components/Icon';
import { icons, kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
function QueueDetails(props) {
const {
@@ -23,7 +24,7 @@ function QueueDetails(props) {
return (
<Icon
name={icons.PENDING}
title={`Release will be processed ${moment(estimatedCompletionTime).fromNow()}`}
title={translate('ReleaseWillBeProcessedInterp', [moment(estimatedCompletionTime).fromNow()])}
/>
);
}
@@ -34,7 +35,7 @@ function QueueDetails(props) {
<Icon
name={icons.DOWNLOAD}
kind={kinds.DANGER}
title={`Import failed: ${errorMessage}`}
title={translate('ImportFailedInterp', [errorMessage])}
/>
);
}
@@ -47,7 +48,7 @@ function QueueDetails(props) {
<Icon
name={icons.DOWNLOADING}
kind={kinds.DANGER}
title={`Download failed: ${errorMessage}`}
title={translate('DownloadFailedInterp', [errorMessage])}
/>
);
}
@@ -57,7 +58,7 @@ function QueueDetails(props) {
<Icon
name={icons.DOWNLOADING}
kind={kinds.DANGER}
title="Download failed: check download client for more details"
title={translate('DownloadFailedCheckDownloadClientForMoreDetails')}
/>
);
}
@@ -67,7 +68,7 @@ function QueueDetails(props) {
<Icon
name={icons.DOWNLOADING}
kind={kinds.WARNING}
title="Download warning: check download client for more details"
title={translate('DownloadWarningCheckDownloadClientForMoreDetails')}
/>
);
}
@@ -76,7 +77,7 @@ function QueueDetails(props) {
return (
<Icon
name={icons.DOWNLOADING}
title={`Book is downloading - ${progress.toFixed(1)}% ${title}`}
title={translate('BookIsDownloadingInterp', [progress.toFixed(1), title])}
/>
);
}

View File

@@ -4,6 +4,7 @@ import FormGroup from 'Components/Form/FormGroup';
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 {
@@ -54,13 +55,15 @@ class QueueOptions extends Component {
return (
<Fragment>
<FormGroup>
<FormLabel>Show Unknown Author Items</FormLabel>
<FormLabel>
{translate('ShowUnknownAuthorItems')}
</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="includeUnknownAuthorItems"
value={includeUnknownAuthorItems}
helpText="Show items without a author in the queue, this could include removed authors, movies or anything else in Readarr's category"
helpText={translate('IncludeUnknownAuthorItemsHelpText')}
onChange={this.onOptionChange}
/>
</FormGroup>

View File

@@ -15,6 +15,8 @@ import TableRow from 'Components/Table/TableRow';
import Popover from 'Components/Tooltip/Popover';
import { icons, kinds, tooltipPositions } from 'Helpers/Props';
import InteractiveImportModal from 'InteractiveImport/InteractiveImportModal';
import formatBytes from 'Utilities/Number/formatBytes';
import translate from 'Utilities/String/translate';
import QueueStatusCell from './QueueStatusCell';
import RemoveQueueItemModal from './RemoveQueueItemModal';
import TimeleftCell from './TimeleftCell';
@@ -41,20 +43,33 @@ class QueueRow extends Component {
this.setState({ isRemoveQueueItemModalOpen: true });
}
onRemoveQueueItemModalConfirmed = (blacklist, skipredownload) => {
this.props.onRemoveQueueItemPress(blacklist, skipredownload);
onRemoveQueueItemModalConfirmed = (blocklist, skipredownload) => {
const {
onRemoveQueueItemPress,
onQueueRowModalOpenOrClose
} = this.props;
onQueueRowModalOpenOrClose(false);
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 });
}
@@ -137,7 +152,7 @@ class QueueRow extends Component {
);
}
if (name === 'authors.sortName') {
if (name === 'authorMetadata.sortName') {
return (
<TableRowCell key={name}>
{
@@ -229,6 +244,12 @@ class QueueRow extends Component {
);
}
if (name === 'size') {
return (
<TableRowCell key={name}>{formatBytes(size)}</TableRowCell>
);
}
if (name === 'outputPath') {
return (
<TableRowCell key={name}>
@@ -285,7 +306,7 @@ class QueueRow extends Component {
kind={kinds.DANGER}
/>
}
title="Manual Download"
title={translate('ManualDownload')}
body="This release failed parsing checks and was manually downloaded from an interactive search. Import is likely to fail."
position={tooltipPositions.LEFT}
/>
@@ -310,7 +331,7 @@ class QueueRow extends Component {
}
<SpinnerIconButton
title="Remove from queue"
title={translate('RemoveFromQueue')}
name={icons.REMOVE}
isSpinning={isRemoving}
onPress={this.onRemoveQueueItemPress}
@@ -335,7 +356,8 @@ class QueueRow extends Component {
<RemoveQueueItemModal
isOpen={isRemoveQueueItemModalOpen}
sourceTitle={title}
canIgnore={!!(author && book)}
canIgnore={!!author}
isPending={isPending}
onRemovePress={this.onRemoveQueueItemModalConfirmed}
onModalClose={this.onRemoveQueueItemModalClose}
/>
@@ -376,7 +398,8 @@ QueueRow.propTypes = {
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
onSelectedChange: PropTypes.func.isRequired,
onGrabPress: PropTypes.func.isRequired,
onRemoveQueueItemPress: PropTypes.func.isRequired
onRemoveQueueItemPress: PropTypes.func.isRequired,
onQueueRowModalOpenOrClose: PropTypes.func.isRequired
};
QueueRow.defaultProps = {

View File

@@ -4,6 +4,7 @@ import Icon from 'Components/Icon';
import TableRowCell from 'Components/Table/Cells/TableRowCell';
import Popover from 'Components/Tooltip/Popover';
import { icons, kinds, tooltipPositions } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import styles from './QueueStatusCell.css';
function getDetailedPopoverBody(statusMessages) {
@@ -49,11 +50,7 @@ function QueueStatusCell(props) {
// status === 'downloading'
let iconName = icons.DOWNLOADING;
let iconKind = kinds.DEFAULT;
let title = 'Downloading';
if (hasWarning) {
iconKind = kinds.WARNING;
}
let title = translate('Title');
if (status === 'paused') {
iconName = icons.PAUSED;
@@ -71,17 +68,24 @@ function QueueStatusCell(props) {
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';

View File

@@ -10,6 +10,7 @@ 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,7 @@ class RemoveQueueItemModal extends Component {
this.state = {
remove: true,
blacklist: false,
blocklist: false,
skipredownload: false
};
}
@@ -32,7 +33,7 @@ class RemoveQueueItemModal extends Component {
resetState = function() {
this.setState({
remove: true,
blacklist: false,
blocklist: false,
skipredownload: false
});
}
@@ -44,8 +45,8 @@ class RemoveQueueItemModal extends Component {
this.setState({ remove: value });
}
onBlacklistChange = ({ value }) => {
this.setState({ blacklist: value });
onBlocklistChange = ({ value }) => {
this.setState({ blocklist: value });
}
onSkipReDownloadChange = ({ value }) => {
@@ -71,10 +72,11 @@ class RemoveQueueItemModal extends Component {
const {
isOpen,
sourceTitle,
canIgnore
canIgnore,
isPending
} = this.props;
const { remove, blacklist, skipredownload } = this.state;
const { remove, blocklist, skipredownload } = this.state;
return (
<Modal
@@ -94,40 +96,50 @@ class RemoveQueueItemModal extends Component {
Are you sure you want to remove '{sourceTitle}' from the queue?
</div>
{
isPending ?
null :
<FormGroup>
<FormLabel>
{translate('RemoveFromDownloadClient')}
</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="remove"
value={remove}
helpTextWarning={translate('RemoveHelpTextWarning')}
isDisabled={!canIgnore}
onChange={this.onRemoveChange}
/>
</FormGroup>
}
<FormGroup>
<FormLabel>Remove From Download Client</FormLabel>
<FormLabel>
{translate('BlocklistRelease')}
</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="remove"
value={remove}
helpTextWarning="Removing will remove the download and the file(s) from the download client."
isDisabled={!canIgnore}
onChange={this.onRemoveChange}
/>
</FormGroup>
<FormGroup>
<FormLabel>Blacklist Release</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="blacklist"
value={blacklist}
helpText="Prevents Readarr from automatically grabbing this release again"
onChange={this.onBlacklistChange}
name="blocklist"
value={blocklist}
helpText={translate('BlocklistHelpText')}
onChange={this.onBlocklistChange}
/>
</FormGroup>
{
blacklist &&
blocklist &&
<FormGroup>
<FormLabel>Skip Redownload</FormLabel>
<FormLabel>
{translate('SkipRedownload')}
</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="skipredownload"
value={skipredownload}
helpText="Prevents Readarr from trying download an alternative release for this item"
helpText={translate('SkipredownloadHelpText')}
onChange={this.onSkipReDownloadChange}
/>
</FormGroup>
@@ -157,6 +169,7 @@ RemoveQueueItemModal.propTypes = {
isOpen: PropTypes.bool.isRequired,
sourceTitle: PropTypes.string.isRequired,
canIgnore: PropTypes.bool.isRequired,
isPending: PropTypes.bool.isRequired,
onRemovePress: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired
};

View File

@@ -10,6 +10,7 @@ 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,7 +23,7 @@ class RemoveQueueItemsModal extends Component {
this.state = {
remove: true,
blacklist: false,
blocklist: false,
skipredownload: false
};
}
@@ -33,7 +34,7 @@ class RemoveQueueItemsModal extends Component {
resetState = function() {
this.setState({
remove: true,
blacklist: false,
blocklist: false,
skipredownload: false
});
}
@@ -45,8 +46,8 @@ class RemoveQueueItemsModal extends Component {
this.setState({ remove: value });
}
onBlacklistChange = ({ value }) => {
this.setState({ blacklist: value });
onBlocklistChange = ({ value }) => {
this.setState({ blocklist: value });
}
onSkipReDownloadChange = ({ value }) => {
@@ -72,10 +73,11 @@ class RemoveQueueItemsModal extends Component {
const {
isOpen,
selectedCount,
canIgnore
canIgnore,
allPending
} = this.props;
const { remove, blacklist, skipredownload } = this.state;
const { remove, blocklist, skipredownload } = this.state;
return (
<Modal
@@ -95,42 +97,50 @@ class RemoveQueueItemsModal extends Component {
Are you sure you want to remove {selectedCount} item{selectedCount > 1 ? 's' : ''} from the queue?
</div>
<FormGroup>
<FormLabel>Remove From Download Client</FormLabel>
{
allPending ?
null :
<FormGroup>
<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."
isDisabled={!canIgnore}
onChange={this.onRemoveChange}
/>
</FormGroup>
<FormInputGroup
type={inputTypes.CHECK}
name="remove"
value={remove}
helpTextWarning={translate('RemoveHelpTextWarning')}
isDisabled={!canIgnore}
onChange={this.onRemoveChange}
/>
</FormGroup>
}
<FormGroup>
<FormLabel>
Blacklist Release{selectedCount > 1 ? 's' : ''}
Add Release{selectedCount > 1 ? 's' : ''} To Blocklist
</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="blacklist"
value={blacklist}
helpText="Prevents Readarr from automatically grabbing these files again"
onChange={this.onBlacklistChange}
name="blocklist"
value={blocklist}
helpText={translate('BlocklistHelpText')}
onChange={this.onBlocklistChange}
/>
</FormGroup>
{
blacklist &&
blocklist &&
<FormGroup>
<FormLabel>Skip Redownload</FormLabel>
<FormLabel>
{translate('SkipRedownload')}
</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="skipredownload"
value={skipredownload}
helpText="Prevents Readarr from trying download alternative releases for the removed items"
helpText={translate('SkipredownloadHelpText')}
onChange={this.onSkipReDownloadChange}
/>
</FormGroup>
@@ -160,6 +170,7 @@ RemoveQueueItemsModal.propTypes = {
isOpen: PropTypes.bool.isRequired,
selectedCount: PropTypes.number.isRequired,
canIgnore: PropTypes.bool.isRequired,
allPending: PropTypes.bool.isRequired,
onRemovePress: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired
};

View File

@@ -5,6 +5,7 @@ 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 translate from 'Utilities/String/translate';
import styles from './TimeleftCell.css';
function TimeleftCell(props) {
@@ -19,35 +20,35 @@ function TimeleftCell(props) {
timeFormat
} = props;
if (status === 'Delay') {
if (status === 'delay') {
const date = getRelativeDate(estimatedCompletionTime, shortDateFormat, showRelativeDates);
const time = formatTime(estimatedCompletionTime, timeFormat, { includeMinuteZero: true });
return (
<TableRowCell
className={styles.timeleft}
title={`Delaying download until ${date} at ${time}`}
title={translate('DelayingDownloadUntilInterp', [date, time])}
>
-
</TableRowCell>
);
}
if (status === 'DownloadClientUnavailable') {
if (status === 'downloadClientUnavailable') {
const date = getRelativeDate(estimatedCompletionTime, shortDateFormat, showRelativeDates);
const time = formatTime(estimatedCompletionTime, timeFormat, { includeMinuteZero: true });
return (
<TableRowCell
className={styles.timeleft}
title={`Retrying download ${date} at ${time}`}
title={translate('RetryingDownloadInterp', [date, time])}
>
-
</TableRowCell>
);
}
if (!timeleft) {
if (!timeleft || status === 'completed' || status === 'failed') {
return (
<TableRowCell className={styles.timeleft}>
-

View File

@@ -0,0 +1,27 @@
import React from 'react';
import DescriptionList from 'Components/DescriptionList/DescriptionList';
import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem';
import translate from 'Utilities/String/translate';
function AuthorMonitorNewItemsOptionsPopoverContent() {
return (
<DescriptionList>
<DescriptionListItem
title={translate('AllBooks')}
data={translate('DataNewAllBooks')}
/>
<DescriptionListItem
title={translate('NewBooks')}
data={translate('DataNewBooks')}
/>
<DescriptionListItem
title={translate('None')}
data={translate('DataNewNone')}
/>
</DescriptionList>
);
}
export default AuthorMonitorNewItemsOptionsPopoverContent;

View File

@@ -1,45 +1,52 @@
import React from 'react';
import Alert from 'Components/Alert';
import DescriptionList from 'Components/DescriptionList/DescriptionList';
import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem';
import translate from 'Utilities/String/translate';
function AuthorMonitoringOptionsPopoverContent() {
return (
<DescriptionList>
<DescriptionListItem
title="All Books"
data="Monitor all books"
/>
<>
<Alert>
{translate('MonitoringOptionsHelpText')}
</Alert>
<DescriptionList>
<DescriptionListItem
title={translate('AllBooks')}
data={translate('DataAllBooks')}
/>
<DescriptionListItem
title="Future Books"
data="Monitor books that have not released yet"
/>
<DescriptionListItem
title={translate('FutureBooks')}
data={translate('DataFutureBooks')}
/>
<DescriptionListItem
title="Missing Books"
data="Monitor books that do not have files or have not released yet"
/>
<DescriptionListItem
title={translate('MissingBooks')}
data={translate('DataMissingBooks')}
/>
<DescriptionListItem
title="Existing Books"
data="Monitor books that have files or have not released yet"
/>
<DescriptionListItem
title={translate('ExistingBooks')}
data={translate('DataExistingBooks')}
/>
<DescriptionListItem
title="First Book"
data="Monitor the first book. All other books will be ignored"
/>
<DescriptionListItem
title={translate('FirstBook')}
data={translate('DataFirstBook')}
/>
<DescriptionListItem
title="Latest Book"
data="Monitor the latest book and future books"
/>
<DescriptionListItem
title={translate('LatestBook')}
data={translate('DataLatestBook')}
/>
<DescriptionListItem
title="None"
data="No books will be monitored"
/>
</DescriptionList>
<DescriptionListItem
title={translate('None')}
data={translate('DataNone')}
/>
</DescriptionList>
</>
);
}

View File

@@ -8,7 +8,7 @@ import AppRoutes from './AppRoutes';
function App({ store, history }) {
return (
<DocumentTitle title="Readarr">
<DocumentTitle title={window.Readarr.instanceName}>
<Provider store={store}>
<ConnectedRouter history={history}>
<PageConnector>

View File

@@ -1,18 +1,19 @@
import PropTypes from 'prop-types';
import React from 'react';
import { Redirect, Route } from 'react-router-dom';
import BlacklistConnector from 'Activity/Blacklist/BlacklistConnector';
import BlocklistConnector from 'Activity/Blocklist/BlocklistConnector';
import HistoryConnector from 'Activity/History/HistoryConnector';
import QueueConnector from 'Activity/Queue/QueueConnector';
import AuthorDetailsPageConnector from 'Author/Details/AuthorDetailsPageConnector';
import AuthorEditorConnector from 'Author/Editor/AuthorEditorConnector';
import AuthorIndexConnector from 'Author/Index/AuthorIndexConnector';
import BookDetailsPageConnector from 'Book/Details/BookDetailsPageConnector';
import BookIndexConnector from 'Book/Index/BookIndexConnector';
import BookshelfConnector from 'Bookshelf/BookshelfConnector';
import CalendarPageConnector from 'Calendar/CalendarPageConnector';
import NotFound from 'Components/NotFound';
import Switch from 'Components/Router/Switch';
import AddNewItemConnector from 'Search/AddNewItemConnector';
import DevelopmentSettingsConnector from 'Settings/Development/DevelopmentSettingsConnector';
import DownloadClientSettingsConnector from 'Settings/DownloadClients/DownloadClientSettingsConnector';
import GeneralSettingsConnector from 'Settings/General/GeneralSettingsConnector';
import ImportListSettingsConnector from 'Settings/ImportLists/ImportListSettingsConnector';
@@ -70,19 +71,26 @@ function AppRoutes(props) {
/>
}
<Route
path="/authors"
component={AuthorIndexConnector}
/>
<Route
path="/add/search"
component={AddNewItemConnector}
/>
<Route
path="/authoreditor"
component={AuthorEditorConnector}
exact={true}
path="/shelf"
component={BookshelfConnector}
/>
<Route
path="/bookshelf"
component={BookshelfConnector}
exact={true}
path="/books"
component={BookIndexConnector}
/>
<Route
@@ -124,8 +132,8 @@ function AppRoutes(props) {
/>
<Route
path="/activity/blacklist"
component={BlacklistConnector}
path="/activity/blocklist"
component={BlocklistConnector}
/>
{/*
@@ -207,6 +215,11 @@ function AppRoutes(props) {
component={UISettingsConnector}
/>
<Route
path="/settings/development"
component={DevelopmentSettingsConnector}
/>
{/*
System
*/}

View File

@@ -8,6 +8,7 @@ import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader';
import { kinds } from 'Helpers/Props';
import UpdateChanges from 'System/Updates/UpdateChanges';
import translate from 'Utilities/String/translate';
import styles from './AppUpdatedModalContent.css';
function AppUpdatedModalContent(props) {
@@ -38,7 +39,9 @@ function AppUpdatedModalContent(props) {
<div>
{
!update.changes &&
<div className={styles.maintenance}>Maintenance release</div>
<div className={styles.maintenance}>
{translate('MaintenanceRelease')}
</div>
}
{
@@ -49,12 +52,12 @@ function AppUpdatedModalContent(props) {
</div>
<UpdateChanges
title="New"
title={translate('New')}
changes={update.changes.new}
/>
<UpdateChanges
title="Fixed"
title={translate('Fixed')}
changes={update.changes.fixed}
/>
</div>

View File

@@ -122,9 +122,17 @@ class AuthorImage extends Component {
placeholder,
size,
lazy,
overflow
overflow,
blurBackground
} = this.props;
const blurStyle = {
...style,
objectFit: 'fill',
filter: 'blur(8px)',
WebkitFilter: 'blur(8px)'
};
const {
url,
hasError,
@@ -168,13 +176,26 @@ class AuthorImage extends Component {
}
return (
<img
className={className}
style={style}
src={isLoaded ? url : placeholder}
onError={this.onError}
onLoad={this.onLoad}
/>
<>
{
blurBackground ?
<img
style={blurStyle}
src={isLoaded ? url : placeholder}
onError={this.onError}
onLoad={this.onLoad}
/> :
null
}
<img
className={className}
style={style}
src={isLoaded ? url : placeholder}
onError={this.onError}
onLoad={this.onLoad}
/>
</>
);
}
}
@@ -188,6 +209,7 @@ AuthorImage.propTypes = {
size: PropTypes.number.isRequired,
lazy: PropTypes.bool.isRequired,
overflow: PropTypes.bool.isRequired,
blurBackground: PropTypes.bool.isRequired,
onError: PropTypes.func,
onLoad: PropTypes.func
};
@@ -195,7 +217,8 @@ AuthorImage.propTypes = {
AuthorImage.defaultProps = {
size: 250,
lazy: true,
overflow: false
overflow: false,
blurBackground: false
};
export default AuthorImage;

View File

@@ -8,7 +8,6 @@ function AuthorPoster(props) {
return (
<AuthorImage
{...props}
coverType="poster"
placeholder={posterPlaceholder}
/>
);
@@ -19,7 +18,8 @@ AuthorPoster.propTypes = {
};
AuthorPoster.defaultProps = {
size: 250
size: 250,
coverType: 'poster'
};
export default AuthorPoster;

View File

@@ -11,6 +11,7 @@ import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader';
import { icons, inputTypes, kinds } from 'Helpers/Props';
import formatBytes from 'Utilities/Number/formatBytes';
import translate from 'Utilities/String/translate';
import styles from './DeleteAuthorModalContent.css';
class DeleteAuthorModalContent extends Component {
@@ -67,7 +68,7 @@ class DeleteAuthorModalContent extends Component {
const addImportListExclusion = this.state.addImportListExclusion;
let deleteFilesLabel = `Delete ${bookFileCount} Book Files`;
let deleteFilesHelpText = 'Delete the book files and author folder';
let deleteFilesHelpText = translate('DeleteFilesHelpText');
if (bookFileCount === 0) {
deleteFilesLabel = 'Delete Author Folder';
@@ -106,13 +107,15 @@ class DeleteAuthorModalContent extends Component {
</FormGroup>
<FormGroup>
<FormLabel>Add List Exclusion</FormLabel>
<FormLabel>
{translate('AddListExclusion')}
</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="addImportListExclusion"
value={addImportListExclusion}
helpText="Prevent author from being added to Readarr by Import lists"
helpText={translate('AddImportListExclusionHelpText')}
kind={kinds.DANGER}
onChange={this.onAddImportListExclusionChange}
/>
@@ -121,7 +124,9 @@ class DeleteAuthorModalContent extends Component {
{
deleteFiles &&
<div className={styles.deleteFilesMessage}>
<div>The author folder <strong>{path}</strong> and all of its content will be deleted.</div>
<div>
{translate('TheAuthorFolderAndAllOfItsContentWillBeDeleted', [path])}
</div>
{
!!bookFileCount &&

View File

@@ -2,55 +2,12 @@
padding: 0;
}
.header {
position: relative;
width: 100%;
height: 310px;
}
.errorMessage {
margin-top: 20px;
text-align: center;
font-size: 20px;
}
.backdrop {
position: absolute;
z-index: -1;
width: 100%;
height: 100%;
background-size: cover;
}
.backdropOverlay {
position: absolute;
width: 100%;
height: 100%;
background: $black;
opacity: 0.7;
}
.headerContent {
display: flex;
padding: 30px;
width: 100%;
height: 100%;
color: $white;
}
.poster {
flex-shrink: 0;
margin-right: 35px;
height: 250px;
}
.info {
display: flex;
flex-direction: column;
flex-grow: 1;
overflow: hidden;
}
.metadataMessage {
color: $helpTextColor;
text-align: center;
@@ -58,97 +15,6 @@
font-size: 20px;
}
.titleRow {
display: flex;
justify-content: space-between;
flex: 0 0 auto;
}
.titleContainer {
display: flex;
margin-bottom: 5px;
}
.title {
font-weight: 300;
font-size: 50px;
line-height: 50px;
}
.toggleMonitoredContainer {
align-self: center;
margin-right: 10px;
}
.monitorToggleButton {
composes: toggleButton from '~Components/MonitorToggleButton.css';
width: 40px;
&:hover {
color: $iconButtonHoverLightColor;
}
}
.alternateTitlesIconContainer {
align-self: flex-end;
margin-left: 20px;
}
.filterIcon {
float: right;
}
.authorNavigationButtons {
white-space: nowrap;
}
.authorNavigationButton {
composes: button from '~Components/Link/IconButton.css';
margin-left: 5px;
width: 30px;
color: #e1e2e3;
white-space: nowrap;
&:hover {
color: $iconButtonHoverLightColor;
}
}
.details {
margin-bottom: 8px;
font-weight: 300;
font-size: 20px;
}
.runtime {
margin-right: 15px;
}
.detailsLabel {
composes: label from '~Components/Label.css';
margin: 5px 10px 5px 0;
}
.path,
.sizeOnDisk,
.qualityProfileName,
.links,
.tags {
margin-left: 8px;
font-weight: 300;
font-size: 17px;
}
.overview {
flex: 1 0 auto;
margin-top: 8px;
min-height: 0;
font-size: $intermediateFontSize;
}
.contentContainer {
padding: 20px;
}
@@ -178,18 +44,43 @@
margin-top: 20px;
}
.authorNavigationButtons {
position: absolute;
right: 0;
z-index: 1;
margin-top: 10px;
padding: 30px;
white-space: nowrap;
}
.authorUpButton,
.authorNavigationButton {
composes: button from '~Components/Link/IconButton.css';
margin-left: 5px;
width: 30px;
color: #e1e2e3;
white-space: nowrap;
&:hover {
color: $iconButtonHoverLightColor;
}
}
@media only screen and (max-width: $breakpointSmall) {
.contentContainer {
padding: 20px 0;
}
.headerContent {
.authorNavigationButtons {
padding: 15px;
}
}
@media only screen and (max-width: $breakpointLarge) {
.poster {
.authorNavigationButtons {
margin-top: 5px;
}
.authorNavigationButton {
display: none;
}
}

View File

@@ -1,58 +1,37 @@
import _ from 'lodash';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { Tab, TabList, TabPanel, Tabs } from 'react-tabs';
import TextTruncate from 'react-text-truncate';
import AuthorPoster from 'Author/AuthorPoster';
import DeleteAuthorModal from 'Author/Delete/DeleteAuthorModal';
import EditAuthorModalConnector from 'Author/Edit/EditAuthorModalConnector';
import AuthorHistoryTable from 'Author/History/AuthorHistoryTable';
import MonitoringOptionsModal from 'Author/MonitoringOptions/MonitoringOptionsModal';
import BookEditorFooter from 'Book/Editor/BookEditorFooter';
import BookFileEditorTable from 'BookFile/Editor/BookFileEditorTable';
import HeartRating from 'Components/HeartRating';
import Icon from 'Components/Icon';
import Label from 'Components/Label';
import IconButton from 'Components/Link/IconButton';
import Link from 'Components/Link/Link';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import MonitorToggleButton from 'Components/MonitorToggleButton';
import PageContent from 'Components/Page/PageContent';
import PageContentBodyConnector from 'Components/Page/PageContentBodyConnector';
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 Popover from 'Components/Tooltip/Popover';
import Tooltip from 'Components/Tooltip/Tooltip';
import { align, icons, kinds, sizes, tooltipPositions } from 'Helpers/Props';
import SwipeHeaderConnector from 'Components/Swipe/SwipeHeaderConnector';
import { align, icons } from 'Helpers/Props';
import InteractiveSearchFilterMenuConnector from 'InteractiveSearch/InteractiveSearchFilterMenuConnector';
import InteractiveSearchTable from 'InteractiveSearch/InteractiveSearchTable';
import OrganizePreviewModalConnector from 'Organize/OrganizePreviewModalConnector';
import RetagPreviewModalConnector from 'Retag/RetagPreviewModalConnector';
import QualityProfileNameConnector from 'Settings/Profiles/Quality/QualityProfileNameConnector';
import fonts from 'Styles/Variables/fonts';
import formatBytes from 'Utilities/Number/formatBytes';
import stripHtml from 'Utilities/String/stripHtml';
import translate from 'Utilities/String/translate';
import getSelectedIds from 'Utilities/Table/getSelectedIds';
import selectAll from 'Utilities/Table/selectAll';
import toggleSelected from 'Utilities/Table/toggleSelected';
import InteractiveImportModal from '../../InteractiveImport/InteractiveImportModal';
import AuthorAlternateTitles from './AuthorAlternateTitles';
import AuthorDetailsLinks from './AuthorDetailsLinks';
import AuthorDetailsHeaderConnector from './AuthorDetailsHeaderConnector';
import AuthorDetailsSeasonConnector from './AuthorDetailsSeasonConnector';
import AuthorDetailsSeriesConnector from './AuthorDetailsSeriesConnector';
import AuthorTagsConnector from './AuthorTagsConnector';
import styles from './AuthorDetails.css';
const defaultFontSize = parseInt(fonts.defaultFontSize);
const lineHeight = parseFloat(fonts.lineHeight);
function getFanartUrl(images) {
const fanartImage = _.find(images, { coverType: 'fanart' });
if (fanartImage) {
// Remove protocol
return fanartImage.url.replace(/^https?:/, '');
}
}
function getExpandedState(newState) {
return {
allExpanded: newState.allSelected,
@@ -75,13 +54,57 @@ class AuthorDetails extends Component {
isEditAuthorModalOpen: false,
isDeleteAuthorModalOpen: false,
isInteractiveImportModalOpen: false,
isMonitorOptionsModalOpen: false,
isEditorActive: false,
allExpanded: false,
allCollapsed: false,
expandedState: {},
allSelected: false,
allUnselected: false,
lastToggled: null,
selectedState: {},
selectedTabIndex: 0
};
}
//
// Control
setSelectedState = (items) => {
const {
selectedState
} = this.state;
const newSelectedState = {};
items.forEach((item) => {
const isItemSelected = selectedState[item.id];
if (isItemSelected) {
newSelectedState[item.id] = isItemSelected;
} else {
newSelectedState[item.id] = false;
}
});
const selectedCount = getSelectedIds(newSelectedState).length;
const newStateCount = Object.keys(newSelectedState).length;
let isAllSelected = false;
let isAllUnselected = false;
if (selectedCount === 0) {
isAllUnselected = true;
} else if (selectedCount === newStateCount) {
isAllSelected = true;
}
this.setState({ selectedState: newSelectedState, allSelected: isAllSelected, allUnselected: isAllUnselected });
}
getSelectedIds = () => {
return getSelectedIds(this.state.selectedState);
}
//
// Listeners
@@ -128,6 +151,18 @@ class AuthorDetails extends Component {
this.setState({ isDeleteAuthorModalOpen: false });
}
onMonitorOptionsPress = () => {
this.setState({ isMonitorOptionsModalOpen: true });
}
onMonitorOptionsClose = () => {
this.setState({ isMonitorOptionsModalOpen: false });
}
onBookEditorTogglePress = () => {
this.setState({ isEditorActive: !this.state.isEditorActive });
}
onExpandAllPress = () => {
const {
allExpanded,
@@ -151,6 +186,27 @@ class AuthorDetails extends Component {
});
}
onSelectAllChange = ({ value }) => {
this.setState(selectAll(this.state.selectedState, value));
}
onSelectAllPress = () => {
this.onSelectAllChange({ value: !this.state.allSelected });
}
onSelectedChange = (items, id, value, shiftKey = false) => {
this.setState((state) => {
return toggleSelected(state, items, id, value, shiftKey);
});
}
onSaveSelected = (changes) => {
this.props.onSaveSelected({
bookIds: this.getSelectedIds(),
...changes
});
}
onTabSelect = (index, lastIndex) => {
this.setState({ selectedTabIndex: index });
}
@@ -162,18 +218,8 @@ class AuthorDetails extends Component {
const {
id,
authorName,
ratings,
path,
statistics,
qualityProfileId,
monitored,
status,
overview,
links,
images,
alternateTitles,
tags,
isSaving,
isRefreshing,
isSearching,
isFetching,
@@ -187,38 +233,31 @@ class AuthorDetails extends Component {
hasBookFiles,
previousAuthor,
nextAuthor,
onMonitorTogglePress,
onRefreshPress,
onSearchPress
onSearchPress,
isSaving,
saveError,
isDeleting,
deleteError,
statistics
} = this.props;
const {
bookFileCount,
sizeOnDisk
} = statistics;
const {
isOrganizeModalOpen,
isRetagModalOpen,
isEditAuthorModalOpen,
isDeleteAuthorModalOpen,
isInteractiveImportModalOpen,
isMonitorOptionsModalOpen,
isEditorActive,
allSelected,
selectedState,
allExpanded,
allCollapsed,
expandedState,
selectedTabIndex
} = this.state;
const continuing = status === 'continuing';
let bookFilesCountMessage = 'No book files';
if (bookFileCount === 1) {
bookFilesCountMessage = '1 book file';
} else if (bookFileCount > 1) {
bookFilesCountMessage = `${bookFileCount} book files`;
}
let expandIcon = icons.EXPAND_INDETERMINATE;
if (allExpanded) {
@@ -227,46 +266,48 @@ class AuthorDetails extends Component {
expandIcon = icons.EXPAND;
}
const selectedBookIds = this.getSelectedIds();
return (
<PageContent title={authorName}>
<PageToolbar>
<PageToolbarSection>
<PageToolbarButton
label="Refresh & Scan"
label={translate('RefreshAndScan')}
iconName={icons.REFRESH}
spinningName={icons.REFRESH}
title="Refresh information and scan disk"
title={translate('RefreshInformationAndScanDisk')}
isSpinning={isRefreshing}
onPress={onRefreshPress}
/>
<PageToolbarButton
label="Search Monitored"
label={translate('SearchMonitored')}
iconName={icons.SEARCH}
isDisabled={!monitored || !hasMonitoredBooks || !hasBooks}
isSpinning={isSearching}
title={hasMonitoredBooks ? undefined : 'No monitored books for this author'}
title={hasMonitoredBooks ? undefined : translate('HasMonitoredBooksNoMonitoredBooksForThisAuthor')}
onPress={onSearchPress}
/>
<PageToolbarSeparator />
<PageToolbarButton
label="Preview Rename"
label={translate('PreviewRename')}
iconName={icons.ORGANIZE}
isDisabled={!hasBookFiles}
onPress={this.onOrganizePress}
/>
{/* <PageToolbarButton */}
{/* label="Preview Retag" */}
{/* iconName={icons.RETAG} */}
{/* isDisabled={!hasBookFiles} */}
{/* onPress={this.onRetagPress} */}
{/* /> */}
<PageToolbarButton
label={translate('PreviewRetag')}
iconName={icons.RETAG}
isDisabled={!hasBookFiles}
onPress={this.onRetagPress}
/>
<PageToolbarButton
label="Manual Import"
label={translate('ManualImport')}
iconName={icons.INTERACTIVE}
onPress={this.onInteractiveImportPress}
/>
@@ -274,256 +315,98 @@ class AuthorDetails extends Component {
<PageToolbarSeparator />
<PageToolbarButton
label="Edit"
label={translate('BookMonitoring')}
iconName={icons.MONITORED}
onPress={this.onMonitorOptionsPress}
/>
<PageToolbarButton
label={translate('Edit')}
iconName={icons.EDIT}
onPress={this.onEditAuthorPress}
/>
<PageToolbarButton
label="Delete"
label={translate('Delete')}
iconName={icons.DELETE}
onPress={this.onDeleteAuthorPress}
/>
<PageToolbarSeparator />
{
isEditorActive ?
<PageToolbarButton
label={translate('BookList')}
iconName={icons.AUTHOR_CONTINUING}
onPress={this.onBookEditorTogglePress}
/> :
<PageToolbarButton
label={translate('BookEditor')}
iconName={icons.EDIT}
onPress={this.onBookEditorTogglePress}
/>
}
{
isEditorActive ?
<PageToolbarButton
label={allSelected ? translate('UnselectAll') : translate('SelectAll')}
iconName={icons.CHECK_SQUARE}
onPress={this.onSelectAllPress}
/> :
null
}
</PageToolbarSection>
<PageToolbarSection alignContent={align.RIGHT}>
<PageToolbarButton
label={allExpanded ? 'Collapse All' : 'Expand All'}
label={allExpanded ? translate('AllExpandedCollapseAll') : translate('AllExpandedExpandAll')}
iconName={expandIcon}
onPress={this.onExpandAllPress}
/>
</PageToolbarSection>
</PageToolbar>
<PageContentBodyConnector innerClassName={styles.innerContentBody}>
<div className={styles.header}>
<div
className={styles.backdrop}
style={{
backgroundImage: `url(${getFanartUrl(images)})`
}}
>
<div className={styles.backdropOverlay} />
</div>
<div className={styles.headerContent}>
<AuthorPoster
className={styles.poster}
images={images}
size={250}
lazy={false}
<PageContentBody innerClassName={styles.innerContentBody}>
<SwipeHeaderConnector
className={styles.header}
nextLink={`/author/${nextAuthor.titleSlug}`}
nextComponent={(width) => <AuthorDetailsHeaderConnector authorId={nextAuthor.id} width={width} />}
prevLink={`/author/${previousAuthor.titleSlug}`}
prevComponent={(width) => <AuthorDetailsHeaderConnector authorId={previousAuthor.id} width={width} />}
currentComponent={(width) => <AuthorDetailsHeaderConnector authorId={id} width={width} />}
>
<div className={styles.authorNavigationButtons}>
<IconButton
className={styles.authorNavigationButton}
name={icons.ARROW_LEFT}
size={30}
title={translate('GoToInterp', [previousAuthor.authorName])}
to={`/author/${previousAuthor.titleSlug}`}
/>
<div className={styles.info}>
<div className={styles.titleRow}>
<div className={styles.titleContainer}>
<div className={styles.toggleMonitoredContainer}>
<MonitorToggleButton
className={styles.monitorToggleButton}
monitored={monitored}
isSaving={isSaving}
size={40}
onPress={onMonitorTogglePress}
/>
</div>
<IconButton
className={styles.authorUpButton}
name={icons.ARROW_UP}
size={30}
title={translate('GoToAuthorListing')}
to={{
pathname: '/',
state: { restoreScrollPosition: true }
}}
/>
<div className={styles.title}>
{authorName}
</div>
{
!!alternateTitles.length &&
<div className={styles.alternateTitlesIconContainer}>
<Popover
anchor={
<Icon
name={icons.ALTERNATE_TITLES}
size={20}
/>
}
title="Alternate Titles"
body={<AuthorAlternateTitles alternateTitles={alternateTitles} />}
position={tooltipPositions.BOTTOM}
/>
</div>
}
</div>
<div className={styles.authorNavigationButtons}>
<IconButton
className={styles.authorNavigationButton}
name={icons.ARROW_LEFT}
size={30}
title={`Go to ${previousAuthor.authorName}`}
to={`/author/${previousAuthor.titleSlug}`}
/>
<IconButton
className={styles.authorNavigationButton}
name={icons.ARROW_UP}
size={30}
title={'Go to author listing'}
to={'/'}
/>
<IconButton
className={styles.authorNavigationButton}
name={icons.ARROW_RIGHT}
size={30}
title={`Go to ${nextAuthor.authorName}`}
to={`/author/${nextAuthor.titleSlug}`}
/>
</div>
</div>
<div className={styles.details}>
<div>
<HeartRating
rating={ratings.value}
iconSize={20}
/>
</div>
</div>
<div className={styles.detailsLabels}>
<Label
className={styles.detailsLabel}
size={sizes.LARGE}
>
<Icon
name={icons.FOLDER}
size={17}
/>
<span className={styles.path}>
{path}
</span>
</Label>
<Label
className={styles.detailsLabel}
title={bookFilesCountMessage}
size={sizes.LARGE}
>
<Icon
name={icons.DRIVE}
size={17}
/>
<span className={styles.sizeOnDisk}>
{
formatBytes(sizeOnDisk)
}
</span>
</Label>
<Label
className={styles.detailsLabel}
title="Quality Profile"
size={sizes.LARGE}
>
<Icon
name={icons.PROFILE}
size={17}
/>
<span className={styles.qualityProfileName}>
{
<QualityProfileNameConnector
qualityProfileId={qualityProfileId}
/>
}
</span>
</Label>
<Label
className={styles.detailsLabel}
size={sizes.LARGE}
>
<Icon
name={monitored ? icons.MONITORED : icons.UNMONITORED}
size={17}
/>
<span className={styles.qualityProfileName}>
{monitored ? 'Monitored' : 'Unmonitored'}
</span>
</Label>
<Label
className={styles.detailsLabel}
title={continuing ? 'More books are expected' : 'No additional books are expected'}
size={sizes.LARGE}
>
<Icon
name={continuing ? icons.AUTHOR_CONTINUING : icons.AUTHOR_ENDED}
size={17}
/>
<span className={styles.qualityProfileName}>
{continuing ? 'Continuing' : 'Deceased'}
</span>
</Label>
<Tooltip
anchor={
<Label
className={styles.detailsLabel}
size={sizes.LARGE}
>
<Icon
name={icons.EXTERNAL_LINK}
size={17}
/>
<span className={styles.links}>
Links
</span>
</Label>
}
tooltip={
<AuthorDetailsLinks
links={links}
/>
}
kind={kinds.INVERSE}
position={tooltipPositions.BOTTOM}
/>
{
!!tags.length &&
<Tooltip
anchor={
<Label
className={styles.detailsLabel}
size={sizes.LARGE}
>
<Icon
name={icons.TAGS}
size={17}
/>
<span className={styles.tags}>
Tags
</span>
</Label>
}
tooltip={<AuthorTagsConnector authorId={id} />}
kind={kinds.INVERSE}
position={tooltipPositions.BOTTOM}
/>
}
</div>
<div className={styles.overview}>
<TextTruncate
line={Math.floor(125 / (defaultFontSize * lineHeight))}
text={stripHtml(overview)}
/>
</div>
</div>
<IconButton
className={styles.authorNavigationButton}
name={icons.ARROW_RIGHT}
size={30}
title={translate('GoToInterp', [nextAuthor.authorName])}
to={`/author/${nextAuthor.titleSlug}`}
/>
</div>
</div>
</SwipeHeaderConnector>
<div className={styles.contentContainer}>
{
@@ -533,12 +416,16 @@ class AuthorDetails extends Component {
{
!isFetching && booksError &&
<div>Loading books failed</div>
<div>
{translate('LoadingBooksFailed')}
</div>
}
{
!isFetching && bookFilesError &&
<div>Loading book files failed</div>
<div>
{translate('LoadingBookFilesFailed')}
</div>
}
{
@@ -551,35 +438,35 @@ class AuthorDetails extends Component {
className={styles.tab}
selectedClassName={styles.selectedTab}
>
Books
{translate('BooksTotal', [statistics.totalBookCount])}
</Tab>
<Tab
className={styles.tab}
selectedClassName={styles.selectedTab}
>
Series
{translate('SeriesTotal', [series.length])}
</Tab>
<Tab
className={styles.tab}
selectedClassName={styles.selectedTab}
>
History
{translate('History')}
</Tab>
<Tab
className={styles.tab}
selectedClassName={styles.selectedTab}
>
Search
{translate('Search')}
</Tab>
<Tab
className={styles.tab}
selectedClassName={styles.selectedTab}
>
Files
{translate('FilesTotal', [statistics.bookFileCount])}
</Tab>
{
@@ -596,7 +483,11 @@ class AuthorDetails extends Component {
<AuthorDetailsSeasonConnector
authorId={id}
isExpanded={true}
selectedState={selectedState}
onExpandPress={this.onExpandPress}
setSelectedState={this.setSelectedState}
onSelectedChange={this.onSelectedChange}
isEditorActive={isEditorActive}
/>
</TabPanel>
@@ -641,14 +532,13 @@ class AuthorDetails extends Component {
</TabPanel>
</Tabs>
}
</div>
<div className={styles.metadataMessage}>
Missing or too many books? Modify or create a new
<Link to='/settings/profiles'> Metadata Profile </Link>
{translate('TooManyBooks')}
<Link to='/settings/profiles'> {translate('MetadataProfile')} </Link>
or manually
<Link to={`/add/search?term=${encodeURIComponent(authorName)}`}> Search </Link>
<Link to={`/add/search?term=${encodeURIComponent(authorName)}`}> {translate('Search')} </Link>
for new items!
</div>
@@ -686,7 +576,26 @@ class AuthorDetails extends Component {
showImportMode={false}
onModalClose={this.onInteractiveImportModalClose}
/>
</PageContentBodyConnector>
<MonitoringOptionsModal
isOpen={isMonitorOptionsModalOpen}
authorId={id}
onModalClose={this.onMonitorOptionsClose}
/>
</PageContentBody>
{
isEditorActive &&
<BookEditorFooter
bookIds={selectedBookIds}
selectedCount={selectedBookIds.length}
isSaving={isSaving}
saveError={saveError}
isDeleting={isDeleting}
deleteError={deleteError}
onSaveSelected={this.onSaveSelected}
/>
}
</PageContent>
);
}
@@ -706,7 +615,6 @@ AuthorDetails.propTypes = {
images: PropTypes.arrayOf(PropTypes.object).isRequired,
alternateTitles: PropTypes.arrayOf(PropTypes.string).isRequired,
tags: PropTypes.arrayOf(PropTypes.number).isRequired,
isSaving: PropTypes.bool.isRequired,
isRefreshing: PropTypes.bool.isRequired,
isSearching: PropTypes.bool.isRequired,
isFetching: PropTypes.bool.isRequired,
@@ -720,15 +628,20 @@ AuthorDetails.propTypes = {
hasBookFiles: PropTypes.bool.isRequired,
previousAuthor: PropTypes.object.isRequired,
nextAuthor: PropTypes.object.isRequired,
isSmallScreen: PropTypes.bool.isRequired,
onMonitorTogglePress: PropTypes.func.isRequired,
onRefreshPress: PropTypes.func.isRequired,
onSearchPress: PropTypes.func.isRequired
onSearchPress: PropTypes.func.isRequired,
isSaving: PropTypes.bool.isRequired,
saveError: PropTypes.object,
isDeleting: PropTypes.bool.isRequired,
deleteError: PropTypes.object,
onSaveSelected: PropTypes.func.isRequired
};
AuthorDetails.defaultProps = {
statistics: {},
tags: [],
isSaving: false
tags: []
};
export default AuthorDetails;

View File

@@ -6,14 +6,15 @@ import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import * as commandNames from 'Commands/commandNames';
import { toggleAuthorMonitored } from 'Store/Actions/authorActions';
import { clearBooks, fetchBooks } from 'Store/Actions/bookActions';
import { clearBookFiles, fetchBookFiles } from 'Store/Actions/bookFileActions';
import { saveBookEditor } from 'Store/Actions/bookIndexActions';
import { executeCommand } from 'Store/Actions/commandActions';
import { clearQueueDetails, fetchQueueDetails } from 'Store/Actions/queueActions';
import { cancelFetchReleases, clearReleases } from 'Store/Actions/releaseActions';
import { clearSeries, fetchSeries } from 'Store/Actions/seriesActions';
import createAllAuthorSelector from 'Store/Selectors/createAllAuthorsSelector';
import createCommandsSelector from 'Store/Selectors/createCommandsSelector';
import createDimensionsSelector from 'Store/Selectors/createDimensionsSelector';
import createSortedSectionSelector from 'Store/Selectors/createSortedSectionSelector';
import { findCommand, isCommandExecuting } from 'Utilities/Command';
import { registerPagePopulator, unregisterPagePopulator } from 'Utilities/pagePopulator';
@@ -21,7 +22,8 @@ import AuthorDetails from './AuthorDetails';
const selectBooks = createSelector(
(state) => state.books,
(books) => {
(state) => state.bookIndex,
(books, index) => {
const {
items,
isFetching,
@@ -29,6 +31,13 @@ const selectBooks = createSelector(
error
} = books;
const {
isSaving,
saveError,
isDeleting,
deleteError
} = index;
const hasBooks = !!items.length;
const hasMonitoredBooks = items.some((e) => e.monitored);
@@ -37,7 +46,11 @@ const selectBooks = createSelector(
isBooksPopulated: isPopulated,
booksError: error,
hasBooks,
hasMonitoredBooks
hasMonitoredBooks,
isSaving,
saveError,
isDeleting,
deleteError
};
}
);
@@ -94,8 +107,9 @@ function createMapStateToProps() {
selectBookFiles,
createAllAuthorSelector(),
createCommandsSelector(),
(titleSlug, books, series, bookFiles, allAuthors, commands) => {
const sortedAuthor = _.orderBy(allAuthors, 'sortName');
createDimensionsSelector(),
(titleSlug, books, series, bookFiles, allAuthors, commands, dimensions) => {
const sortedAuthor = _.orderBy(allAuthors, 'sortNameLastFirst');
const authorIndex = _.findIndex(sortedAuthor, { titleSlug });
const author = sortedAuthor[authorIndex];
@@ -108,7 +122,11 @@ function createMapStateToProps() {
isBooksPopulated,
booksError,
hasBooks,
hasMonitoredBooks
hasMonitoredBooks,
isSaving,
saveError,
isDeleting,
deleteError
} = books;
const {
@@ -168,6 +186,10 @@ function createMapStateToProps() {
isFetching,
isPopulated,
booksError,
isSaving,
saveError,
isDeleting,
deleteError,
seriesError,
bookFilesError,
hasBooks,
@@ -176,17 +198,17 @@ function createMapStateToProps() {
series: seriesItems,
hasBookFiles,
previousAuthor,
nextAuthor
nextAuthor,
isSmallScreen: dimensions.isSmallScreen
};
}
);
}
const mapDispatchToProps = {
fetchBooks,
clearBooks,
fetchSeries,
clearSeries,
saveBookEditor,
fetchBookFiles,
clearBookFiles,
toggleAuthorMonitored,
@@ -245,7 +267,6 @@ class AuthorDetailsConnector extends Component {
populate = () => {
const authorId = this.props.id;
this.props.fetchBooks({ authorId });
this.props.fetchSeries({ authorId });
this.props.fetchBookFiles({ authorId });
this.props.fetchQueueDetails({ authorId });
@@ -253,7 +274,6 @@ class AuthorDetailsConnector extends Component {
unpopulate = () => {
this.props.cancelFetchReleases();
this.props.clearBooks();
this.props.clearSeries();
this.props.clearBookFiles();
this.props.clearQueueDetails();
@@ -284,6 +304,10 @@ class AuthorDetailsConnector extends Component {
});
}
onSaveSelected = (payload) => {
this.props.saveBookEditor(payload);
}
//
// Render
@@ -294,6 +318,7 @@ class AuthorDetailsConnector extends Component {
onMonitorTogglePress={this.onMonitorTogglePress}
onRefreshPress={this.onRefreshPress}
onSearchPress={this.onSearchPress}
onSaveSelected={this.onSaveSelected}
/>
);
}
@@ -307,10 +332,9 @@ AuthorDetailsConnector.propTypes = {
isRefreshing: PropTypes.bool.isRequired,
isRenamingFiles: PropTypes.bool.isRequired,
isRenamingAuthor: PropTypes.bool.isRequired,
fetchBooks: PropTypes.func.isRequired,
clearBooks: PropTypes.func.isRequired,
fetchSeries: PropTypes.func.isRequired,
clearSeries: PropTypes.func.isRequired,
saveBookEditor: PropTypes.func.isRequired,
fetchBookFiles: PropTypes.func.isRequired,
clearBookFiles: PropTypes.func.isRequired,
toggleAuthorMonitored: PropTypes.func.isRequired,

View File

@@ -0,0 +1,148 @@
.header {
position: relative;
width: 100%;
height: 310px;
}
.backdrop {
position: absolute;
z-index: -1;
width: 100%;
height: 100%;
background-size: cover;
}
.backdropOverlay {
position: absolute;
width: 100%;
height: 100%;
background: $black;
opacity: 0.7;
}
.headerContent {
display: flex;
padding: 30px;
width: 100%;
height: 100%;
color: $white;
}
.poster {
flex-shrink: 0;
margin-right: 35px;
height: 250px;
}
.info {
display: flex;
flex-direction: column;
flex-grow: 1;
overflow: hidden;
}
.titleRow {
position: relative;
display: flex;
justify-content: space-between;
flex: 0 0 auto;
}
.titleContainer {
display: flex;
margin-top: -5px;
}
.title {
font-weight: 300;
font-size: 50px;
line-height: 60px;
}
.toggleMonitoredContainer {
align-self: center;
}
.monitorToggleButton {
composes: toggleButton from '~Components/MonitorToggleButton.css';
width: 40px;
&:hover {
color: $iconButtonHoverLightColor;
}
}
.alternateTitlesIconContainer {
align-self: flex-end;
margin-left: 20px;
}
.authorNavigationButtons {
position: absolute;
right: 0;
z-index: 1;
margin-top: 10px;
padding: 30px;
white-space: nowrap;
}
.authorUpButton,
.authorNavigationButton {
composes: button from '~Components/Link/IconButton.css';
margin-left: 5px;
width: 30px;
color: #e1e2e3;
white-space: nowrap;
&:hover {
color: $iconButtonHoverLightColor;
}
}
.details {
margin-bottom: 8px;
font-weight: 300;
font-size: 20px;
}
.detailsLabel {
composes: label from '~Components/Label.css';
margin: 5px 10px 5px 0;
}
.path,
.sizeOnDisk,
.qualityProfileName,
.links,
.tags {
margin-left: 8px;
font-weight: 300;
font-size: 17px;
}
.overview {
flex: 1 1 auto;
margin-top: 8px;
min-height: 0;
font-size: $intermediateFontSize;
}
@media only screen and (max-width: $breakpointSmall) {
.headerContent {
padding: 15px;
}
.title {
font-size: 30px;
line-height: 50px;
}
}
@media only screen and (max-width: $breakpointLarge) {
.poster {
display: none;
}
}

View File

@@ -0,0 +1,340 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import TextTruncate from 'react-text-truncate';
import AuthorPoster from 'Author/AuthorPoster';
import HeartRating from 'Components/HeartRating';
import Icon from 'Components/Icon';
import Label from 'Components/Label';
import Marquee from 'Components/Marquee';
import Measure from 'Components/Measure';
import MonitorToggleButton from 'Components/MonitorToggleButton';
import Popover from 'Components/Tooltip/Popover';
import Tooltip from 'Components/Tooltip/Tooltip';
import { icons, kinds, sizes, tooltipPositions } from 'Helpers/Props';
import QualityProfileNameConnector from 'Settings/Profiles/Quality/QualityProfileNameConnector';
import fonts from 'Styles/Variables/fonts';
import formatBytes from 'Utilities/Number/formatBytes';
import stripHtml from 'Utilities/String/stripHtml';
import translate from 'Utilities/String/translate';
import AuthorAlternateTitles from './AuthorAlternateTitles';
import AuthorDetailsLinks from './AuthorDetailsLinks';
import AuthorTagsConnector from './AuthorTagsConnector';
import styles from './AuthorDetailsHeader.css';
const defaultFontSize = parseInt(fonts.defaultFontSize);
const lineHeight = parseFloat(fonts.lineHeight);
function getFanartUrl(images) {
const fanartImage = images.find((x) => x.coverType === 'fanart');
if (fanartImage) {
// Remove protocol
return fanartImage.url.replace(/^https?:/, '');
}
}
class AuthorDetailsHeader extends Component {
//
// Lifecyle
constructor(props) {
super(props);
this.state = {
overviewHeight: 0,
titleWidth: 0
};
}
//
// Listeners
onOverviewMeasure = ({ height }) => {
this.setState({ overviewHeight: height });
}
onTitleMeasure = ({ width }) => {
this.setState({ titleWidth: width });
}
//
// Render
render() {
const {
id,
width,
authorName,
ratings,
path,
statistics,
qualityProfileId,
monitored,
status,
overview,
links,
images,
alternateTitles,
tags,
isSaving,
isSmallScreen,
onMonitorTogglePress
} = this.props;
const {
bookFileCount,
sizeOnDisk
} = statistics;
const {
overviewHeight,
titleWidth
} = this.state;
const marqueeWidth = titleWidth - (isSmallScreen ? 85 : 160);
const continuing = status === 'continuing';
let bookFilesCountMessage = translate('BookFilesCountMessage');
if (bookFileCount === 1) {
bookFilesCountMessage = '1 book file';
} else if (bookFileCount > 1) {
bookFilesCountMessage = `${bookFileCount} book files`;
}
return (
<div className={styles.header} style={{ width }} >
<div
className={styles.backdrop}
style={{
backgroundImage: `url(${getFanartUrl(images)})`
}}
>
<div className={styles.backdropOverlay} />
</div>
<div className={styles.headerContent}>
<AuthorPoster
className={styles.poster}
images={images}
size={250}
lazy={false}
/>
<div className={styles.info}>
<Measure
className={styles.titleRow}
onMeasure={this.onTitleMeasure}
>
<div className={styles.titleContainer}>
<div className={styles.toggleMonitoredContainer}>
<MonitorToggleButton
className={styles.monitorToggleButton}
monitored={monitored}
isSaving={isSaving}
size={isSmallScreen ? 30: 40}
onPress={onMonitorTogglePress}
/>
</div>
<div className={styles.title} style={{ width: marqueeWidth }}>
<Marquee text={authorName} />
</div>
{
!!alternateTitles.length &&
<div className={styles.alternateTitlesIconContainer}>
<Popover
anchor={
<Icon
name={icons.ALTERNATE_TITLES}
size={20}
/>
}
title={translate('AlternateTitles')}
body={<AuthorAlternateTitles alternateTitles={alternateTitles} />}
position={tooltipPositions.BOTTOM}
/>
</div>
}
</div>
</Measure>
<div className={styles.details}>
<div>
<HeartRating
rating={ratings.value}
iconSize={20}
/>
</div>
</div>
<div className={styles.detailsLabels}>
<Label
className={styles.detailsLabel}
size={sizes.LARGE}
>
<Icon
name={icons.FOLDER}
size={17}
/>
<span className={styles.path}>
{path}
</span>
</Label>
<Label
className={styles.detailsLabel}
title={bookFilesCountMessage}
size={sizes.LARGE}
>
<Icon
name={icons.DRIVE}
size={17}
/>
<span className={styles.sizeOnDisk}>
{
formatBytes(sizeOnDisk || 0)
}
</span>
</Label>
<Label
className={styles.detailsLabel}
title={translate('QualityProfile')}
size={sizes.LARGE}
>
<Icon
name={icons.PROFILE}
size={17}
/>
<span className={styles.qualityProfileName}>
{
<QualityProfileNameConnector
qualityProfileId={qualityProfileId}
/>
}
</span>
</Label>
<Label
className={styles.detailsLabel}
size={sizes.LARGE}
>
<Icon
name={monitored ? icons.MONITORED : icons.UNMONITORED}
size={17}
/>
<span className={styles.qualityProfileName}>
{monitored ? 'Monitored' : 'Unmonitored'}
</span>
</Label>
<Label
className={styles.detailsLabel}
title={continuing ? translate('ContinuingMoreBooksAreExpected') : translate('ContinuingNoAdditionalBooksAreExpected')}
size={sizes.LARGE}
>
<Icon
name={continuing ? icons.AUTHOR_CONTINUING : icons.AUTHOR_ENDED}
size={17}
/>
<span className={styles.qualityProfileName}>
{continuing ? 'Continuing' : 'Deceased'}
</span>
</Label>
<Tooltip
anchor={
<Label
className={styles.detailsLabel}
size={sizes.LARGE}
>
<Icon
name={icons.EXTERNAL_LINK}
size={17}
/>
<span className={styles.links}>
Links
</span>
</Label>
}
tooltip={
<AuthorDetailsLinks
links={links}
/>
}
kind={kinds.INVERSE}
position={tooltipPositions.BOTTOM}
/>
{
!!tags.length &&
<Tooltip
anchor={
<Label
className={styles.detailsLabel}
size={sizes.LARGE}
>
<Icon
name={icons.TAGS}
size={17}
/>
<span className={styles.tags}>
Tags
</span>
</Label>
}
tooltip={<AuthorTagsConnector authorId={id} />}
kind={kinds.INVERSE}
position={tooltipPositions.BOTTOM}
/>
}
</div>
<Measure
onMeasure={this.onOverviewMeasure}
className={styles.overview}
>
<TextTruncate
line={Math.floor(overviewHeight / (defaultFontSize * lineHeight))}
text={stripHtml(overview)}
/>
</Measure>
</div>
</div>
</div>
);
}
}
AuthorDetailsHeader.propTypes = {
id: PropTypes.number.isRequired,
width: PropTypes.number.isRequired,
authorName: PropTypes.string.isRequired,
ratings: PropTypes.object.isRequired,
path: PropTypes.string.isRequired,
statistics: PropTypes.object.isRequired,
qualityProfileId: PropTypes.number.isRequired,
monitored: PropTypes.bool.isRequired,
status: PropTypes.string.isRequired,
overview: PropTypes.string,
links: PropTypes.arrayOf(PropTypes.object).isRequired,
images: PropTypes.arrayOf(PropTypes.object).isRequired,
alternateTitles: PropTypes.arrayOf(PropTypes.string).isRequired,
tags: PropTypes.arrayOf(PropTypes.number).isRequired,
isSaving: PropTypes.bool.isRequired,
isSmallScreen: PropTypes.bool.isRequired,
onMonitorTogglePress: PropTypes.func.isRequired
};
export default AuthorDetailsHeader;

View File

@@ -0,0 +1,71 @@
/* eslint max-params: 0 */
import _ from 'lodash';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { toggleAuthorMonitored } from 'Store/Actions/authorActions';
import createAuthorSelector from 'Store/Selectors/createAuthorSelector';
import createDimensionsSelector from 'Store/Selectors/createDimensionsSelector';
import AuthorDetailsHeader from './AuthorDetailsHeader';
function createMapStateToProps() {
return createSelector(
(state) => state.authors,
createAuthorSelector(),
createDimensionsSelector(),
(authors, author, dimensions) => {
const alternateTitles = _.reduce(author.alternateTitles, (acc, alternateTitle) => {
if ((alternateTitle.seasonNumber === -1 || alternateTitle.seasonNumber === undefined) &&
(alternateTitle.sceneSeasonNumber === -1 || alternateTitle.sceneSeasonNumber === undefined)) {
acc.push(alternateTitle.title);
}
return acc;
}, []);
return {
...author,
isSaving: authors.isSaving,
alternateTitles,
isSmallScreen: dimensions.isSmallScreen
};
}
);
}
const mapDispatchToProps = {
toggleAuthorMonitored
};
class AuthorDetailsHeaderConnector extends Component {
//
// Listeners
onMonitorTogglePress = (monitored) => {
this.props.toggleAuthorMonitored({
authorId: this.props.authorId,
monitored
});
}
//
// Render
render() {
return (
<AuthorDetailsHeader
{...this.props}
onMonitorTogglePress={this.onMonitorTogglePress}
/>
);
}
}
AuthorDetailsHeaderConnector.propTypes = {
authorId: PropTypes.number.isRequired,
toggleAuthorMonitored: PropTypes.func.isRequired
};
export default connect(createMapStateToProps, mapDispatchToProps)(AuthorDetailsHeaderConnector);

View File

@@ -7,8 +7,9 @@ import { createSelector } from 'reselect';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import NotFound from 'Components/NotFound';
import PageContent from 'Components/Page/PageContent';
import PageContentBodyConnector from 'Components/Page/PageContentBodyConnector';
import PageContentBody from 'Components/Page/PageContentBody';
import getErrorMessage from 'Utilities/Object/getErrorMessage';
import translate from 'Utilities/String/translate';
import AuthorDetailsConnector from './AuthorDetailsConnector';
import styles from './AuthorDetails.css';
@@ -74,9 +75,9 @@ class AuthorDetailsPageConnector extends Component {
if (isFetching && !isPopulated) {
return (
<PageContent title='loading'>
<PageContentBodyConnector>
<PageContentBody>
<LoadingIndicator />
</PageContentBodyConnector>
</PageContentBody>
</PageContent>
);
}
@@ -92,7 +93,7 @@ class AuthorDetailsPageConnector extends Component {
if (!titleSlug) {
return (
<NotFound
message="Sorry, that author cannot be found."
message={translate('SorryThatAuthorCannotBeFound')}
/>
);
}

View File

@@ -4,6 +4,7 @@ import React, { Component } from 'react';
import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody';
import { sortDirections } from 'Helpers/Props';
import hasDifferentItemsOrOrder from 'Utilities/Object/hasDifferentItemsOrOrder';
import getToggledRange from 'Utilities/Table/getToggledRange';
import BookRowConnector from './BookRowConnector';
import styles from './AuthorDetailsSeason.css';
@@ -21,6 +22,26 @@ class AuthorDetailsSeason extends Component {
};
}
componentDidMount() {
this.props.setSelectedState(this.props.items);
}
componentDidUpdate(prevProps) {
const {
items,
sortKey,
sortDirection,
setSelectedState
} = this.props;
if (sortKey !== prevProps.sortKey ||
sortDirection !== prevProps.sortDirection ||
hasDifferentItemsOrOrder(prevProps.items, items)
) {
setSelectedState(items);
}
}
//
// Listeners
@@ -42,26 +63,42 @@ class AuthorDetailsSeason extends Component {
this.props.onMonitorBookPress(_.uniq(bookIds), monitored);
}
onSelectedChange = ({ id, value, shiftKey = false }) => {
const {
onSelectedChange,
items
} = this.props;
return onSelectedChange(items, id, value, shiftKey);
}
//
// Render
render() {
const {
items,
isEditorActive,
columns,
sortKey,
sortDirection,
onSortPress,
onTableOptionChange
onTableOptionChange,
selectedState
} = this.props;
let titleColumns = columns;
if (!isEditorActive) {
titleColumns = columns.filter((x) => x.name !== 'select');
}
return (
<div
className={styles.bookType}
>
<div className={styles.books}>
<Table
columns={columns}
columns={titleColumns}
sortKey={sortKey}
sortDirection={sortDirection}
onSortPress={onSortPress}
@@ -76,6 +113,9 @@ class AuthorDetailsSeason extends Component {
columns={columns}
{...item}
onMonitorBookPress={this.onMonitorBookPress}
isEditorActive={isEditorActive}
isSelected={selectedState[item.id]}
onSelectedChange={this.onSelectedChange}
/>
);
})
@@ -92,9 +132,13 @@ AuthorDetailsSeason.propTypes = {
sortKey: PropTypes.string,
sortDirection: PropTypes.oneOf(sortDirections.all),
items: PropTypes.arrayOf(PropTypes.object).isRequired,
isEditorActive: PropTypes.bool.isRequired,
selectedState: PropTypes.object.isRequired,
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
onTableOptionChange: PropTypes.func.isRequired,
onExpandPress: PropTypes.func.isRequired,
setSelectedState: PropTypes.func.isRequired,
onSelectedChange: PropTypes.func.isRequired,
onSortPress: PropTypes.func.isRequired,
onMonitorBookPress: PropTypes.func.isRequired,
uiSettings: PropTypes.object.isRequired

View File

@@ -4,24 +4,22 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { setBooksSort, setBooksTableOption, toggleBooksMonitored } from 'Store/Actions/bookActions';
import { setAuthorDetailsId, setAuthorDetailsSort } from 'Store/Actions/authorDetailsActions';
import { setBooksTableOption, toggleBooksMonitored } from 'Store/Actions/bookActions';
import { executeCommand } from 'Store/Actions/commandActions';
import createAuthorSelector from 'Store/Selectors/createAuthorSelector';
import createClientSideCollectionSelector from 'Store/Selectors/createClientSideCollectionSelector';
import createCommandsSelector from 'Store/Selectors/createCommandsSelector';
import createDimensionsSelector from 'Store/Selectors/createDimensionsSelector';
import createUISettingsSelector from 'Store/Selectors/createUISettingsSelector';
import AuthorDetailsSeason from './AuthorDetailsSeason';
function createMapStateToProps() {
return createSelector(
(state, { label }) => label,
createClientSideCollectionSelector('books'),
createClientSideCollectionSelector('books', 'authorDetails'),
createAuthorSelector(),
createCommandsSelector(),
createDimensionsSelector(),
createUISettingsSelector(),
(label, books, author, commands, dimensions, uiSettings) => {
(books, author, dimensions, uiSettings) => {
const booksInGroup = books.items;
@@ -47,14 +45,22 @@ function createMapStateToProps() {
}
const mapDispatchToProps = {
setAuthorDetailsId,
setAuthorDetailsSort,
toggleBooksMonitored,
setBooksTableOption,
dispatchSetBookSort: setBooksSort,
executeCommand
};
class AuthorDetailsSeasonConnector extends Component {
//
// Lifecycle
componentDidMount() {
this.props.setAuthorDetailsId({ authorId: this.props.authorId });
}
//
// Listeners
@@ -63,7 +69,7 @@ class AuthorDetailsSeasonConnector extends Component {
}
onSortPress = (sortKey) => {
this.props.dispatchSetBookSort({ sortKey });
this.props.setAuthorDetailsSort({ sortKey });
}
onMonitorBookPress = (bookIds, monitored) => {
@@ -92,7 +98,8 @@ AuthorDetailsSeasonConnector.propTypes = {
authorId: PropTypes.number.isRequired,
toggleBooksMonitored: PropTypes.func.isRequired,
setBooksTableOption: PropTypes.func.isRequired,
dispatchSetBookSort: PropTypes.func.isRequired,
setAuthorDetailsId: PropTypes.func.isRequired,
setAuthorDetailsSort: PropTypes.func.isRequired,
executeCommand: PropTypes.func.isRequired
};

View File

@@ -100,12 +100,6 @@
composes: actionButton;
margin-right: 15px;
/* position: absolute; */
/* top: 50%; */
/* left: 90%; */
/* margin-top: -12px; */
/* margin-left: -15px; */
}
.noBooks {

View File

@@ -8,6 +8,7 @@ import MonitorToggleButton from 'Components/MonitorToggleButton';
import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody';
import { icons, sortDirections } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import getToggledRange from 'Utilities/Table/getToggledRange';
import BookRowConnector from './BookRowConnector';
import styles from './AuthorDetailsSeries.css';
@@ -152,7 +153,7 @@ class AuthorDetailsSeries extends Component {
<Icon
className={styles.expandButtonIcon}
name={isExpanded ? icons.COLLAPSE : icons.EXPAND}
title={isExpanded ? 'Hide books' : 'Show books'}
title={isExpanded ? translate('IsExpandedHideBooks') : translate('IsExpandedShowBooks')}
size={24}
/>
@@ -198,7 +199,7 @@ class AuthorDetailsSeries extends Component {
iconClassName={styles.collapseButtonIcon}
name={icons.COLLAPSE}
size={20}
title="Hide books"
title={translate('HideBooks')}
onPress={this.onExpandPress}
/>
</div>

View File

@@ -4,13 +4,12 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { setBooksTableOption, toggleBooksMonitored } from 'Store/Actions/bookActions';
import { toggleBooksMonitored } from 'Store/Actions/bookActions';
import { executeCommand } from 'Store/Actions/commandActions';
import { setSeriesSort } from 'Store/Actions/seriesActions';
import { setSeriesSort, setSeriesTableOption } from 'Store/Actions/seriesActions';
import createAuthorSelector from 'Store/Selectors/createAuthorSelector';
import createCommandsSelector from 'Store/Selectors/createCommandsSelector';
import createDimensionsSelector from 'Store/Selectors/createDimensionsSelector';
// import createClientSideCollectionSelector from 'Store/Selectors/createClientSideCollectionSelector';
import createUISettingsSelector from 'Store/Selectors/createUISettingsSelector';
import AuthorDetailsSeries from './AuthorDetailsSeries';
@@ -70,7 +69,7 @@ function createMapStateToProps() {
const mapDispatchToProps = {
toggleBooksMonitored,
setBooksTableOption,
setSeriesTableOption,
dispatchSetSeriesSort: setSeriesSort,
executeCommand
};
@@ -81,7 +80,7 @@ class AuthorDetailsSeasonConnector extends Component {
// Listeners
onTableOptionChange = (payload) => {
this.props.setBooksTableOption(payload);
this.props.setSeriesTableOption(payload);
}
onSortPress = (sortKey) => {
@@ -113,7 +112,7 @@ class AuthorDetailsSeasonConnector extends Component {
AuthorDetailsSeasonConnector.propTypes = {
authorId: PropTypes.number.isRequired,
toggleBooksMonitored: PropTypes.func.isRequired,
setBooksTableOption: PropTypes.func.isRequired,
setSeriesTableOption: PropTypes.func.isRequired,
dispatchSetSeriesSort: PropTypes.func.isRequired,
executeCommand: PropTypes.func.isRequired
};

View File

@@ -1,7 +1,5 @@
.title {
composes: cell from '~Components/Table/Cells/TableRowCell.css';
white-space: nowrap;
}
.monitored {
@@ -10,8 +8,22 @@
width: 42px;
}
.position,
.rating,
.status {
composes: cell from '~Components/Table/Cells/TableRowCell.css';
width: 100px;
}
.releaseDate {
composes: cell from '~Components/Table/Cells/TableRowCell.css';
width: 120px;
}
.pageCount {
composes: cell from '~Components/Table/Cells/TableRowCell.css';
width: 80px;
}

View File

@@ -2,27 +2,15 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import BookSearchCellConnector from 'Book/BookSearchCellConnector';
import BookTitleLink from 'Book/BookTitleLink';
import Label from 'Components/Label';
import MonitorToggleButton from 'Components/MonitorToggleButton';
import StarRating from 'Components/StarRating';
import RelativeDateCellConnector from 'Components/Table/Cells/RelativeDateCellConnector';
import TableRowCell from 'Components/Table/Cells/TableRowCell';
import TableSelectCell from 'Components/Table/Cells/TableSelectCell';
import TableRow from 'Components/Table/TableRow';
import { kinds, sizes } from 'Helpers/Props';
import BookStatus from './BookStatus';
import styles from './BookRow.css';
function getBookCountKind(monitored, bookFileCount, bookCount) {
if (bookFileCount === bookCount && bookCount > 0) {
return kinds.SUCCESS;
}
if (!monitored) {
return kinds.WARNING;
}
return kinds.DANGER;
}
class BookRow extends Component {
//
@@ -68,7 +56,6 @@ class BookRow extends Component {
id,
authorId,
monitored,
statistics,
releaseDate,
title,
seriesTitle,
@@ -78,14 +65,15 @@ class BookRow extends Component {
isSaving,
authorMonitored,
titleSlug,
bookFiles,
isEditorActive,
isSelected,
onSelectedChange,
columns
} = this.props;
const {
bookCount,
bookFileCount,
totalBookCount
} = statistics;
const bookFile = bookFiles[0];
const isAvailable = Date.parse(releaseDate) < new Date();
return (
<TableRow>
@@ -100,6 +88,18 @@ class BookRow extends Component {
return null;
}
if (isEditorActive && name === 'select') {
return (
<TableSelectCell
key={name}
id={id}
isSelected={isSelected}
isDisabled={false}
onSelectedChange={onSelectedChange}
/>
);
}
if (name === 'monitored') {
return (
<TableRowCell
@@ -145,7 +145,7 @@ class BookRow extends Component {
return (
<TableRowCell
key={name}
className={styles.title}
className={styles.position}
>
{position || ''}
</TableRowCell>
@@ -154,7 +154,10 @@ class BookRow extends Component {
if (name === 'rating') {
return (
<TableRowCell key={name}>
<TableRowCell
key={name}
className={styles.rating}
>
{
<StarRating
rating={ratings.value}
@@ -168,6 +171,7 @@ class BookRow extends Component {
if (name === 'releaseDate') {
return (
<RelativeDateCellConnector
className={styles.releaseDate}
key={name}
date={releaseDate}
/>
@@ -178,6 +182,7 @@ class BookRow extends Component {
return (
<TableRowCell
key={name}
className={styles.pageCount}
>
{pageCount || ''}
</TableRowCell>
@@ -190,15 +195,11 @@ class BookRow extends Component {
key={name}
className={styles.status}
>
<Label
title={`${totalBookCount} books total. ${bookFileCount} books with files.`}
kind={getBookCountKind(monitored, bookFileCount, bookCount)}
size={sizes.MEDIUM}
>
{
<span>{bookFileCount} / {bookCount}</span>
}
</Label>
<BookStatus
isAvailable={isAvailable}
monitored={monitored}
bookFile={bookFile}
/>
</TableRowCell>
);
}
@@ -228,22 +229,18 @@ BookRow.propTypes = {
releaseDate: PropTypes.string,
title: PropTypes.string.isRequired,
seriesTitle: PropTypes.string.isRequired,
position: PropTypes.number,
position: PropTypes.string,
pageCount: PropTypes.number,
ratings: PropTypes.object.isRequired,
titleSlug: PropTypes.string.isRequired,
isSaving: PropTypes.bool,
authorMonitored: PropTypes.bool.isRequired,
statistics: PropTypes.object.isRequired,
bookFiles: PropTypes.arrayOf(PropTypes.object).isRequired,
isEditorActive: PropTypes.bool.isRequired,
isSelected: PropTypes.bool,
onSelectedChange: PropTypes.func.isRequired,
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
onMonitorBookPress: PropTypes.func.isRequired
};
BookRow.defaultProps = {
statistics: {
bookCount: 0,
bookFileCount: 0
}
};
export default BookRow;

View File

@@ -2,17 +2,38 @@
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import createAuthorSelector from 'Store/Selectors/createAuthorSelector';
import createBookFileSelector from 'Store/Selectors/createBookFileSelector';
import BookRow from './BookRow';
const selectBookFiles = createSelector(
(state) => state.bookFiles,
(bookFiles) => {
const {
items
} = bookFiles;
const bookFileDict = items.reduce((acc, file) => {
const bookId = file.bookId;
if (!acc.hasOwnProperty(bookId)) {
acc[bookId] = [];
}
acc[bookId].push(file);
return acc;
}, {});
return bookFileDict;
}
);
function createMapStateToProps() {
return createSelector(
createAuthorSelector(),
createBookFileSelector(),
(author = {}, bookFile) => {
selectBookFiles,
(state, { id }) => id,
(author = {}, bookFiles, bookId) => {
return {
authorMonitored: author.monitored,
bookFilePath: bookFile ? bookFile.path : null
bookFiles: bookFiles[bookId] ?? []
};
}
);

View File

@@ -1,3 +1,4 @@
.center {
display: flex;
justify-content: center;

View File

@@ -0,0 +1,78 @@
import PropTypes from 'prop-types';
import React from 'react';
import BookQuality from 'Book/BookQuality';
import Label from 'Components/Label';
import { kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import styles from './BookStatus.css';
function BookStatus(props) {
const {
isAvailable,
monitored,
bookFile
} = props;
const hasBookFile = !!bookFile;
if (hasBookFile) {
const quality = bookFile.quality;
return (
<div className={styles.center}>
<BookQuality
title={quality.quality.name}
size={bookFile.size}
quality={quality}
isMonitored={monitored}
isCutoffNotMet={bookFile.qualityCutoffNotMet}
/>
</div>
);
}
if (!monitored) {
return (
<div className={styles.center}>
<Label
title={translate('NotMonitored')}
kind={kinds.WARNING}
>
{translate('NotMonitored')}
</Label>
</div>
);
}
if (isAvailable) {
return (
<div className={styles.center}>
<Label
title={translate('BookAvailableButMissing')}
kind={kinds.DANGER}
>
{translate('Missing')}
</Label>
</div>
);
}
return (
<div className={styles.center}>
<Label
title={translate('NotAvailable')}
kind={kinds.INFO}
>
{translate('NotAvailable')}
</Label>
</div>
);
}
BookStatus.propTypes = {
isAvailable: PropTypes.bool,
monitored: PropTypes.bool.isRequired,
bookFile: PropTypes.object
};
export default BookStatus;

View File

@@ -1,6 +1,7 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import AuthorMetadataProfilePopoverContent from 'AddAuthor/AuthorMetadataProfilePopoverContent';
import AuthorMonitorNewItemsOptionsPopoverContent from 'AddAuthor/AuthorMonitorNewItemsOptionsPopoverContent';
import MoveAuthorModal from 'Author/MoveAuthor/MoveAuthorModal';
import Form from 'Components/Form/Form';
import FormGroup from 'Components/Form/FormGroup';
@@ -15,6 +16,7 @@ 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 translate from 'Utilities/String/translate';
import styles from './EditAuthorModalContent.css';
class EditAuthorModalContent extends Component {
@@ -72,6 +74,7 @@ class EditAuthorModalContent extends Component {
const {
monitored,
monitorNewItems,
qualityProfileId,
metadataProfileId,
path,
@@ -87,19 +90,48 @@ class EditAuthorModalContent extends Component {
<ModalBody>
<Form {...otherProps}>
<FormGroup>
<FormLabel>Monitored</FormLabel>
<FormLabel>
{translate('Monitored')}
</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="monitored"
helpText="Download monitored books from this author"
helpText={translate('MonitoredHelpText')}
{...monitored}
onChange={onInputChange}
/>
</FormGroup>
<FormGroup>
<FormLabel>Quality Profile</FormLabel>
<FormLabel>
{translate('MonitorNewItems')}
<Popover
anchor={
<Icon
className={styles.labelIcon}
name={icons.INFO}
/>
}
title={translate('MonitorNewItems')}
body={<AuthorMonitorNewItemsOptionsPopoverContent />}
position={tooltipPositions.RIGHT}
/>
</FormLabel>
<FormInputGroup
type={inputTypes.MONITOR_NEW_ITEMS_SELECT}
name="monitorNewItems"
helpText={translate('MonitorNewItemsHelpText')}
{...monitorNewItems}
onChange={onInputChange}
/>
</FormGroup>
<FormGroup>
<FormLabel>
{translate('QualityProfile')}
</FormLabel>
<FormInputGroup
type={inputTypes.QUALITY_PROFILE_SELECT}
@@ -122,7 +154,7 @@ class EditAuthorModalContent extends Component {
name={icons.INFO}
/>
}
title="Metadata Profile"
title={translate('MetadataProfile')}
body={<AuthorMetadataProfilePopoverContent />}
position={tooltipPositions.RIGHT}
/>
@@ -132,7 +164,7 @@ class EditAuthorModalContent extends Component {
<FormInputGroup
type={inputTypes.METADATA_PROFILE_SELECT}
name="metadataProfileId"
helpText="Changes will take place on next author refresh"
helpText={translate('MetadataProfileIdHelpText')}
includeNone={true}
{...metadataProfileId}
onChange={onInputChange}
@@ -141,7 +173,9 @@ class EditAuthorModalContent extends Component {
}
<FormGroup>
<FormLabel>Path</FormLabel>
<FormLabel>
{translate('Path')}
</FormLabel>
<FormInputGroup
type={inputTypes.PATH}
@@ -152,7 +186,9 @@ class EditAuthorModalContent extends Component {
</FormGroup>
<FormGroup>
<FormLabel>Tags</FormLabel>
<FormLabel>
{translate('Tags')}
</FormLabel>
<FormInputGroup
type={inputTypes.TAG}

View File

@@ -39,6 +39,7 @@ function createMapStateToProps() {
const authorSettings = _.pick(author, [
'monitored',
'monitorNewItems',
'qualityProfileId',
'metadataProfileId',
'path',

View File

@@ -6,3 +6,25 @@
margin-top: 20px;
margin-bottom: 10px;
}
.searchForNewBookLabelContainer {
display: flex;
margin-top: 2px;
}
.searchForNewBookLabel {
margin-right: 8px;
font-weight: normal;
}
.searchForNewBookContainer {
composes: container from '~Components/Form/CheckInput.css';
flex: 0 1 0;
}
.searchForNewBookInput {
composes: input from '~Components/Form/CheckInput.css';
margin-top: 0;
}

View File

@@ -1,6 +1,7 @@
import PropTypes from 'prop-types';
import React from 'react';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import CheckInput from 'Components/Form/CheckInput';
import Icon from 'Components/Icon';
import Button from 'Components/Link/Button';
import ModalBody from 'Components/Modal/ModalBody';
@@ -10,58 +11,114 @@ import ModalHeader from 'Components/Modal/ModalHeader';
import { icons, kinds } from 'Helpers/Props';
import styles from './RetagAuthorModalContent.css';
function RetagAuthorModalContent(props) {
const {
authorNames,
onModalClose,
onRetagAuthorPress
} = props;
class RetagAuthorModalContent extends Component {
return (
<ModalContent onModalClose={onModalClose}>
<ModalHeader>
Retag Selected Author
</ModalHeader>
//
// Lifecycle
<ModalBody>
<Alert>
Tip: To preview the tags that will be written... select "Cancel" then click any author name and use the
<Icon
className={styles.retagIcon}
name={icons.RETAG}
/>
</Alert>
constructor(props, context) {
super(props, context);
<div className={styles.message}>
Are you sure you want to re-tag all files in the {authorNames.length} selected author?
</div>
<ul>
{
authorNames.map((authorName) => {
return (
<li key={authorName}>
{authorName}
</li>
);
})
}
</ul>
</ModalBody>
this.state = {
updateCovers: false,
embedMetadata: false
};
}
<ModalFooter>
<Button onPress={onModalClose}>
Cancel
</Button>
//
// Listeners
<Button
kind={kinds.DANGER}
onPress={onRetagAuthorPress}
>
Retag
</Button>
</ModalFooter>
</ModalContent>
);
onCheckInputChange = ({ name, value }) => {
this.setState({ [name]: value });
}
onRetagAuthorPress = () => {
this.props.onRetagAuthorPress(this.state.updateCovers, this.state.embedMetadata);
}
//
// Render
render() {
const {
authorNames,
onModalClose
} = this.props;
return (
<ModalContent onModalClose={onModalClose}>
<ModalHeader>
Retag Selected Author
</ModalHeader>
<ModalBody>
<Alert>
Tip: To preview the tags that will be written... select "Cancel" then click any author name and use the
<Icon
className={styles.retagIcon}
name={icons.RETAG}
/>
</Alert>
<div className={styles.message}>
Are you sure you want to re-tag all files in the {authorNames.length} selected author?
</div>
<ul>
{
authorNames.map((authorName) => {
return (
<li key={authorName}>
{authorName}
</li>
);
})
}
</ul>
</ModalBody>
<ModalFooter>
<label className={styles.searchForNewBookLabelContainer}>
<span className={styles.searchForNewBookLabel}>
Update Covers
</span>
<CheckInput
containerClassName={styles.searchForNewBookContainer}
className={styles.searchForNewBookInput}
name="updateCovers"
value={this.state.updateCovers}
onChange={this.onCheckInputChange}
/>
</label>
<label className={styles.searchForNewBookLabelContainer}>
<span className={styles.searchForNewBookLabel}>
Embed Metadata
</span>
<CheckInput
containerClassName={styles.searchForNewBookContainer}
className={styles.searchForNewBookInput}
name="embedMetadata"
value={this.state.embedMetadata}
onChange={this.onCheckInputChange}
/>
</label>
<Button onPress={onModalClose}>
Cancel
</Button>
<Button
kind={kinds.DANGER}
onPress={this.onRetagAuthorPress}
>
Retag
</Button>
</ModalFooter>
</ModalContent>
);
}
}
RetagAuthorModalContent.propTypes = {

View File

@@ -36,10 +36,12 @@ class RetagAuthorModalContentConnector extends Component {
//
// Listeners
onRetagAuthorPress = () => {
onRetagAuthorPress = (updateCovers, embedMetadata) => {
this.props.executeCommand({
name: commandNames.RETAG_AUTHOR,
authorIds: this.props.authorIds
authorIds: this.props.authorIds,
updateCovers,
embedMetadata
});
this.props.onModalClose(true);

View File

@@ -1,303 +0,0 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import NoAuthor from 'Author/NoAuthor';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import FilterMenu from 'Components/Menu/FilterMenu';
import PageContent from 'Components/Page/PageContent';
import PageContentBodyConnector from 'Components/Page/PageContentBodyConnector';
import PageToolbar from 'Components/Page/Toolbar/PageToolbar';
import PageToolbarSection from 'Components/Page/Toolbar/PageToolbarSection';
import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody';
import { align, sortDirections } from 'Helpers/Props';
import getErrorMessage from 'Utilities/Object/getErrorMessage';
import getSelectedIds from 'Utilities/Table/getSelectedIds';
import selectAll from 'Utilities/Table/selectAll';
import toggleSelected from 'Utilities/Table/toggleSelected';
import RetagAuthorModal from './AudioTags/RetagAuthorModal';
import AuthorEditorFilterModalConnector from './AuthorEditorFilterModalConnector';
import AuthorEditorFooter from './AuthorEditorFooter';
import AuthorEditorRowConnector from './AuthorEditorRowConnector';
import OrganizeAuthorModal from './Organize/OrganizeAuthorModal';
function getColumns(showMetadataProfile) {
return [
{
name: 'status',
isSortable: true,
isVisible: true
},
{
name: 'sortName',
label: 'Name',
isSortable: true,
isVisible: true
},
{
name: 'qualityProfileId',
label: 'Quality Profile',
isSortable: true,
isVisible: true
},
{
name: 'metadataProfileId',
label: 'Metadata Profile',
isSortable: true,
isVisible: showMetadataProfile
},
{
name: 'path',
label: 'Path',
isSortable: true,
isVisible: true
},
{
name: 'tags',
label: 'Tags',
isSortable: false,
isVisible: true
}
];
}
class AuthorEditor extends Component {
//
// Lifecycle
constructor(props, context) {
super(props, context);
this.state = {
allSelected: false,
allUnselected: false,
lastToggled: null,
selectedState: {},
isOrganizingAuthorModalOpen: false,
isRetaggingAuthorModalOpen: false,
columns: getColumns(props.showMetadataProfile)
};
}
componentDidUpdate(prevProps) {
const {
isDeleting,
deleteError
} = this.props;
const hasFinishedDeleting = prevProps.isDeleting &&
!isDeleting &&
!deleteError;
if (hasFinishedDeleting) {
this.onSelectAllChange({ value: false });
}
}
//
// Control
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);
});
}
onSaveSelected = (changes) => {
this.props.onSaveSelected({
authorIds: this.getSelectedIds(),
...changes
});
}
onOrganizeAuthorPress = () => {
this.setState({ isOrganizingAuthorModalOpen: true });
}
onOrganizeAuthorModalClose = (organized) => {
this.setState({ isOrganizingAuthorModalOpen: false });
if (organized === true) {
this.onSelectAllChange({ value: false });
}
}
onRetagAuthorPress = () => {
this.setState({ isRetaggingAuthorModalOpen: true });
}
onRetagAuthorModalClose = (organized) => {
this.setState({ isRetaggingAuthorModalOpen: false });
if (organized === true) {
this.onSelectAllChange({ value: false });
}
}
//
// Render
render() {
const {
isFetching,
isPopulated,
error,
totalItems,
items,
selectedFilterKey,
filters,
customFilters,
sortKey,
sortDirection,
isSaving,
saveError,
isDeleting,
deleteError,
isOrganizingAuthor,
isRetaggingAuthor,
showMetadataProfile,
onSortPress,
onFilterSelect
} = this.props;
const {
allSelected,
allUnselected,
selectedState,
columns
} = this.state;
const selectedAuthorIds = this.getSelectedIds();
return (
<PageContent title="Author Editor">
<PageToolbar>
<PageToolbarSection />
<PageToolbarSection alignContent={align.RIGHT}>
<FilterMenu
alignMenu={align.RIGHT}
selectedFilterKey={selectedFilterKey}
filters={filters}
customFilters={customFilters}
filterModalConnectorComponent={AuthorEditorFilterModalConnector}
onFilterSelect={onFilterSelect}
/>
</PageToolbarSection>
</PageToolbar>
<PageContentBodyConnector>
{
isFetching && !isPopulated &&
<LoadingIndicator />
}
{
!isFetching && !!error &&
<div>{getErrorMessage(error, 'Failed to load author from API')}</div>
}
{
!error && isPopulated && !!items.length &&
<div>
<Table
columns={columns}
sortKey={sortKey}
sortDirection={sortDirection}
selectAll={true}
allSelected={allSelected}
allUnselected={allUnselected}
onSortPress={onSortPress}
onSelectAllChange={this.onSelectAllChange}
>
<TableBody>
{
items.map((item) => {
return (
<AuthorEditorRowConnector
key={item.id}
{...item}
columns={columns}
isSelected={selectedState[item.id]}
onSelectedChange={this.onSelectedChange}
/>
);
})
}
</TableBody>
</Table>
</div>
}
{
!error && isPopulated && !items.length &&
<NoAuthor totalItems={totalItems} />
}
</PageContentBodyConnector>
<AuthorEditorFooter
authorIds={selectedAuthorIds}
selectedCount={selectedAuthorIds.length}
isSaving={isSaving}
saveError={saveError}
isDeleting={isDeleting}
deleteError={deleteError}
isOrganizingAuthor={isOrganizingAuthor}
isRetaggingAuthor={isRetaggingAuthor}
showMetadataProfile={showMetadataProfile}
onSaveSelected={this.onSaveSelected}
onOrganizeAuthorPress={this.onOrganizeAuthorPress}
onRetagAuthorPress={this.onRetagAuthorPress}
/>
<OrganizeAuthorModal
isOpen={this.state.isOrganizingAuthorModalOpen}
authorIds={selectedAuthorIds}
onModalClose={this.onOrganizeAuthorModalClose}
/>
<RetagAuthorModal
isOpen={this.state.isRetaggingAuthorModalOpen}
authorIds={selectedAuthorIds}
onModalClose={this.onRetagAuthorModalClose}
/>
</PageContent>
);
}
}
AuthorEditor.propTypes = {
isFetching: PropTypes.bool.isRequired,
isPopulated: PropTypes.bool.isRequired,
error: PropTypes.object,
totalItems: PropTypes.number.isRequired,
items: PropTypes.arrayOf(PropTypes.object).isRequired,
sortKey: PropTypes.string,
sortDirection: PropTypes.oneOf(sortDirections.all),
selectedFilterKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
filters: PropTypes.arrayOf(PropTypes.object).isRequired,
customFilters: PropTypes.arrayOf(PropTypes.object).isRequired,
isSaving: PropTypes.bool.isRequired,
saveError: PropTypes.object,
isDeleting: PropTypes.bool.isRequired,
deleteError: PropTypes.object,
isOrganizingAuthor: PropTypes.bool.isRequired,
isRetaggingAuthor: PropTypes.bool.isRequired,
showMetadataProfile: PropTypes.bool.isRequired,
onSortPress: PropTypes.func.isRequired,
onFilterSelect: PropTypes.func.isRequired,
onSaveSelected: PropTypes.func.isRequired
};
export default AuthorEditor;

View File

@@ -1,92 +0,0 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import * as commandNames from 'Commands/commandNames';
import { saveAuthorEditor, setAuthorEditorFilter, setAuthorEditorSort } from 'Store/Actions/authorEditorActions';
import { executeCommand } from 'Store/Actions/commandActions';
import { fetchRootFolders } from 'Store/Actions/settingsActions';
import createClientSideCollectionSelector from 'Store/Selectors/createClientSideCollectionSelector';
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
import AuthorEditor from './AuthorEditor';
function createMapStateToProps() {
return createSelector(
(state) => state.settings.metadataProfiles,
createClientSideCollectionSelector('authors', 'authorEditor'),
createCommandExecutingSelector(commandNames.RENAME_AUTHOR),
createCommandExecutingSelector(commandNames.RETAG_AUTHOR),
(metadataProfiles, author, isOrganizingAuthor, isRetaggingAuthor) => {
return {
isOrganizingAuthor,
isRetaggingAuthor,
showMetadataProfile: metadataProfiles.items.length > 1,
...author
};
}
);
}
const mapDispatchToProps = {
dispatchSetAuthorEditorSort: setAuthorEditorSort,
dispatchSetAuthorEditorFilter: setAuthorEditorFilter,
dispatchSaveAuthorEditor: saveAuthorEditor,
dispatchFetchRootFolders: fetchRootFolders,
dispatchExecuteCommand: executeCommand
};
class AuthorEditorConnector extends Component {
//
// Lifecycle
componentDidMount() {
this.props.dispatchFetchRootFolders();
}
//
// Listeners
onSortPress = (sortKey) => {
this.props.dispatchSetAuthorEditorSort({ sortKey });
}
onFilterSelect = (selectedFilterKey) => {
this.props.dispatchSetAuthorEditorFilter({ selectedFilterKey });
}
onSaveSelected = (payload) => {
this.props.dispatchSaveAuthorEditor(payload);
}
onMoveSelected = (payload) => {
this.props.dispatchExecuteCommand({
name: commandNames.MOVE_AUTHOR,
...payload
});
}
//
// Render
render() {
return (
<AuthorEditor
{...this.props}
onSortPress={this.onSortPress}
onFilterSelect={this.onFilterSelect}
onSaveSelected={this.onSaveSelected}
/>
);
}
}
AuthorEditorConnector.propTypes = {
dispatchSetAuthorEditorSort: PropTypes.func.isRequired,
dispatchSetAuthorEditorFilter: PropTypes.func.isRequired,
dispatchSaveAuthorEditor: PropTypes.func.isRequired,
dispatchFetchRootFolders: PropTypes.func.isRequired,
dispatchExecuteCommand: PropTypes.func.isRequired
};
export default connect(createMapStateToProps, mapDispatchToProps)(AuthorEditorConnector);

View File

@@ -1,11 +1,23 @@
.footer {
display: flex;
flex-direction: column;
flex-grow: 1;
}
.dropdownContainer {
display: flex;
flex-wrap: wrap;
margin-bottom: 10px;
}
.inputContainer {
flex: 1;
margin-right: 20px;
min-width: 150px;
}
.buttonContainer {
display: flex;
justify-content: flex-end;
flex-grow: 1;
}
@@ -24,12 +36,14 @@
composes: button from '~Components/Link/SpinnerButton.css';
margin-right: 10px;
margin-bottom: 10px;
height: 35px;
}
.deleteSelectedButton {
composes: button from '~Components/Link/SpinnerButton.css';
margin-bottom: 10px;
margin-left: 50px;
height: 35px;
}
@@ -48,6 +62,10 @@
}
@media only screen and (max-width: $breakpointSmall) {
.dropdownContainer {
display: block;
}
.inputContainer {
margin-right: 0;
}
@@ -61,6 +79,7 @@
}
.buttons {
display: block;
justify-content: space-between;
}

View File

@@ -2,12 +2,14 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import MoveAuthorModal from 'Author/MoveAuthor/MoveAuthorModal';
import MetadataProfileSelectInputConnector from 'Components/Form/MetadataProfileSelectInputConnector';
import MonitorNewItemsSelectInput from 'Components/Form/MonitorNewItemsSelectInput';
import QualityProfileSelectInputConnector from 'Components/Form/QualityProfileSelectInputConnector';
import RootFolderSelectInputConnector from 'Components/Form/RootFolderSelectInputConnector';
import SelectInput from 'Components/Form/SelectInput';
import SpinnerButton from 'Components/Link/SpinnerButton';
import PageContentFooter from 'Components/Page/PageContentFooter';
import { kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import AuthorEditorFooterLabel from './AuthorEditorFooterLabel';
import DeleteAuthorModal from './Delete/DeleteAuthorModal';
import TagsModal from './Tags/TagsModal';
@@ -25,6 +27,7 @@ class AuthorEditorFooter extends Component {
this.state = {
monitored: NO_CHANGE,
monitorNewItems: NO_CHANGE,
qualityProfileId: NO_CHANGE,
metadataProfileId: NO_CHANGE,
rootFolderPath: NO_CHANGE,
@@ -45,6 +48,7 @@ class AuthorEditorFooter extends Component {
if (prevProps.isSaving && !isSaving && !saveError) {
this.setState({
monitored: NO_CHANGE,
monitorNewItems: NO_CHANGE,
qualityProfileId: NO_CHANGE,
metadataProfileId: NO_CHANGE,
rootFolderPath: NO_CHANGE,
@@ -138,13 +142,13 @@ class AuthorEditorFooter extends Component {
isDeleting,
isOrganizingAuthor,
isRetaggingAuthor,
showMetadataProfile,
onOrganizeAuthorPress,
onRetagAuthorPress
} = this.props;
const {
monitored,
monitorNewItems,
qualityProfileId,
metadataProfileId,
rootFolderPath,
@@ -163,41 +167,58 @@ class AuthorEditorFooter extends Component {
return (
<PageContentFooter>
<div className={styles.inputContainer}>
<AuthorEditorFooterLabel
label="Monitor Author"
isSaving={isSaving && monitored !== NO_CHANGE}
/>
<SelectInput
name="monitored"
value={monitored}
values={monitoredOptions}
isDisabled={!selectedCount}
onChange={this.onInputChange}
/>
</div>
<div className={styles.inputContainer}>
<AuthorEditorFooterLabel
label="Quality Profile"
isSaving={isSaving && qualityProfileId !== NO_CHANGE}
/>
<QualityProfileSelectInputConnector
name="qualityProfileId"
value={qualityProfileId}
includeNoChange={true}
isDisabled={!selectedCount}
onChange={this.onInputChange}
/>
</div>
{
showMetadataProfile &&
<div className={styles.footer}>
<div className={styles.dropdownContainer}>
<div className={styles.inputContainer}>
<AuthorEditorFooterLabel
label="Metadata Profile"
label={translate('MonitorAuthor')}
isSaving={isSaving && monitored !== NO_CHANGE}
/>
<SelectInput
name="monitored"
value={monitored}
values={monitoredOptions}
isDisabled={!selectedCount}
onChange={this.onInputChange}
/>
</div>
<div className={styles.inputContainer}>
<AuthorEditorFooterLabel
label={translate('MonitorNewItems')}
isSaving={isSaving && monitored !== NO_CHANGE}
/>
<MonitorNewItemsSelectInput
name="monitorNewItems"
value={monitorNewItems}
includeNoChange={true}
isDisabled={!selectedCount}
onChange={this.onInputChange}
/>
</div>
<div className={styles.inputContainer}>
<AuthorEditorFooterLabel
label={translate('QualityProfile')}
isSaving={isSaving && qualityProfileId !== NO_CHANGE}
/>
<QualityProfileSelectInputConnector
name="qualityProfileId"
value={qualityProfileId}
includeNoChange={true}
isDisabled={!selectedCount}
onChange={this.onInputChange}
/>
</div>
<div
className={styles.inputContainer}
>
<AuthorEditorFooterLabel
label={translate('MetadataProfile')}
isSaving={isSaving && metadataProfileId !== NO_CHANGE}
/>
@@ -210,33 +231,35 @@ class AuthorEditorFooter extends Component {
onChange={this.onInputChange}
/>
</div>
}
<div className={styles.inputContainer}>
<AuthorEditorFooterLabel
label="Root Folder"
isSaving={isSaving && rootFolderPath !== NO_CHANGE}
/>
<div
className={styles.inputContainer}
>
<AuthorEditorFooterLabel
label={translate('RootFolder')}
isSaving={isSaving && rootFolderPath !== NO_CHANGE}
/>
<RootFolderSelectInputConnector
name="rootFolderPath"
value={rootFolderPath}
includeNoChange={true}
isDisabled={!selectedCount}
selectedValueOptions={{ includeFreeSpace: false }}
onChange={this.onInputChange}
/>
</div>
<RootFolderSelectInputConnector
name="rootFolderPath"
value={rootFolderPath}
includeNoChange={true}
isDisabled={!selectedCount}
selectedValueOptions={{ includeFreeSpace: false }}
onChange={this.onInputChange}
/>
</div>
</div>
<div className={styles.buttonContainer}>
<div className={styles.buttonContainerContent}>
<AuthorEditorFooterLabel
label={`${selectedCount} Author(s) Selected`}
isSaving={false}
/>
<div className={styles.buttonContainer}>
<div className={styles.buttonContainerContent}>
<AuthorEditorFooterLabel
label={translate('SelectedCountAuthorsSelectedInterp', [selectedCount])}
isSaving={false}
/>
<div className={styles.buttons}>
<div className={styles.buttons}>
<div>
<SpinnerButton
className={styles.organizeSelectedButton}
kind={kinds.WARNING}
@@ -244,7 +267,7 @@ class AuthorEditorFooter extends Component {
isDisabled={!selectedCount || isOrganizingAuthor || isRetaggingAuthor}
onPress={onOrganizeAuthorPress}
>
Rename Files
{translate('RenameFiles')}
</SpinnerButton>
<SpinnerButton
@@ -254,7 +277,7 @@ class AuthorEditorFooter extends Component {
isDisabled={!selectedCount || isOrganizingAuthor || isRetaggingAuthor}
onPress={onRetagAuthorPress}
>
Write Metadata Tags
{translate('WriteMetadataTags')}
</SpinnerButton>
<SpinnerButton
@@ -263,19 +286,20 @@ class AuthorEditorFooter extends Component {
isDisabled={!selectedCount || isOrganizingAuthor || isRetaggingAuthor}
onPress={this.onTagsPress}
>
Set Readarr Tags
{translate('SetReadarrTags')}
</SpinnerButton>
</div>
<SpinnerButton
className={styles.deleteSelectedButton}
kind={kinds.DANGER}
isSpinning={isDeleting}
isDisabled={!selectedCount || isDeleting}
onPress={this.onDeleteSelectedPress}
>
Delete
</SpinnerButton>
<SpinnerButton
className={styles.deleteSelectedButton}
kind={kinds.DANGER}
isSpinning={isDeleting}
isDisabled={!selectedCount || isDeleting}
onPress={this.onDeleteSelectedPress}
>
{translate('Delete')}
</SpinnerButton>
</div>
</div>
</div>
</div>

View File

@@ -1,4 +1,3 @@
import _ from 'lodash';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import AuthorNameLink from 'Author/AuthorNameLink';
@@ -7,6 +6,7 @@ import TableRowCell from 'Components/Table/Cells/TableRowCell';
import TableSelectCell from 'Components/Table/Cells/TableSelectCell';
import TableRow from 'Components/Table/TableRow';
import TagListConnector from 'Components/TagListConnector';
import formatBytes from 'Utilities/Number/formatBytes';
class AuthorEditorRow extends Component {
@@ -27,11 +27,11 @@ class AuthorEditorRow extends Component {
status,
titleSlug,
authorName,
authorType,
monitored,
metadataProfile,
qualityProfile,
path,
statistics,
tags,
columns,
isSelected,
@@ -46,39 +46,85 @@ class AuthorEditorRow extends Component {
onSelectedChange={onSelectedChange}
/>
<AuthorStatusCell
authorType={authorType}
monitored={monitored}
status={status}
/>
<TableRowCell>
<AuthorNameLink
titleSlug={titleSlug}
authorName={authorName}
/>
</TableRowCell>
<TableRowCell>
{qualityProfile.name}
</TableRowCell>
{
_.find(columns, { name: 'metadataProfileId' }).isVisible &&
<TableRowCell>
{metadataProfile.name}
</TableRowCell>
columns.map((column) => {
const {
name,
isVisible
} = column;
if (!isVisible) {
return null;
}
if (name === 'status') {
return (
<AuthorStatusCell
key={name}
monitored={monitored}
status={status}
/>
);
}
if (name === 'sortName') {
return (
<TableRowCell
key={name}
>
<AuthorNameLink
titleSlug={titleSlug}
authorName={authorName}
/>
</TableRowCell>
);
}
if (name === 'qualityProfileId') {
return (
<TableRowCell key={name}>
{qualityProfile.name}
</TableRowCell>
);
}
if (name === 'metadataProfileId') {
return (
<TableRowCell key={name}>
{metadataProfile.name}
</TableRowCell>
);
}
if (name === 'path') {
return (
<TableRowCell key={name}>
{path}
</TableRowCell>
);
}
if (name === 'sizeOnDisk') {
return (
<TableRowCell key={name}>
{formatBytes(statistics.sizeOnDisk)}
</TableRowCell>
);
}
if (name === 'tags') {
return (
<TableRowCell key={name}>
<TagListConnector
tags={tags}
/>
</TableRowCell>
);
}
return null;
})
}
<TableRowCell>
{path}
</TableRowCell>
<TableRowCell>
<TagListConnector
tags={tags}
/>
</TableRowCell>
</TableRow>
);
}
@@ -89,11 +135,11 @@ AuthorEditorRow.propTypes = {
status: PropTypes.string.isRequired,
titleSlug: PropTypes.string.isRequired,
authorName: PropTypes.string.isRequired,
authorType: PropTypes.string,
monitored: PropTypes.bool.isRequired,
metadataProfile: PropTypes.object.isRequired,
qualityProfile: PropTypes.object.isRequired,
path: PropTypes.string.isRequired,
statistics: PropTypes.object.isRequired,
tags: PropTypes.arrayOf(PropTypes.number).isRequired,
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
isSelected: PropTypes.bool,

View File

@@ -1,7 +1,7 @@
import _ from 'lodash';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { bulkDeleteAuthor } from 'Store/Actions/authorEditorActions';
import { bulkDeleteAuthor } from 'Store/Actions/authorIndexActions';
import createAllAuthorSelector from 'Store/Selectors/createAllAuthorsSelector';
import DeleteAuthorModalContent from './DeleteAuthorModalContent';

View File

@@ -25,7 +25,7 @@ function OrganizeAuthorModalContent(props) {
<ModalBody>
<Alert>
Tip: To preview a rename... select "Cancel" then click any author name and use the
Tip: To preview a rename, select "Cancel", then select any author name and use the
<Icon
className={styles.renameIcon}
name={icons.ORGANIZE}

View File

@@ -12,6 +12,7 @@ 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 './TagsModalContent.css';
class TagsModalContent extends Component {
@@ -74,7 +75,9 @@ class TagsModalContent extends Component {
<ModalBody>
<Form>
<FormGroup>
<FormLabel>Tags</FormLabel>
<FormLabel>
{translate('Tags')}
</FormLabel>
<FormInputGroup
type={inputTypes.TAG}
@@ -85,7 +88,9 @@ class TagsModalContent extends Component {
</FormGroup>
<FormGroup>
<FormLabel>Apply Tags</FormLabel>
<FormLabel>
{translate('ApplyTags')}
</FormLabel>
<FormInputGroup
type={inputTypes.SELECT}
@@ -93,17 +98,19 @@ class TagsModalContent extends Component {
value={applyTags}
values={applyTagsOptions}
helpTexts={[
'How to apply tags to the selected author',
'Add: Add the tags the existing list of tags',
'Remove: Remove the entered tags',
'Replace: Replace the tags with the entered tags (enter no tags to clear all tags)'
translate('ApplyTagsHelpTexts1'),
translate('ApplyTagsHelpTexts2'),
translate('ApplyTagsHelpTexts3'),
translate('ApplyTagsHelpTexts4')
]}
onChange={this.onInputChange}
/>
</FormGroup>
<FormGroup>
<FormLabel>Result</FormLabel>
<FormLabel>
{translate('Result')}
</FormLabel>
<div className={styles.result}>
{
@@ -120,7 +127,7 @@ class TagsModalContent extends Component {
return (
<Label
key={tag.id}
title={removeTag ? 'Removing tag' : 'Existing tag'}
title={removeTag ? translate('RemoveTagRemovingTag') : translate('RemoveTagExistingTag')}
kind={removeTag ? kinds.INVERSE : kinds.INFO}
size={sizes.LARGE}
>
@@ -146,7 +153,7 @@ class TagsModalContent extends Component {
return (
<Label
key={tag.id}
title={'Adding tag'}
title={translate('AddingTag')}
kind={kinds.SUCCESS}
size={sizes.LARGE}
>

View File

@@ -1,3 +1,9 @@
.sourceTitle {
composes: cell from '~Components/Table/Cells/TableRowCell.css';
word-break: break-word;
}
.details,
.actions {
composes: cell from '~Components/Table/Cells/TableRowCell.css';

View File

@@ -11,6 +11,7 @@ import TableRowCell from 'Components/Table/Cells/TableRowCell';
import TableRow from 'Components/Table/TableRow';
import Popover from 'Components/Tooltip/Popover';
import { icons, kinds, tooltipPositions } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import styles from './AuthorHistoryRow.css';
function getTitle(eventType) {
@@ -94,7 +95,7 @@ class AuthorHistoryRow extends Component {
{book.title}
</TableRowCell>
<TableRowCell>
<TableRowCell className={styles.sourceTitle}>
{sourceTitle}
</TableRowCell>
@@ -132,7 +133,7 @@ class AuthorHistoryRow extends Component {
{
eventType === 'grabbed' &&
<IconButton
title="Mark as failed"
title={translate('MarkAsFailed')}
name={icons.REMOVE}
onPress={this.onMarkAsFailedPress}
/>
@@ -142,9 +143,9 @@ class AuthorHistoryRow extends Component {
<ConfirmModal
isOpen={isMarkAsFailedModalOpen}
kind={kinds.DANGER}
title="Mark as Failed"
message={`Are you sure you want to mark '${sourceTitle}' as failed?`}
confirmLabel="Mark as Failed"
title={translate('MarkAsFailed')}
message={translate('MarkAsFailedMessageText', [sourceTitle])}
confirmLabel={translate('MarkAsFailed')}
onConfirm={this.onConfirmMarkAsFailed}
onCancel={this.onMarkAsFailedModalClose}
/>

View File

@@ -3,6 +3,7 @@ import React, { Component } from 'react';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody';
import translate from 'Utilities/String/translate';
import AuthorHistoryRowConnector from './AuthorHistoryRowConnector';
const columns = [
@@ -69,12 +70,16 @@ class AuthorHistoryTableContent extends Component {
{
!isFetching && !!error &&
<div>Unable to load history.</div>
<div>
{translate('UnableToLoadHistory')}
</div>
}
{
isPopulated && !hasItems && !error &&
<div>No history.</div>
<div>
{translate('NoHistory')}
</div>
}
{

View File

@@ -1,10 +1,13 @@
import _ from 'lodash';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import RetagAuthorModal from 'Author/Editor/AudioTags/RetagAuthorModal';
import AuthorEditorFooter from 'Author/Editor/AuthorEditorFooter';
import OrganizeAuthorModal from 'Author/Editor/Organize/OrganizeAuthorModal';
import NoAuthor from 'Author/NoAuthor';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import PageContent from 'Components/Page/PageContent';
import PageContentBodyConnector from 'Components/Page/PageContentBodyConnector';
import PageContentBody from 'Components/Page/PageContentBody';
import PageJumpBar from 'Components/Page/PageJumpBar';
import PageToolbar from 'Components/Page/Toolbar/PageToolbar';
import PageToolbarButton from 'Components/Page/Toolbar/PageToolbarButton';
@@ -14,9 +17,11 @@ import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptions
import { align, icons, sortDirections } from 'Helpers/Props';
import getErrorMessage from 'Utilities/Object/getErrorMessage';
import hasDifferentItemsOrOrder from 'Utilities/Object/hasDifferentItemsOrOrder';
import translate from 'Utilities/String/translate';
import getSelectedIds from 'Utilities/Table/getSelectedIds';
import selectAll from 'Utilities/Table/selectAll';
import toggleSelected from 'Utilities/Table/toggleSelected';
import AuthorIndexFooterConnector from './AuthorIndexFooterConnector';
import AuthorIndexBannersConnector from './Banners/AuthorIndexBannersConnector';
import AuthorIndexBannerOptionsModal from './Banners/Options/AuthorIndexBannerOptionsModal';
import AuthorIndexFilterMenu from './Menus/AuthorIndexFilterMenu';
import AuthorIndexSortMenu from './Menus/AuthorIndexSortMenu';
import AuthorIndexViewMenu from './Menus/AuthorIndexViewMenu';
@@ -33,10 +38,6 @@ function getViewComponent(view) {
return AuthorIndexPostersConnector;
}
if (view === 'banners') {
return AuthorIndexBannersConnector;
}
if (view === 'overview') {
return AuthorIndexOverviewsConnector;
}
@@ -57,13 +58,20 @@ class AuthorIndex extends Component {
jumpBarItems: { order: [] },
jumpToCharacter: null,
isPosterOptionsModalOpen: false,
isBannerOptionsModalOpen: false,
isOverviewOptionsModalOpen: false
isOverviewOptionsModalOpen: false,
isEditorActive: false,
isOrganizingAuthorModalOpen: false,
isRetaggingAuthorModalOpen: false,
allSelected: false,
allUnselected: false,
lastToggled: null,
selectedState: {}
};
}
componentDidMount() {
this.setJumpBarItems();
this.setSelectedState();
}
componentDidUpdate(prevProps) {
@@ -78,6 +86,7 @@ class AuthorIndex extends Component {
hasDifferentItemsOrOrder(prevProps.items, items)
) {
this.setJumpBarItems();
this.setSelectedState();
}
if (this.state.jumpToCharacter != null) {
@@ -92,6 +101,48 @@ class AuthorIndex extends Component {
this.setState({ scroller: ref });
}
getSelectedIds = () => {
if (this.state.allUnselected) {
return [];
}
return getSelectedIds(this.state.selectedState);
}
setSelectedState() {
const {
items
} = this.props;
const {
selectedState
} = this.state;
const newSelectedState = {};
items.forEach((author) => {
const isItemSelected = selectedState[author.id];
if (isItemSelected) {
newSelectedState[author.id] = isItemSelected;
} else {
newSelectedState[author.id] = false;
}
});
const selectedCount = getSelectedIds(newSelectedState).length;
const newStateCount = Object.keys(newSelectedState).length;
let isAllSelected = false;
let isAllUnselected = false;
if (selectedCount === 0) {
isAllUnselected = true;
} else if (selectedCount === newStateCount) {
isAllSelected = true;
}
this.setState({ selectedState: newSelectedState, allSelected: isAllSelected, allUnselected: isAllUnselected });
}
setJumpBarItems() {
const {
items,
@@ -100,13 +151,13 @@ class AuthorIndex extends Component {
} = this.props;
// Reset if not sorting by sortName
if (sortKey !== 'sortName') {
if (sortKey !== 'sortName' && sortKey !== 'sortNameLastFirst') {
this.setState({ jumpBarItems: { order: [] } });
return;
}
const characters = _.reduce(items, (acc, item) => {
let char = item.sortName.charAt(0);
let char = item[sortKey].charAt(0);
if (!isNaN(char)) {
char = '#';
@@ -147,14 +198,6 @@ class AuthorIndex extends Component {
this.setState({ isPosterOptionsModalOpen: false });
}
onBannerOptionsPress = () => {
this.setState({ isBannerOptionsModalOpen: true });
}
onBannerOptionsModalClose = () => {
this.setState({ isBannerOptionsModalOpen: false });
}
onOverviewOptionsPress = () => {
this.setState({ isOverviewOptionsModalOpen: true });
}
@@ -163,10 +206,72 @@ class AuthorIndex extends Component {
this.setState({ isOverviewOptionsModalOpen: false });
}
onEditorTogglePress = () => {
if (this.state.isEditorActive) {
this.setState({ isEditorActive: false });
} else {
const newState = selectAll(this.state.selectedState, false);
newState.isEditorActive = true;
this.setState(newState);
}
}
onJumpBarItemPress = (jumpToCharacter) => {
this.setState({ jumpToCharacter });
}
onSelectAllChange = ({ value }) => {
this.setState(selectAll(this.state.selectedState, value));
}
onSelectAllPress = () => {
this.onSelectAllChange({ value: !this.state.allSelected });
}
onSelectedChange = ({ id, value, shiftKey = false }) => {
this.setState((state) => {
return toggleSelected(state, this.props.items, id, value, shiftKey);
});
}
onSaveSelected = (changes) => {
this.props.onSaveSelected({
authorIds: this.getSelectedIds(),
...changes
});
}
onOrganizeAuthorPress = () => {
this.setState({ isOrganizingAuthorModalOpen: true });
}
onOrganizeAuthorModalClose = (organized) => {
this.setState({ isOrganizingAuthorModalOpen: false });
if (organized === true) {
this.onSelectAllChange({ value: false });
}
}
onRetagAuthorPress = () => {
this.setState({ isRetaggingAuthorModalOpen: true });
}
onRetagAuthorModalClose = (organized) => {
this.setState({ isRetaggingAuthorModalOpen: false });
if (organized === true) {
this.onSelectAllChange({ value: false });
}
}
onRefreshAuthorPress = () => {
const selectedIds = this.getSelectedIds();
const refreshIds = this.state.isEditorActive && selectedIds.length > 0 ? selectedIds : [];
this.props.onRefreshAuthorPress(refreshIds);
}
//
// Render
@@ -186,11 +291,16 @@ class AuthorIndex extends Component {
view,
isRefreshingAuthor,
isRssSyncExecuting,
isOrganizingAuthor,
isRetaggingAuthor,
isSaving,
saveError,
isDeleting,
deleteError,
onScroll,
onSortSelect,
onFilterSelect,
onViewSelect,
onRefreshAuthorPress,
onRssSyncPress,
...otherProps
} = this.props;
@@ -200,34 +310,70 @@ class AuthorIndex extends Component {
jumpBarItems,
jumpToCharacter,
isPosterOptionsModalOpen,
isBannerOptionsModalOpen,
isOverviewOptionsModalOpen
isOverviewOptionsModalOpen,
isEditorActive,
selectedState,
allSelected,
allUnselected
} = this.state;
const selectedAuthorIds = this.getSelectedIds();
const ViewComponent = getViewComponent(view);
const isLoaded = !!(!error && isPopulated && items.length && scroller);
const hasNoAuthor = !totalItems;
const refreshLabel = isEditorActive && selectedAuthorIds.length > 0 ? translate('UpdateSelected') : translate('UpdateAll');
return (
<PageContent>
<PageToolbar>
<PageToolbarSection>
<PageToolbarButton
label="Update all"
label={refreshLabel}
iconName={icons.REFRESH}
spinningName={icons.REFRESH}
isSpinning={isRefreshingAuthor}
onPress={onRefreshAuthorPress}
onPress={this.onRefreshAuthorPress}
/>
<PageToolbarButton
label="RSS Sync"
label={translate('RSSSync')}
iconName={icons.RSS}
isSpinning={isRssSyncExecuting}
isDisabled={hasNoAuthor}
onPress={onRssSyncPress}
/>
<PageToolbarSeparator />
{
isEditorActive ?
<PageToolbarButton
label={translate('AuthorIndex')}
iconName={icons.AUTHOR_CONTINUING}
isDisabled={hasNoAuthor}
onPress={this.onEditorTogglePress}
/> :
<PageToolbarButton
label={translate('AuthorEditor')}
iconName={icons.EDIT}
isDisabled={hasNoAuthor}
onPress={this.onEditorTogglePress}
/>
}
{
isEditorActive ?
<PageToolbarButton
label={allSelected ? translate('UnselectAll') : translate('SelectAll')}
iconName={icons.CHECK_SQUARE}
isDisabled={hasNoAuthor}
onPress={this.onSelectAllPress}
/> :
null
}
</PageToolbarSection>
<PageToolbarSection
@@ -242,7 +388,7 @@ class AuthorIndex extends Component {
optionsComponent={AuthorIndexTableOptionsConnector}
>
<PageToolbarButton
label="Options"
label={translate('Options')}
iconName={icons.TABLE}
/>
</TableOptionsModalWrapper> :
@@ -252,7 +398,7 @@ class AuthorIndex extends Component {
{
view === 'posters' ?
<PageToolbarButton
label="Options"
label={translate('Options')}
iconName={icons.POSTER}
isDisabled={hasNoAuthor}
onPress={this.onPosterOptionsPress}
@@ -260,21 +406,10 @@ class AuthorIndex extends Component {
null
}
{
view === 'banners' ?
<PageToolbarButton
label="Options"
iconName={icons.POSTER}
isDisabled={hasNoAuthor}
onPress={this.onBannerOptionsPress}
/> :
null
}
{
view === 'overview' ?
<PageToolbarButton
label="Options"
label={translate('Options')}
iconName={icons.OVERVIEW}
isDisabled={hasNoAuthor}
onPress={this.onOverviewOptionsPress}
@@ -282,11 +417,7 @@ class AuthorIndex extends Component {
null
}
{
(view === 'posters' || view === 'banners' || view === 'overview') &&
<PageToolbarSeparator />
}
<PageToolbarSeparator />
<AuthorIndexViewMenu
view={view}
@@ -312,7 +443,7 @@ class AuthorIndex extends Component {
</PageToolbar>
<div className={styles.pageContentBodyWrapper}>
<PageContentBodyConnector
<PageContentBody
registerScroller={this.setScrollerRef}
className={styles.contentBody}
innerClassName={styles[`${view}InnerContentBody`]}
@@ -340,6 +471,12 @@ class AuthorIndex extends Component {
sortKey={sortKey}
sortDirection={sortDirection}
jumpToCharacter={jumpToCharacter}
isEditorActive={isEditorActive}
allSelected={allSelected}
allUnselected={allUnselected}
onSelectedChange={this.onSelectedChange}
onSelectAllChange={this.onSelectAllChange}
selectedState={selectedState}
{...otherProps}
/>
@@ -351,7 +488,7 @@ class AuthorIndex extends Component {
!error && isPopulated && !items.length &&
<NoAuthor totalItems={totalItems} />
}
</PageContentBodyConnector>
</PageContentBody>
{
isLoaded && !!jumpBarItems.order.length &&
@@ -362,22 +499,46 @@ class AuthorIndex extends Component {
}
</div>
{
isLoaded && isEditorActive &&
<AuthorEditorFooter
authorIds={selectedAuthorIds}
selectedCount={selectedAuthorIds.length}
isSaving={isSaving}
saveError={saveError}
isDeleting={isDeleting}
deleteError={deleteError}
isOrganizingAuthor={isOrganizingAuthor}
isRetaggingAuthor={isRetaggingAuthor}
showMetadataProfile={true}
onSaveSelected={this.onSaveSelected}
onOrganizeAuthorPress={this.onOrganizeAuthorPress}
onRetagAuthorPress={this.onRetagAuthorPress}
/>
}
<AuthorIndexPosterOptionsModal
isOpen={isPosterOptionsModalOpen}
onModalClose={this.onPosterOptionsModalClose}
/>
<AuthorIndexBannerOptionsModal
isOpen={isBannerOptionsModalOpen}
onModalClose={this.onBannerOptionsModalClose}
/>
<AuthorIndexOverviewOptionsModal
isOpen={isOverviewOptionsModalOpen}
onModalClose={this.onOverviewOptionsModalClose}
/>
<OrganizeAuthorModal
isOpen={this.state.isOrganizingAuthorModalOpen}
authorIds={selectedAuthorIds}
onModalClose={this.onOrganizeAuthorModalClose}
/>
<RetagAuthorModal
isOpen={this.state.isRetaggingAuthorModalOpen}
authorIds={selectedAuthorIds}
onModalClose={this.onRetagAuthorModalClose}
/>
</PageContent>
);
}
@@ -397,14 +558,21 @@ AuthorIndex.propTypes = {
sortDirection: PropTypes.oneOf(sortDirections.all),
view: PropTypes.string.isRequired,
isRefreshingAuthor: PropTypes.bool.isRequired,
isOrganizingAuthor: PropTypes.bool.isRequired,
isRetaggingAuthor: PropTypes.bool.isRequired,
isRssSyncExecuting: PropTypes.bool.isRequired,
isSmallScreen: PropTypes.bool.isRequired,
isSaving: PropTypes.bool.isRequired,
saveError: PropTypes.object,
isDeleting: PropTypes.bool.isRequired,
deleteError: PropTypes.object,
onSortSelect: PropTypes.func.isRequired,
onFilterSelect: PropTypes.func.isRequired,
onViewSelect: PropTypes.func.isRequired,
onRefreshAuthorPress: PropTypes.func.isRequired,
onRssSyncPress: PropTypes.func.isRequired,
onScroll: PropTypes.func.isRequired
onScroll: PropTypes.func.isRequired,
onSaveSelected: PropTypes.func.isRequired
};
export default AuthorIndex;

View File

@@ -5,11 +5,10 @@ import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import * as commandNames from 'Commands/commandNames';
import withScrollPosition from 'Components/withScrollPosition';
import { setAuthorFilter, setAuthorSort, setAuthorTableOption, setAuthorView } from 'Store/Actions/authorIndexActions';
import { saveAuthorEditor, setAuthorFilter, setAuthorSort, setAuthorTableOption, setAuthorView } from 'Store/Actions/authorIndexActions';
import { executeCommand } from 'Store/Actions/commandActions';
import scrollPositions from 'Store/scrollPositions';
import createAuthorClientSideCollectionItemsSelector
from 'Store/Selectors/createAuthorClientSideCollectionItemsSelector';
import createAuthorClientSideCollectionItemsSelector from 'Store/Selectors/createAuthorClientSideCollectionItemsSelector';
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
import createDimensionsSelector from 'Store/Selectors/createDimensionsSelector';
import AuthorIndex from './AuthorIndex';
@@ -19,16 +18,22 @@ function createMapStateToProps() {
createAuthorClientSideCollectionItemsSelector('authorIndex'),
createCommandExecutingSelector(commandNames.REFRESH_AUTHOR),
createCommandExecutingSelector(commandNames.RSS_SYNC),
createCommandExecutingSelector(commandNames.RENAME_AUTHOR),
createCommandExecutingSelector(commandNames.RETAG_AUTHOR),
createDimensionsSelector(),
(
author,
isRefreshingAuthor,
isOrganizingAuthor,
isRetaggingAuthor,
isRssSyncExecuting,
dimensionsState
) => {
return {
...author,
isRefreshingAuthor,
isOrganizingAuthor,
isRetaggingAuthor,
isRssSyncExecuting,
isSmallScreen: dimensionsState.isSmallScreen
};
@@ -54,9 +59,14 @@ function createMapDispatchToProps(dispatch, props) {
dispatch(setAuthorView({ view }));
},
onRefreshAuthorPress() {
dispatchSaveAuthorEditor(payload) {
dispatch(saveAuthorEditor(payload));
},
onRefreshAuthorPress(items) {
dispatch(executeCommand({
name: commandNames.REFRESH_AUTHOR
name: commandNames.BULK_REFRESH_AUTHOR,
authorIds: items
}));
},
@@ -77,6 +87,10 @@ class AuthorIndexConnector extends Component {
this.props.dispatchSetAuthorView(view);
}
onSaveSelected = (payload) => {
this.props.dispatchSaveAuthorEditor(payload);
}
onScroll = ({ scrollTop }) => {
scrollPositions.authorIndex = scrollTop;
}
@@ -90,6 +104,7 @@ class AuthorIndexConnector extends Component {
{...this.props}
onViewSelect={this.onViewSelect}
onScroll={this.onScroll}
onSaveSelected={this.onSaveSelected}
/>
);
}
@@ -98,7 +113,8 @@ class AuthorIndexConnector extends Component {
AuthorIndexConnector.propTypes = {
isSmallScreen: PropTypes.bool.isRequired,
view: PropTypes.string.isRequired,
dispatchSetAuthorView: PropTypes.func.isRequired
dispatchSetAuthorView: PropTypes.func.isRequired,
dispatchSaveAuthorEditor: PropTypes.func.isRequired
};
export default withScrollPosition(

View File

@@ -5,6 +5,7 @@ import { ColorImpairedConsumer } from 'App/ColorImpairedContext';
import DescriptionList from 'Components/DescriptionList/DescriptionList';
import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem';
import formatBytes from 'Utilities/Number/formatBytes';
import translate from 'Utilities/String/translate';
import styles from './AuthorIndexFooter.css';
class AuthorIndexFooter extends PureComponent {
@@ -60,7 +61,9 @@ class AuthorIndexFooter extends PureComponent {
enableColorImpairedMode && 'colorImpaired'
)}
/>
<div>Continuing (All books downloaded)</div>
<div>
{translate('ContinuingAllBooksDownloaded')}
</div>
</div>
<div className={styles.legendItem}>
@@ -70,7 +73,9 @@ class AuthorIndexFooter extends PureComponent {
enableColorImpairedMode && 'colorImpaired'
)}
/>
<div>Ended (All books downloaded)</div>
<div>
{translate('EndedAllBooksDownloaded')}
</div>
</div>
<div className={styles.legendItem}>
@@ -80,7 +85,9 @@ class AuthorIndexFooter extends PureComponent {
enableColorImpairedMode && 'colorImpaired'
)}
/>
<div>Missing Books (Author monitored)</div>
<div>
{translate('MissingBooksAuthorMonitored')}
</div>
</div>
<div className={styles.legendItem}>
@@ -90,55 +97,57 @@ class AuthorIndexFooter extends PureComponent {
enableColorImpairedMode && 'colorImpaired'
)}
/>
<div>Missing Books (Author not monitored)</div>
<div>
{translate('MissingBooksAuthorNotMonitored')}
</div>
</div>
</div>
<div className={styles.statistics}>
<DescriptionList>
<DescriptionListItem
title="Authors"
title={translate('Authors')}
data={count}
/>
<DescriptionListItem
title="Ended"
title={translate('Ended')}
data={ended}
/>
<DescriptionListItem
title="Continuing"
title={translate('Continuing')}
data={continuing}
/>
</DescriptionList>
<DescriptionList>
<DescriptionListItem
title="Monitored"
title={translate('Monitored')}
data={monitored}
/>
<DescriptionListItem
title="Unmonitored"
title={translate('Unmonitored')}
data={count - monitored}
/>
</DescriptionList>
<DescriptionList>
<DescriptionListItem
title="Books"
title={translate('Books')}
data={books}
/>
<DescriptionListItem
title="Files"
title={translate('Files')}
data={bookFiles}
/>
</DescriptionList>
<DescriptionList>
<DescriptionListItem
title="Total File Size"
title={translate('TotalFileSize')}
data={formatBytes(totalFileSize)}
/>
</DescriptionList>

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