Compare commits

...

275 commits

Author SHA1 Message Date
Bogdan
91f06801ca
Bump version to 2.13.1 2025-06-15 09:22:00 +03:00
Bogdan
dc61618711 Save Publish Dates as UTC for grabbed albums 2025-06-12 11:35:35 +03:00
Bogdan
fd00a5627c Fixed: Improve error message for queue items from Transmission
(cherry picked from commit 0ae07898ba6f85299e739d38ab1dd900c39e91d2)
2025-06-12 11:32:16 +03:00
Bogdan
66ea1b1dfb Fixed: Avoid requests without categories for FileList
(cherry picked from commit 4728fa29ef578a7ff33cf16a4e6b46689c4be1b4)
2025-06-12 11:10:06 +03:00
Bogdan
72fa05cf41 Fixed: Sending notifications for Custom Script with unparsed artist
(cherry picked from commit 76b1130b6811454fa6b1e80e0b2012c24c4ae8fa)
2025-06-12 11:06:46 +03:00
Bogdan
c51b5c6fba Log when expected track file is missing from disk on upgrade
(cherry picked from commit 1047e71b7d78812f2fa04b150fc6774efc1a6af8)
2025-06-12 11:05:21 +03:00
Bogdan
efebab9ba2 Update default log level message
(cherry picked from commit 817d13e85c89d1f10abab09a8f63272a46f5d0b6)
2025-06-12 11:03:29 +03:00
Mark McDowall
47c32c9963 Improve messaging when NZB contains invalid XML
(cherry picked from commit 728df146ada115a367bf1ce808482a4625e6098d)
2025-06-12 10:56:57 +03:00
Stevie Robinson
9f229bb684 Ensure Custom Format Maximum Size won't overflow
(cherry picked from commit a50d2562649bbe77d0feb9fbfc594d56952e0a5e)
2025-06-12 10:56:14 +03:00
Mark McDowall
f9b2e57696 Increase maximum backup restoration size to 5GB
(cherry picked from commit e38deb34221ebf131adcce9551774898f46b1f7f)
2025-06-12 10:55:49 +03:00
carrossos
4b48edab0a Treat HTTP 410 response for failed download similarly to HTTP 404
(cherry picked from commit 818ae02a7a8f0a8ea0a44e0015e2667d96453332)
2025-06-12 10:55:02 +03:00
Stevie Robinson
e087574de7 New: Ignore volumes containing .timemachine from Disk Space
(cherry picked from commit a853c537db0a6bd499a2277987dc170d2a1f5645)
2025-06-12 10:54:16 +03:00
Bogdan
8877cf99f1 Use the thrown exception in http timeout handling
(cherry picked from commit 14e324ee30694ae017a39fd6f66392dc2d104617)
2025-06-12 10:53:59 +03:00
Stevie Robinson
a56e5b3f9a New: Don't allow remote path to start with space
(cherry picked from commit 5ba3ff598770fdf9e5a53d490c8bcbdd6a59c4cc)

Fixed validation for Remote Path Mapping

(cherry picked from commit bf34b4309402ce529a8c04de70f44b28948761f4)
2025-06-12 10:52:01 +03:00
Stevie Robinson
5bb1949ea2 Fixed: Include network drive types in Disk Space
(cherry picked from commit 9ffcd141a515e99604881a4ef383dadafef31eeb)
2025-06-12 10:47:17 +03:00
Bogdan
979042948d Fixed: Quality sliders on some browsers 2025-06-12 10:47:00 +03:00
Mark McDowall
ebe59b18d9 Sync react-slider props for Quality sliders with upstream
(cherry picked from commit 9dab2ba6e4316879e4db8db47363476a5c4f13b2)
2025-06-12 10:46:53 +03:00
Bogdan
086a451dff Follow redirects for usenet grabs on non-prod builds
(cherry picked from commit 1cdca8ef3e47e19c9264db6b322161b615b20294)
2025-06-12 10:39:37 +03:00
Mark McDowall
1bcb82eed0 Prevent should refresh artists and albums from failing
(cherry picked from commit 3eed84c67938fed308e562e69cf7bcd727063803)
2025-06-12 10:38:23 +03:00
Mark McDowall
ae9b4cec75 New: Update wording when removing a root folder
(cherry picked from commit 51c17fd3122f7b96a4155593d465ba32870d0c91)
2025-06-12 10:35:09 +03:00
Mark McDowall
ed777de015 Fixed: Escape backticks in discord notifications
(cherry picked from commit 70c74fc1769f2094a14faaa103c49d744534be9f)
2025-06-12 10:30:03 +03:00
Bogdan
96f956a5d6 Fix fullscreen automation screenshots 2025-06-10 13:13:38 +03:00
Bogdan
68a8f40746 Fixed translations for the updates page 2025-06-09 23:33:06 +03:00
Bogdan
c518cf63e7
Bump version to 2.13.0 2025-06-09 20:28:15 +03:00
Bogdan
da55b8578a Bump IPAddressRange and SixLabors.ImageSharp 2025-06-09 15:21:12 +03:00
Bogdan
234c29ef49
Bump version to 2.12.4 2025-06-08 10:31:50 +03:00
Weblate
de169e8a1f Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: CandyD-1992 <259215606@qq.com>
Co-authored-by: Ilbebino <tommasobellandi08@gmail.com>
Co-authored-by: NanderTGA <nander.roobaert@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/nl/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/zh_CN/
Translation: Servarr/Lidarr
2025-06-06 21:24:28 +03:00
Bogdan
4b300a448a Skip tests temporally 2025-06-06 18:06:09 +03:00
Gykes
785bcfda0b
Fixed: Sort artists by genre on index table view 2025-06-03 09:13:36 +03:00
Bogdan
94ea751ad2 Ignore Jetbrains IntelliJ Workspace Directories 2025-06-02 11:18:44 +03:00
Bogdan
0c172b58f1
Bump version to 2.12.3 2025-06-01 10:40:54 +03:00
Weblate
ea2ee70208 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Discover999 <13189912235@163.com>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Weblate <noreply-mt-weblate@weblate.org>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: arsenius88 <arsenovich_andr@ukr.net>
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/nb_NO/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/pt/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/uk/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/zh_Hans/
Translation: Servarr/Lidarr
2025-05-25 16:19:12 +03:00
Bogdan
8b63928a25
Bump version to 2.12.2 2025-05-25 16:18:38 +03:00
Bogdan
7217e891f7 New: Real time UI updates for provider changes
(cherry picked from commit 20ef22be94f4bdb5633ddfb080e91c8d5b0229da)

Closes #5178
2025-05-22 19:36:21 +03:00
Bogdan
345bbcd992
Bump version to 2.12.1 2025-05-04 21:08:35 +03:00
Bogdan
bd9d7ba085 Fixed: Parsing FLAC24 as FLAC 24-bit 2025-05-01 17:26:52 +03:00
Bogdan
3937bebfea Add plugins branch to the bug report template 2025-05-01 15:57:05 +03:00
Bogdan
767b0930a5 Bump caniuse db 2025-04-28 15:02:42 +03:00
Bogdan
c3f0fc640c Bump core-js to 3.41 2025-04-28 15:01:30 +03:00
Bogdan
9dbcc79436 Bump version to 2.12.0 2025-04-28 15:00:29 +03:00
Bogdan
3dd04cecbf Skip spotify mapping tests 2025-04-28 12:41:35 +03:00
Bogdan
d8850af019 Increase input sizes in edit artist modal
Closes #5294
2025-04-17 12:36:02 +03:00
Bogdan
fbfd24e226
Bump version to 2.11.2 2025-04-13 10:08:22 +03:00
Weblate
d9562c701e Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Hugoren Martinako <aumpfbahn@gmail.com>
Co-authored-by: Ste <stefanucciu@gmail.com>
Co-authored-by: Weblate <noreply-mt-weblate@weblate.org>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/uk/
Translation: Servarr/Lidarr
2025-04-08 15:40:25 +03:00
Servarr
d21ad2ad68 Automated API Docs update 2025-04-08 15:38:55 +03:00
Bogdan
556f0ea54b Fixed: Disallow tags creation with empty label 2025-04-08 15:30:20 +03:00
Bogdan
e4a36ca388 Log delete statements only once 2025-04-08 15:29:28 +03:00
Bogdan
1045684935 Bump Selenium.WebDriver.ChromeDriver 2025-04-08 15:28:37 +03:00
Mark McDowall
9ba71ae6b1 Update WikiUrl type in API docs
(cherry picked from commit 9bd619ccfe074abe396bbf043a36a5be18a7ba4b)
2025-04-08 15:28:06 +03:00
Mark McDowall
89b9352fef Fixed: Set output encoding to UTF-8 when running external processes
(cherry picked from commit f8e57b09856278a6d0c65f18704e96a33459687d)
2025-04-08 15:26:59 +03:00
Mark McDowall
c83332e58c New: Prevent Remote Path Mapping local folder being set to System folder or '/'
(cherry picked from commit 0f904e091702a2ac53771ee3aeb5aafe62688035)
2025-04-08 15:26:38 +03:00
Bogdan
4677a1115a
Bump linux agent to ubuntu-22.04 2025-04-02 00:11:01 +03:00
Weblate
6150a57596 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Maxime Surrel <maxime.surrel@live.fr>
Co-authored-by: Moxitech <moxitogame59@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: Xing Wang <wxing82@outlook.com>
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ru/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/zh_CN/
Translation: Servarr/Lidarr
2025-03-30 10:17:56 +03:00
Bogdan
13f6b1a086
Bump version to 2.11.1 2025-03-30 10:17:14 +03:00
Bogdan
8027ab5d2e
Include invalid path in exception message when failing to normalize 2025-03-28 09:57:57 +02:00
Bogdan
5bdc119b98 Fixed: Include Track for history/since
Fixes #5421
2025-03-27 19:47:03 +02:00
Bogdan
1b9b57ae9b Bump browserslist-db 2025-03-25 21:13:13 +02:00
Mark McDowall
c28a97cafd Fixed: Deleting artist folder fails when files/folders aren't instantly removed
(cherry picked from commit c84699ed5d5a2f59f236c26a8999d25a1102ec02)
2025-03-25 21:11:58 +02:00
Bogdan
099d19a04d Cleanup unused sorting fields for bulk manage providers
(cherry picked from commit 6115236d3853f70a18b73aef15ebe4e18ab48e40)
2025-03-25 21:11:32 +02:00
Bogdan
d381463b60 New: Display indexer in download failed details
(cherry picked from commit a324052debf63a8db73a2f3c79201864892bb62c)
2025-03-25 21:10:19 +02:00
Bogdan
a86bd8e862 Fixed: Inherit indexer, size and release group for marked as failed history
(cherry picked from commit e08c9d5501e65aabce3456b2dd7571867508d88f)
2025-03-25 21:08:13 +02:00
Mark McDowall
4bea38ab9c Improve logging when login fails due to CryptographicException
(cherry picked from commit 1449941471cbb8885e9298317b9a30f2576d7941)
2025-03-25 21:03:41 +02:00
Bogdan
950c51bc59 Fixed: Priority validation for indexers and download clients
(cherry picked from commit f0e320f3aa501f120721503b8256f464a31be783)
2025-03-25 21:00:43 +02:00
Mark McDowall
18f13fe7f8 Fixed: Allow tables to scroll on tablets in portrait mode
(cherry picked from commit 5fb632eb46cf77ea4f61d407f6429d9c32dba766)
2025-03-25 20:58:58 +02:00
Bogdan
f8d4b3a59b Bump NLog, Npgsql, System.Memory and System.ValueTuple 2025-03-23 13:10:50 +02:00
Bogdan
5cf9624e55
Bump version to 2.11.0 2025-03-23 13:02:07 +02:00
Mark McDowall
81895f8033 Fixed: Drop downs flickering in some cases
(cherry picked from commit 3b024443c5447b7638a69a99809bf44b2419261f)

Closes #5386
2025-03-23 09:42:29 +02:00
Weblate
a1c2bfa527 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Fixer <ygj59783@zslsz.com>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Weblate <noreply-mt-weblate@weblate.org>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ar/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/bg/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/cs/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/da/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/el/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/he/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/hi/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/hr/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/is/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ja/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ko/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/nb_NO/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/nl/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/pl/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/pt/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ro/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ru/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/sk/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/sv/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/th/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/tr/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/uk/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/vi/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/zh_CN/
Translation: Servarr/Lidarr
2025-03-16 11:38:19 +02:00
Bogdan
33049910de
Bump version to 2.10.3 2025-03-16 10:47:47 +02:00
Bogdan
6dd87fd348
Bump version to 2.10.2 2025-03-09 11:52:12 +02:00
Bogdan
9314eb34ab Fixed: Displaying warnings for automatic failed imports in queue 2025-03-08 15:44:52 +02:00
Bogdan
84b91ba6c1 Bump Polly to 8.5.2 2025-03-07 23:18:35 +02:00
Bogdan
6c6f92fbed Bump SixLabors.ImageSharp to 3.1.7 2025-03-07 23:17:29 +02:00
Bogdan
1e42ae94aa Fix Completed Download Service tests 2025-03-06 19:49:26 +02:00
Servarr
29f5810865 Automated API Docs update 2025-03-06 19:24:11 +02:00
Bogdan
342c82aa1f Fixed: Avoid notifications on reprocessing failed items in queue 2025-03-06 19:15:59 +02:00
Bogdan
5a3f879442 Fixed: Sending import failure notifications to webhook/notifiarr 2025-03-06 17:28:36 +02:00
Mark McDowall
6e57c14e57 Fixed: Marking queued item as failed not blocking the correct Torrent Info Hash
(cherry picked from commit 4b186e894e4e229a435c077e00c65b67ca178333)

Fixes #4977
Closes #4988
2025-03-06 16:34:28 +02:00
Bogdan
9fc549b43b Fixed: Replace diacritics in Clean Title naming tokens 2025-03-05 20:12:15 +02:00
Weblate
a2201001c5 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Fixer <ygj59783@zslsz.com>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: youngjimisme <977671346@qq.com>
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/zh_CN/
Translation: Servarr/Lidarr
2025-03-05 20:03:53 +02:00
Mark McDowall
8c99280f07 Fixed: Adding albums with unknown items in queue 2025-03-05 19:59:56 +02:00
Bogdan
07db508580 Fixed: Calculating custom formats for queue 2025-03-05 19:59:56 +02:00
Bogdan
031f32a52c Fixed: Refresh cache for tracked queue on artist/album add or removal
Prevents a NullRef in CompletedDownloadService.VerifyImport when publishing DownloadCompletedEvent for an already cached tracked download
2025-03-05 19:59:56 +02:00
Mark McDowall
2997c16346 Fixed: Reprocessing items that were previously blocked during importing
(cherry picked from commit bce848facf8aeaeac6a1d59c92941d00589034a4)
2025-03-05 19:59:56 +02:00
Mark McDowall
a1a53dbb5e New: Improve UI status when downloads cannot be imported automatically
(cherry picked from commit 6d5ff9c4d6993d16848980aea499a45b1b51d95c)
2025-03-05 19:59:56 +02:00
Mark McDowall
e8bb78e5bb New: Improve messaging if release is in queue because all tracks in release were not imported
(cherry picked from commit 2728bf79ca41bc372de515cb09e1034a8c006c2b)
2025-03-05 19:59:56 +02:00
Bogdan
6292f223ac Fixed: Attempt to ensure all import results are imported
Fixes #2746
Closes #4815
2025-03-05 19:53:11 +02:00
Bogdan
f4dc294ab3 Fixed: Instance name must contain application name 2025-03-01 13:35:07 +02:00
Bogdan
23611cb116
Bump version to 2.10.1 2025-02-23 12:16:19 +02:00
Bogdan
f177345d01 Fixed: Avoid checking for free space if other specifications fail first 2025-02-22 21:35:18 +02:00
Bogdan
ec050a7b3c Fixed: Prevent NullRef for webhooks when Artist Metadata is not set
Fixes #5368
2025-02-22 16:36:25 +02:00
Mark McDowall
860bd04c59 New: Add artist tags to Webhook and Notifiarr events
(cherry picked from commit cc0a284660f139d5f47b27a2c389973e5e888587)

Closes #4805
2025-02-22 16:26:26 +02:00
Mark McDowall
261f30d268 New: Genres and Images for Webhooks and Notifiarr
(cherry picked from commit fd3dd1ab7dc86cd9e231fa432cc8d2772d5a4bad)

Closes #4832
2025-02-22 16:26:00 +02:00
Weblate
36998abba0 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Fixer <ygj59783@zslsz.com>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/zh_Hans/
Translation: Servarr/Lidarr
2025-02-19 17:25:54 +02:00
Mark McDowall
ad12617694 Cleanse console log messages
(cherry picked from commit 609e964794e17343f63e1ecff3fef323e3d284ff)
2025-02-19 17:09:39 +02:00
Stevie Robinson
be115da157 Fixed: Fallback to Instance Name for Discord notifications
(cherry picked from commit b99e06acc0a3ecae2857d9225b35424c82c67a2b)
2025-02-19 17:06:58 +02:00
Chaz Harris
664b972494
Fixed: Custom Lists using only ArtistMusicBrainzId (#5399)
When using a JSON list that consists of only MusicBrainzId's the list is being filtered.
2025-02-16 21:03:41 +02:00
Bogdan
2b2fd5a175 Fix download links for FileList when passkey contains spaces 2025-02-16 12:20:27 +02:00
Chaz Harris
d8222c066c
Bump devcontainer nodejs version to 20 (#5398) 2025-02-15 11:47:22 +02:00
Weblate
bc6417229e Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Gallyam Biktashev <gallyamb@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Weblate <noreply-mt-weblate@weblate.org>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/bg/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ru/
Translation: Servarr/Lidarr
2025-02-07 19:15:05 -06:00
Bogdan
e0e17a2ea7 Building docs on ARM
Co-authored-by: Mark McDowall <mark@mcdowall.ca>
(cherry picked from commit 147e732c9ca7a4c289d4f6386f1277650e11f15b)
(cherry picked from commit dd900eb7395144b6d299f10fe9475d49d194664e)
2025-02-06 00:54:20 +02:00
Bogdan
5bf2ae9e6f
Bump version to 2.10.0 2025-02-03 14:11:43 +02:00
Bogdan
8e01ba5f21
Bump version to 2.9.6 2025-02-02 12:48:53 +02:00
Mark McDowall
45e8ecffa0 Fixed: Ignore special folders inside Blackhole watch folders
(cherry picked from commit e79dd6f8e689617b1fd9f96c639ac300669112c5)
2025-02-01 23:52:09 +02:00
Bogdan
3c4b438d27 Fixed: Health warning for downloading inside root folders
(cherry picked from commit 1e9fd02e9d2bf57247adcac5728e2a0d2b084b86)

Fixes #5384
2025-02-01 23:51:13 +02:00
Bogdan
8fd79d7291 New: Prefer newer Usenet releases
(cherry picked from commit 6a439f03273b376feda713ef04a6912fc3af9d0a)
2025-02-01 23:45:27 +02:00
Weblate
477a799b8a Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Dani Talens <databio@gmail.com>
Co-authored-by: Mailme Dashite <mailmedashite@protonmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/de/
Translation: Servarr/Lidarr
2025-02-01 23:45:21 +02:00
Bogdan
51a38bc648 Fix logging message for directory watcher error 2025-01-28 21:57:30 +02:00
Weblate
917f705695 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Dani Talens <databio@gmail.com>
Co-authored-by: Lizandra Candido da Silva <lizandra.c.s@gmail.com>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Pieterjan Van Saet <hybridfox2@gmail.com>
Co-authored-by: Weblate <noreply-mt-weblate@weblate.org>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: ahgharaghani <ah.gharaghani@gmail.com>
Co-authored-by: fordas <fordas15@gmail.com>
Co-authored-by: warkurre86 <tom.novo.86@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/bg/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/cs/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/fa/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ko/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/nb_NO/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/nl/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/tr/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/zh_CN/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/zh_Hans/
Translation: Servarr/Lidarr
2025-01-28 21:55:36 +02:00
Bogdan
5a1092b511 Prevent page crash on console.error being used with non-string values
(cherry picked from commit 963395b9695a28af6bc7dd398e9eea18c834c3c9)
2025-01-28 21:49:43 +02:00
jcassette
ef2c6366c4 New: reflink support for ZFS
(cherry picked from commit a840bb542362d58006b6cc27affd58ee6b965b80)

Closes #5369
2025-01-19 17:32:47 +02:00
Bogdan
1ffb82e364
Bump version to 2.9.5 2025-01-19 17:16:09 +02:00
Bogdan
e2f8753a6a Improve messaging for no mediums on album details 2025-01-17 00:42:08 +02:00
Gauthier
739019498f New: Add headers setting in webhook connection
(cherry picked from commit 78fb20282de73c0ea47375895a807235385d90e3)

Closes #5242
2025-01-15 23:06:47 +02:00
Bogdan
396b2ae7c1 Bump SonarCloud azure extension for UI analysis to 3.X 2025-01-14 11:19:52 +02:00
Qstick
0216616738 Bump SonarCloud azure extension to 3.X
(cherry picked from commit 5fac3486130df3b316dd882d676ca13ecb697b59)
2025-01-14 10:09:06 +02:00
Mark McDowall
82e0b628cc Fixed: Parsing of release names with colon in the title
(cherry picked from commit ec698c2cf7df1e1182ffa2f4505fe0872e2d08bc)
2025-01-14 04:16:12 +02:00
Weblate
014f8a58b1 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Mickaël O <mickael.ouillon@ac-bordeaux.fr>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Weblate <noreply-mt-weblate@weblate.org>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/cs/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/fr/
Translation: Servarr/Lidarr
2025-01-12 15:18:26 +02:00
Bogdan
5cbb2848c7
Bump version to 2.9.4 2025-01-12 15:17:02 +02:00
Weblate
554cf8ec55 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Alexander Balya <alexander.balya@gmail.com>
Co-authored-by: Ano10 <Ano10@users.noreply.translate.servarr.com>
Co-authored-by: Fixer <ygj59783@zslsz.com>
Co-authored-by: GkhnGRBZ <gkhn.gurbuz@hotmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Matti Meikäläinen <diefor-93@hotmail.com>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Tommy Au <smarttommyau@gmail.com>
Co-authored-by: Weblate <noreply-mt-weblate@weblate.org>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: fordas <fordas15@gmail.com>
Co-authored-by: marapavelka <mara.pavelka@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ar/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/bg/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/cs/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/da/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/el/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/he/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/hi/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/hr/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/is/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ja/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ko/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/nb_NO/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/nl/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/pl/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/pt/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ro/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ru/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/sk/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/sv/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/th/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/tr/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/uk/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/vi/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/zh_CN/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/zh_TW/
Translation: Servarr/Lidarr
2025-01-05 13:17:21 +02:00
Stevie Robinson
4ff6c71456 Fixed: Listening on all IPv4 Addresses
(cherry picked from commit 035c474f10c257331a5f47e863d24af82537e335)
2025-01-05 13:16:36 +02:00
Stevie Robinson
7cfcf01ae3 Fixed: qBittorrent Ratio Limit Check
(cherry picked from commit 4dcc015fb19ceb57d2e8f4985c5137e765829d1c)
2025-01-05 13:16:24 +02:00
Bogdan
17c5c66e54
Bump version to 2.9.3 2025-01-05 13:16:11 +02:00
Bogdan
40dab8deb9 Check if backup folder is writable on backup
(cherry picked from commit 8aad79fd3e14eb885724a5e5790803c289be2f25)

Closes #5348
2024-12-31 12:20:10 +02:00
Bogdan
39f0e4d989 Suggest adding IP to RPC whitelist for on failed Transmission auth
(cherry picked from commit f05e552e8e6dc02cd26444073ab9a678dcb36492)
2024-12-31 12:19:06 +02:00
Bogdan
35a46eca7b
Bump version to 2.9.2 2024-12-30 01:01:47 +02:00
Mark McDowall
79b29f39f9 Don't send session information to Sentry
(cherry picked from commit fae24e98fb9230c2f3701caef457332952c6723f)
2024-12-28 16:00:11 +02:00
Bruno Garcia
0e19c03e9a Update Sentry SDK add features
Co-authored-by: Stefan Jandl <reg@bitfox.at>
(cherry picked from commit 6377c688fc7b35749d608bf62796446bb5bcb11b)
2024-12-28 16:00:11 +02:00
Weblate
e6388cab94 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: GkhnGRBZ <gkhn.gurbuz@hotmail.com>
Co-authored-by: Tommy Au <smarttommyau@gmail.com>
Co-authored-by: Weblate <noreply-mt-weblate@weblate.org>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ar/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/bg/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/cs/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/da/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/el/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/he/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/hi/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/hr/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/id/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/is/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ja/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ko/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/nl/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/pl/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/pt/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ro/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ru/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/sv/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/th/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/tr/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/uk/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/vi/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/zh_CN/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/zh_TW/
Translation: Servarr/Lidarr
2024-12-22 17:18:20 +02:00
Bogdan
47e504fbc9 Add translations for some download client settings 2024-12-22 17:17:04 +02:00
Mika
1a40839202 Add file-count for Transmission RPC
(cherry picked from commit 23c741fd001582fa363c2723eff9facd3091618b)
2024-12-22 17:17:04 +02:00
Bogdan
25a80aa29d Avoid default category on existing Transmission configurations
Co-authored-by: Mark McDowall <mark@mcdowall.ca>
(cherry picked from commit bd656ae7f66fc9224ef2a57857152ee5d54d54f8)
2024-12-22 17:17:04 +02:00
Bogdan
7255126af5 New: Labels support for Transmission 4.0
(cherry picked from commit 675e3cd38a14ea33c27f2d66a4be2bf802e17d88)
2024-12-22 17:17:04 +02:00
Bogdan
166f87ae68 Include exception message in LidarrAPI failure message
(cherry picked from commit 1e89a1a3cb8fa83e4415b047513cbecacbebc59c)

Closes #5176
2024-12-22 16:21:13 +02:00
Bogdan
babdf10273
Bump version to 2.9.1 2024-12-22 13:26:41 +02:00
Bogdan
19c2994ff3 Skip spotify mapping tests 2024-12-21 16:08:38 +02:00
Bogdan
e420ee0645 Bump NLog, IPAddressRange, Polly, ImageSharp, Npgsql, System.Memory and Ical.Net
Closes #5333
2024-12-21 15:39:06 +02:00
Bogdan
78469a96c9 Bump MailKit to 4.8.0 and Microsoft.Data.SqlClient to 2.1.7
Closes #5332
2024-12-21 15:34:04 +02:00
Servarr
bc6df548fc Automated API Docs update 2024-12-17 19:50:37 +02:00
Stevie Robinson
797e4c773e Replace URLs in translations with tokens
(cherry picked from commit 98d60e1a8e9abce6b31b3cdd745eff0fed181458)
2024-12-17 18:49:21 +02:00
Weblate
119141723a Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: GkhnGRBZ <gkhn.gurbuz@hotmail.com>
Co-authored-by: Weblate <noreply-mt-weblate@weblate.org>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/cs/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/el/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/pl/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ro/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/sv/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/th/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/tr/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/vi/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/zh_CN/
Translation: Servarr/Lidarr
2024-12-17 18:45:19 +02:00
Mark McDowall
fd1719e58c Fixed: Artists without tags bypassing tags on Download Client
(cherry picked from commit c0e264cfc520ee387bfc882c95a5822c655e0d9b)

Fix typo about download clients comment

(cherry picked from commit c39fb4fe6f0ed5e1dc2aa33f4455a4d0c760063b)

Closes #5309
Closes #5318
2024-12-17 18:30:39 +02:00
Mark McDowall
41612708ff Sync TimeSpanConverter with upstream
Co-authored-by: Bogdan <mynameisbogdan@users.noreply.github.com>

(cherry picked from commit 1374240321f08d1400faf95e84217e4b7a2d116b)

Closes #5301
2024-12-17 18:28:20 +02:00
Bogdan
535caf1324 Add return type for artist/album lookup endpoint
Closes #5282
2024-12-17 18:27:00 +02:00
Mark McDowall
eb3c7d6990 Update React
(cherry picked from commit 4491df3ae7530f2167beebc3548dd01fd2cc1a12)

Towards #5264
2024-12-17 18:25:56 +02:00
Mark McDowall
4c603e24f6 Support Postgres with non-standard version string
(cherry picked from commit 40f4ef27b22113c1dae0d0cbdee8205132bed68a)

Closes #5267
2024-12-17 18:19:06 +02:00
Bogdan
ec93c33aa9 Console warnings for missing translations on development builds
(cherry picked from commit 67a1ecb0fea4e6c7dfdb68fbe3ef30d4c22398d8)

Closes #5239
2024-12-17 18:10:08 +02:00
Mark McDowall
afb3fd5bd5 Upgrade typescript-eslint packages to 8.181.1
(cherry picked from commit ed10b63fa0c161cac7e0a2084e53785ab1798208)

Closes #5325
2024-12-17 17:41:10 +02:00
Mark McDowall
198a13755f Upgrade TypeScript and core-js
(cherry picked from commit 148480909917f69ff3b2ca547ccb4716dd56606e)

Closes #5306
2024-12-17 17:38:24 +02:00
Bogdan
44a5654918 Log adding missing artist messages as info 2024-12-17 15:48:45 +02:00
Mark McDowall
8aa0754843 Upgrade Font Awesome to 6.7.1
(cherry picked from commit 016b5718386593c030f14fcac307c93ee1ceeca6)
2024-12-17 15:47:58 +02:00
Mark McDowall
c42e96b55d Upgrade babel to 7.26.0
(cherry picked from commit bfcd017012730c97eb587ae2d2e91f72ee7a1de3)
2024-12-17 15:47:45 +02:00
Bogdan
f92935e3d2 Set minor version for core-js in babel/preset-env
(cherry picked from commit 2e83d59f61957cbc2171bef097fe2410e72729ad)
2024-12-17 15:47:05 +02:00
Bogdan
13bb8f5089 Bump version to 2.9.0 2024-12-16 21:04:53 +02:00
Bogdan
ad084cdf91 Fixed: Parse FLAC 24-bit/24_bit/24.bit as FLAC 24bit 2024-12-16 16:29:05 +02:00
Bogdan
4bcdc49777 Fixed: Refresh backup list on deletion
(cherry picked from commit 3b00112447361b19c04851a510e63f812597a043)
2024-12-15 05:30:39 +02:00
Mark McDowall
502cb20898 Fixed: Error getting processes in some cases
(cherry picked from commit b552d4e9f7ca7388404aa0d52566010a54cb0244)
2024-12-15 05:30:28 +02:00
Weblate
0fd6c263b1 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Dani Talens <databio@gmail.com>
Co-authored-by: GkhnGRBZ <gkhn.gurbuz@hotmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Tomer Horowitz <tomerh2001@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: fordas <fordas15@gmail.com>
Co-authored-by: hhjuhl <hans@kopula.dk>
Co-authored-by: keysuck <joshkkim@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/da/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/he/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ko/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/tr/
Translation: Servarr/Lidarr
2024-12-14 02:34:55 +02:00
Bogdan
11af8a5e05
Bump version to 2.8.2 2024-12-08 18:17:10 +02:00
Servarr
88196340a8 Automated API Docs update 2024-12-04 17:50:06 +02:00
Weblate
4048f2bd72 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Albrt9527 <2563009889@qq.com>
Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Ardenet <1213193613@qq.com>
Co-authored-by: GkhnGRBZ <gkhn.gurbuz@hotmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
Co-authored-by: Mizuyoru_TW <mizuyoru.tw@gmail.com>
Co-authored-by: Robin Dadswell <robin@robindadswell.tech>
Co-authored-by: Rodion <rodyon009@gmail.com>
Co-authored-by: Weblate <noreply-mt-weblate@weblate.org>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: farebyting <farelbyting@gmail.com>
Co-authored-by: mryx007 <mryx@mail.de>
Co-authored-by: sagstickler <sags.tickler.0v@icloud.com>
Co-authored-by: thelooter <evekolb2204@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ar/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/bg/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/cs/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/da/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/el/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/he/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/hi/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/hr/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/id/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/is/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ja/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ko/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/nb_NO/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/nl/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/pl/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/pt/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ro/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ru/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/sk/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/sv/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/th/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/tr/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/uk/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/vi/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/zh_CN/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/zh_HANS/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/zh_Hans/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/zh_TW/
Translation: Servarr/Lidarr
2024-12-04 17:37:40 +02:00
Bogdan
1f76f6cb19 Fixed: Trimming disabled logs database
(cherry picked from commit d5dff8e8d6301b661a713702e1c476705423fc4f)
2024-12-04 17:36:14 +02:00
Jared
cc409d50f5 New: Config file setting to disable log database
(cherry picked from commit 92eab4b2e26741b7f20b6b7177418402cb15a3aa)
2024-12-04 17:36:14 +02:00
Mark McDowall
14716a1405 New: Support for new SABnzbd history retention values
(cherry picked from commit e361f18837d98c089f7dc9c0190221ca8e2cf225)
2024-12-04 17:33:23 +02:00
Mark McDowall
f3a697ca68 Deluge communication improvements
(cherry picked from commit 183b8b574a4dd948b5fada94d0e645b87710f223)
2024-12-04 17:33:03 +02:00
soup
f87a8fa9f5 New: Add config file setting for CGNAT authentication bypass
(cherry picked from commit 4c41a4f368046f73f82306bbd73bec992392938b)
2024-12-04 17:32:39 +02:00
Bogdan
b298bfd932 Fix tags help message 2024-12-04 16:04:39 +02:00
Bogdan
ecb7d9f6a6 Fix adding delay profile error message 2024-12-04 15:44:36 +02:00
Gylesie
eef55f65c6 Remove unnecessary heap allocations in local IP check
(cherry picked from commit ed536a85ad5f2062bf6f01f80efddb19fa935f63)
2024-12-02 02:33:25 +02:00
d-rez
beabad5e3a
Fixed: Updated Base Url for Redacted (#5250) 2024-11-28 00:14:39 +02:00
Mark McDowall
2b1684a793 Webpack web target
(cherry picked from commit a90866a73e6cff9a286c23e60c74672f4c0d317a)
2024-11-27 12:24:16 +02:00
Mark McDowall
f23d75d031 Fixed: Normalize unicode characters when comparing paths for equality
(cherry picked from commit ceeec091f85d0094e07537b7f62f18292655a710)
2024-11-17 11:33:58 +02:00
Mark McDowall
abe0090f94 Fixed: Allow files to be moved from Torrent Blackhole even when remove is disabled
(cherry picked from commit f739fd0900695e2ff312d13985c87d84ae00ea75)
2024-11-17 11:33:46 +02:00
Bogdan
8d32a532e4 Pin ReportGenerator in Azure Pipelines for .NET 6
(cherry picked from commit 50ce480abf043140e209d2d2959fbea8dd5dd2ab)
2024-11-15 15:46:49 -06:00
Weblate
a3b78aacdc Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Fixer <ygj59783@zslsz.com>
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ro/
Translation: Servarr/Lidarr
2024-11-07 16:57:42 +02:00
Weblate
c43a141b65 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Lizandra Candido da Silva <lizandra.c.s@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ar/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/bg/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/cs/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/da/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/he/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/hi/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/hr/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/id/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/is/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ja/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ko/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/lv/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/nb_NO/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/nl/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/pl/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ro/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ru/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/sk/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/sv/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/th/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/tr/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/uk/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/zh_TW/
Translation: Servarr/Lidarr
2024-11-07 08:39:10 -06:00
Servarr
d2f5feab5d Automated API Docs update 2024-11-06 17:15:50 -06:00
Mark McDowall
cfb517a90f Fixed: Filtering queue by multiple qualities
(cherry picked from commit b8af3af9f16db96337832c2989f4e7ff3dc2ed30)

Closes #5223
2024-11-04 19:04:13 +02:00
Bogdan
3f81e0254f Fixed: Loading queue with pending releases for deleted artists
(cherry picked from commit 38c0135d7cd05b22bede934f8571c439dcf70a88)

Closes #5214
2024-11-04 18:59:04 +02:00
Bogdan
29d17c6347 Fixed: Root folder existence for import lists health check
Closes #5218
2024-11-04 18:57:10 +02:00
Bogdan
23f7dc3d3c Show an artist path as example in Mount Health Check
Closes #5225
2024-11-04 18:54:11 +02:00
Mark McDowall
e39e990696 New: Use instance name in PWA manifest
(cherry picked from commit 1fcfb88d2aa0126c4b3c878c8e310311ea57d04d)

Closes #5203
2024-11-04 18:46:05 +02:00
Mark McDowall
0c2ede48e8 Fixed: PWA Manifest with URL base
(cherry picked from commit aedcd046fc4fc621dae4b231cc80d4b269a69177)

Closes #5203

Fixed: PWA Manifest images

(cherry picked from commit da7d17f5e826d5273dba0b4f73227ffc8ed8a6c7)

Closes #5030
2024-11-04 18:45:33 +02:00
Mark McDowall
ca23ac3011 Rename Manage Custom Formats to Manage Formats
(cherry picked from commit 0f225b05c00add562c9a6aa8cc4cf494e83176c1)

Closes #5207
2024-11-04 18:40:17 +02:00
Bogdan
e50e79167a Fixed: Cleaning the French preposition 'à' from names
(cherry picked from commit 22005dc8c500cd77e4a710248582cd4a0036988f)

Closes #5213
2024-11-04 18:39:09 +02:00
Weblate
fd3f493eb6 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Lars <lars.erik.heloe@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: mytelegrambot <lacsonluxur@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ko/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/nb_NO/
Translation: Servarr/Lidarr
2024-11-04 18:30:15 +02:00
Mark McDowall
f6d3481e38 New: Add individual edit to Manage Custom Formats
(cherry picked from commit e006b405323c276eb5b7f2dd97b97c80394a6930)
2024-11-04 18:27:55 +02:00
Mark McDowall
e04c28fe2d Use current time for cache break in development
(cherry picked from commit 020ed32fcfab1c6fbe57af5ea650300272c93fd7)
2024-11-04 18:27:25 +02:00
Bogdan
030300c896 Bump version to 2.8.1 2024-11-03 11:42:29 +02:00
Weblate
50872f3629 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Daniel <statoxxl@gmail.com>
Co-authored-by: GkhnGRBZ <gkhn.gurbuz@hotmail.com>
Co-authored-by: HUi <huynguyeexn@gmail.com>
Co-authored-by: Kuzmich <kuzmich55@gmail.com>
Co-authored-by: Moon55 <dylan.gurdak@protonmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: http://translate.servarr.com/projects/servarr/lidarr/tr/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ru/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/vi/
Translation: Servarr/Lidarr
2024-11-02 21:13:14 +02:00
Bogdan
3232e9ab94 Fixed: Initial state for qBittorrent v5.0
(cherry picked from commit ff724b7f4099284b8062f1625cf07b7822782edf)

Closes #5187
2024-10-27 09:27:40 +02:00
Bogdan
8623b4410c Inherit trigger from pushed command models
(cherry picked from commit 0bc4903954b955fce0c368ef7fd2a6f3761d6a93)

Closes #5181
2024-10-27 09:19:04 +02:00
Bogdan
a843a46fbe Improve message for grab errors due to no matching tags
Co-authored-by: zakary <zak@ary.dev>
(cherry picked from commit df672487cf1d5f067849367a2bfb0068defc315d)

Closes #5182
2024-10-27 09:16:10 +02:00
Hadrien Patte
54a758a1b8 Use OperatingSystem class to get OS information
(cherry picked from commit 135b5c2ddd8f0a274b0d59eb07f75aaf1446b9da)
2024-10-27 09:13:46 +02:00
Bogdan
ca5379f817 Fixed: Natural sorting for tags list in the UI
(cherry picked from commit 10b55bbee656774a81541904d6dbb2fd5c8c9b7a)
2024-10-27 04:57:15 +02:00
Bogdan
96b51a02e2 Fixed: Status check for completed directories in Deluge
(cherry picked from commit 33139d4b53c1adad769c7e2b0510e8990c66b84a)
2024-10-27 04:57:00 +02:00
Bogdan
f7acd57f73 Cleanse exceptions in event logs
(cherry picked from commit 404e6d68ea526ab521cd39ecda1bf3b02285765d)
2024-10-27 04:56:38 +02:00
Bogdan
20eb61dbc6 Bump version to 2.8.0 2024-10-26 09:11:29 +03:00
Weblate
cb6608975e Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Ardenet <1213193613@qq.com>
Co-authored-by: Fixer <ygj59783@zslsz.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: fordas <fordas15@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ar/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/bg/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/cs/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/da/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/el/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/he/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/hi/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/hr/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/id/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/is/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ja/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ko/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/nb_NO/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/nl/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/pl/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/pt/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ro/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ru/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/sk/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/sv/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/th/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/tr/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/uk/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/vi/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/zh_CN/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/zh_TW/
Translation: Servarr/Lidarr
2024-10-26 07:50:24 +03:00
Bogdan
2db04a3452 Rename unused CancelMessageText 2024-10-20 11:11:10 +03:00
Bogdan
5cead5f7ff Bump version to 2.7.1 2024-10-20 08:04:01 +03:00
Weblate
850c08dda3 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: JoseFilipeFerreira <jose.filipe.matos.ferreira@gmail.com>
Co-authored-by: Kuzmich <kuzmich55@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/da/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/hr/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/pt/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ru/
Translation: Servarr/Lidarr
2024-10-20 06:07:14 +03:00
Bogdan
f005695b48 Skip spotify mapping tests 2024-10-20 06:05:35 +03:00
Mark McDowall
55626594c5 New: Allow major version updates to be installed
(cherry picked from commit 0e95ba2021b23cc65bce0a0620dd48e355250dab)
2024-10-20 06:05:35 +03:00
Bogdan
c645afc389 Bump frontend packages 2024-10-13 23:32:20 +03:00
Bogdan
33d6169882 Bump dotnet to 6.0.35 2024-10-13 23:32:20 +03:00
Hadrien Patte
c750f4764f
Sync OsInfo with upstream (#5163) 2024-10-09 19:52:58 +03:00
Bogdan
c6c52c4117 Bump version to 2.7.0 2024-10-09 14:06:33 +03:00
Servarr
0e9a5fbd04 Automated API Docs update 2024-10-08 15:48:17 +03:00
Weblate
f3cd49a2da Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Ardenet <1213193613@qq.com>
Co-authored-by: FloatStream <1213193613@qq.com>
Co-authored-by: GkhnGRBZ <gkhn.gurbuz@hotmail.com>
Co-authored-by: Lizandra Candido da Silva <lizandra.c.s@gmail.com>
Co-authored-by: Mathias <mathias@rodilbach.dk>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: angelsky11 <angelsky11@gmail.com>
Co-authored-by: anne <gagatebis@hotmail.com>
Co-authored-by: fordas <fordas15@gmail.com>
Co-authored-by: jsain <josip.sain@gmail.com>
Co-authored-by: liuwqq <843384478@qq.com>
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/da/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/hr/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ru/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/tr/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/uk/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/zh_CN/
Translation: Servarr/Lidarr
2024-10-08 02:20:10 +03:00
Mark McDowall
1a74118d6b New: Use 307 redirect for requests missing URL Base
(cherry picked from commit 39074b0b1d040969f86d787c2346d5ed5a9f72dc)
2024-10-08 02:19:48 +03:00
Bogdan
9850823298 Fixed: Error updating providers with ID missing from JSON
(cherry picked from commit c435fcd685cc97e98d14f747227eefd39e4d1164)
2024-10-08 02:19:36 +03:00
Bogdan
bd7d25f963 Fixed: Sorting by title and release dates in Select Album modal
Fixes #5145
Closes #5125

Co-authored-by: Mark McDowall <mark@mcdowall.ca>
2024-10-07 16:49:27 +03:00
Bogdan
3a5012655e Bump macOS runner version to 13 2024-10-06 16:22:42 +03:00
Bogdan
ba55a4778a Bump version to 2.6.4 2024-10-06 12:03:57 +03:00
Servarr
ff91589f73 Automated API Docs update 2024-10-03 21:13:18 +03:00
Bogdan
2caba01123 Fix tests for nested artist folders 2024-10-03 15:18:59 +03:00
Bogdan
4588bc4a7e Fixed: Manual importing to nested artist folders 2024-10-03 14:47:36 +03:00
ManiMatter
3381ffc311
New: Last Searched column on Wanted screens (#5084)
* Added lastSearchTime to API & Wanted Screens.
2024-10-02 22:52:27 +03:00
ManiMatter
f705603211
Updated .gitignore to remove duplications and add '_temp*' (#5142) 2024-10-02 22:50:43 +03:00
Bogdan
715274bcc7 Improve indexer name for RED 2024-10-02 09:35:45 +03:00
Bogdan
9b063aa291 Bump version to 2.6.3 2024-09-29 08:19:05 +03:00
Robin Dadswell
af4ff00476 Fixed: Telegram log message including token
(cherry picked from commit a7cb264cc8013d9a56aee7d5e41acfd76cde5f96)
2024-09-28 05:06:49 +03:00
Bogdan
b14c647c86 Display naming example errors when all fields are empty
(cherry picked from commit 768af433d1655c587a9eee9b100f306ba4345f88)
2024-09-28 05:06:23 +03:00
Bogdan
00cca22dc7 Fixed: Adding individual albums for existing artists 2024-09-23 03:48:14 +03:00
Emmanuel Ferdman
73fddd5201 Update license reference
Signed-off-by: Emmanuel Ferdman <emmanuelferdman@gmail.com>
2024-09-22 21:55:42 +03:00
Bogdan
b7e5a745a1 Bump version to 2.6.2 2024-09-22 07:46:32 +03:00
Servarr
b67533bccf Automated API Docs update 2024-09-22 05:22:37 +03:00
Bogdan
21d9ecccd6 Fixed: Improve validation for individual album adding 2024-09-22 04:48:21 +03:00
momo
34c9300cbf Fix description for API key as query parameter
(cherry picked from commit 30c36fdc3baa686102ff124833c7963fc786f251)
2024-09-21 21:18:39 +03:00
Mark McDowall
3e5af06622 Fixed: Unable to login when instance name contained brackets 2024-09-21 02:51:27 +03:00
Bogdan
ccce4f5cc0
New: Show warning in queue if download contains executable or archive file and no audio file was detected (#5106)
* Improve handling of releases without audio files

New: Show warning in queue if download contains executable or archive file and no audio file was detected

(cherry picked from commit b15b6a079846b21cac8476820fce9cde81732291)

* New: Add additional archive exentions

(cherry picked from commit 750a9353f82da4e016bee25e0c625cd6d8613b57)

---------

Co-authored-by: Mark McDowall <mark@mcdowall.ca>
2024-09-18 01:26:48 +03:00
Mark McDowall
5947b4642c New: Check for available space before grabbing
(cherry picked from commit 4b5ff3927d3c123f9e3a2bc74328323fab1b0745)

Closes #5095
2024-09-17 17:40:56 +03:00
Mark McDowall
856ac2ffa5 New: Add exception to SSL Certificate validation message
(cherry picked from commit d84c4500949a530fac92d73f7f2f8e8462b37244)

Closes #5103
2024-09-17 17:40:56 +03:00
Bogdan
b2a4c75cce Fixed: Refresh tags after updating autotags
(cherry picked from commit 6a332b40ac94e6e7c23217074da8e18e0ca3a319)

Closes #5093
2024-09-17 17:40:56 +03:00
Mark McDowall
2818f4e073 New: Use instance name in forms authentication cookie name
(cherry picked from commit 97ebaf279650082c6baee9563ef179921c5ed25a)

Closes #5102
2024-09-17 17:40:56 +03:00
Weblate
60fe75877b Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: fordas <fordas15@gmail.com>
Co-authored-by: genoher <genoher@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/es/
Translation: Servarr/Lidarr
2024-09-17 17:16:04 +03:00
Bogdan
2170ada8a2 Fixed: Linking autotags with tag specification to all tags
(cherry picked from commit a929548ae38d2c5504b961f22131897508d26470)
2024-09-16 17:03:47 +03:00
Bogdan
c26c0d5bd6 Bump version to 2.6.1 2024-09-15 15:55:04 +03:00
Weblate
d17c6a9b3e Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: FloatStream <1213193613@qq.com>
Co-authored-by: Kuzmich55 <kuzmich55@gmail.com>
Co-authored-by: Lizandra Candido da Silva <lizandra.c.s@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ru/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/zh_CN/
Translation: Servarr/Lidarr
2024-09-10 23:46:26 +03:00
Bogdan
af6c0cc6f5 Display secondary types on album details 2024-09-08 17:12:30 +03:00
Bogdan
21344361e4 Add weblate widget 2024-09-08 11:30:19 +03:00
Weblate
8efb602531 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Dream <seth.gecko.rr@gmail.com>
Co-authored-by: FloatStream <1213193613@qq.com>
Co-authored-by: Gabriel Markowski <gmarkowski62@gmail.com>
Co-authored-by: GkhnGRBZ <gkhn.gurbuz@hotmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Jason54 <jason54700.jg@gmail.com>
Co-authored-by: Kerk en IT <info@kerkenit.nl>
Co-authored-by: Lizandra Candido da Silva <lizandra.c.s@gmail.com>
Co-authored-by: MattiaPell <mattiapellegrini16@gmail.com>
Co-authored-by: Nota Inutilis <hugo@notainutilis.fr>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: fordas <fordas15@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ar/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/bg/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/cs/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/da/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/el/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/he/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/hi/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/hr/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/is/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ja/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ko/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/nb_NO/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/nl/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/pl/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/pt/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ro/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/ru/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/sk/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/sv/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/th/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/tr/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/uk/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/vi/
Translate-URL: https://translate.servarr.com/projects/servarr/lidarr/zh_CN/
Translation: Servarr/Lidarr
2024-09-04 19:45:28 +03:00
Bogdan
bd5f171fa9 Bump version to 2.6.0 2024-09-01 10:29:06 +03:00
Bogdan
1dee2aaf80 Fix tests 2024-09-01 09:10:41 +03:00
Bogdan
f024dad65f Bump workflow actions 2024-09-01 09:10:41 +03:00
Erik Lentz
ef3b644d52
Fixed: Update English Localization reference to Movies (#5061) 2024-08-28 13:37:32 -05:00
Bogdan
af4eeeb893 Don't persist value for SslCertHash when checking for existence
(cherry picked from commit 98c4cbdd13dc49ad30e91343897b8bd006002489)
2024-08-27 07:53:02 +03:00
Servarr
7738ee78c8 Automated API Docs update 2024-08-27 07:52:50 +03:00
Bogdan
8d3dc0a470 Validation for bulk series editor
Closes #4983
2024-08-26 07:07:20 +03:00
Mark McDowall
2b8b8ed147 New: Configurable log file size limit
(cherry picked from commit 813965e6a20edef2772d68eaa7646af33028425a)

Closes #4982
2024-08-26 07:00:11 +03:00
Mark McDowall
828e04bcad New: Add Compact Log Event Format option for console logging
(cherry picked from commit 0d914f4c53876540ed2df83ad3d71615c013856f)

Closes #4981
2024-08-26 06:54:23 +03:00
Bogdan
bb6528c104 Upgrade nlog to 5.3.3
Closes #4980
2024-08-26 06:50:53 +03:00
Bogdan
f49388f3c4 Fixed: Ensure Root Folder exists when Adding Artist
Closes #5041
2024-08-26 06:44:39 +03:00
Bogdan
8ff8c27e24 New: Root folder exists validation for import lists
Closes #4820
2024-08-26 06:42:42 +03:00
martylukyy
281bcb28fe New: Configure log file size limit in UI
(cherry picked from commit 35baebaf7280749d5dfe5440e28b425e45a22d21)

Closes #5023
2024-08-26 06:37:07 +03:00
Bogdan
e60a219671 Bump babel packages
Closes #5025
2024-08-26 06:35:00 +03:00
Bogdan
34ac9dbfcb Use autoprefixer in UI build
(cherry picked from commit 47a05ecb36e5c960b4f6ca7d279df7c281114611)

Closes #5024
2024-08-26 06:33:54 +03:00
Bogdan
30ceb77615 New: Bulk manage custom formats
Closes #5050
2024-08-26 04:32:16 +03:00
Bogdan
304646f324 Fixed: Hide reboot and shutdown UI buttons on docker
Closes #5048
2024-08-26 04:21:19 +03:00
bakerboy448
7555141961 Fixed: Trim spaces and empty values in Proxy Bypass List
(cherry picked from commit 846333ddf0d9da775c80d004fdb9b41e700ef359)

Closes #5044
Closes #5045
2024-08-26 04:19:31 +03:00
Bogdan
df09e903d4 New: Bypass IP addresses ranges in proxies
(cherry picked from commit 402db9128c214d4c5af6583643cb49d3aa7a28b5)
2024-08-26 04:17:46 +03:00
Bogdan
88f4c0c6cd Fix disabled style for monitor toggle button
(cherry picked from commit dde28cbd7e16b85f78d38c8dde7cf6bbb6119bb3)
2024-08-26 04:16:51 +03:00
Treycos
8f9281f914 Updated code action fixall value for VSCode
(cherry picked from commit 8af4246ff9baee4c291550102769a1186f65dc29)
2024-08-26 04:16:41 +03:00
Mark McDowall
5fed16c38a Fixed: Limit redirects after login to local paths
(cherry picked from commit 14005d8d1054eafaba808337a109d5812f3e79e6)
2024-08-26 04:16:28 +03:00
Bogdan
963ffbea4e Bump version to 2.5.3 2024-08-25 10:15:40 +03:00
Bogdan
b514de2840 Revert "Fixed: Stale formats score after changing quality profile for artists"
This reverts commit afbead8a88.
2024-08-18 20:10:27 +03:00
Bogdan
6673d14edd Fixed: Duplicated changelog lines 2024-08-18 18:22:08 +03:00
Mark McDowall
da954dc31e Align queue action buttons on right
(cherry picked from commit f7a58aab339e2012b6bb91d0b3a38d733ec213c6)

Closes #4989
2024-08-18 18:20:16 +03:00
Bogdan
51d22bed2a Include available version in update health check
(cherry picked from commit 15e3c3efb18242caf28b9bfc77a72a78296018bf)
(cherry picked from commit 3b29096e402c9a738b12ca8085b97924c52577f9)

Closes #4949
Closes #5000
2024-08-18 18:18:19 +03:00
Bogdan
04e0d3f22e Skip duplicate import list exclusions
(cherry picked from commit 9af2f137f41867a29d544fad77551672a79f24b6)

Closes #5003
2024-08-18 18:14:26 +03:00
Bogdan
809db4022e Fixed: Persist selected custom filter for interactive searches
Closes #5006
2024-08-18 17:59:03 +03:00
Bogdan
afbead8a88 Fixed: Stale formats score after changing quality profile for artists
Closes #5009
2024-08-18 17:57:54 +03:00
Bogdan
950e94564e Sort quality and metadata profiles by name in custom filters
(cherry picked from commit dc7a16a03ae7d1f2492e7cca26de5a0ecbdde96b)

Closes #5010
2024-08-18 17:45:58 +03:00
Bogdan
790e1233ec Bump version to 2.5.2 2024-08-18 15:03:17 +03:00
431 changed files with 10901 additions and 5721 deletions

View file

@ -6,7 +6,7 @@
"features": {
"ghcr.io/devcontainers/features/node:1": {
"nodeGypDependencies": true,
"version": "16",
"version": "20",
"nvmVersion": "latest"
}
},

View file

@ -60,6 +60,7 @@ body:
- Master
- Develop
- Nightly
- Plugins (experimental)
- Other (This issue will be closed)
validations:
required: true

View file

@ -12,6 +12,6 @@ jobs:
action:
runs-on: ubuntu-latest
steps:
- uses: dessant/label-actions@v3
- uses: dessant/label-actions@v4
with:
process-only: 'issues'

View file

@ -9,7 +9,7 @@ jobs:
lock:
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@v4
- uses: dessant/lock-threads@v5
with:
github-token: ${{ github.token }}
issue-inactive-days: '90'

35
.gitignore vendored
View file

@ -121,6 +121,7 @@ _artifacts
_rawPackage/
_dotTrace*
_tests/
_temp*
*.Result.xml
coverage*.xml
coverage*.json
@ -139,12 +140,6 @@ project.fragment.lock.json
artifacts/
**/Properties/launchSettings.json
#VS outout folders
bin
obj
output/*
# macOS metadata files
._*
.DS_Store
@ -163,34 +158,12 @@ Thumbs.db
/tools/Addins/*
packages.config.md5sum
# Common IntelliJ Platform excludes
# User specific
**/.idea/**/workspace.xml
**/.idea/**/tasks.xml
**/.idea/shelf/*
**/.idea/dictionaries
**/.idea/.idea.Radarr.Posix
**/.idea/.idea.Radarr.Windows
# Sensitive or high-churn files
**/.idea/**/dataSources/
**/.idea/**/dataSources.ids
**/.idea/**/dataSources.xml
**/.idea/**/dataSources.local.xml
**/.idea/**/sqlDataSources.xml
**/.idea/**/dynamic.xml
# Rider
# Rider auto-generates .iml files, and contentModel.xml
**/.idea/**/*.iml
**/.idea/**/contentModel.xml
**/.idea/**/modules.xml
# ignore node_modules symlink
node_modules
node_modules.nosync
# API doc generation
.config/
# Ignore Jetbrains IntelliJ Workspace Directories
.idea/

View file

@ -1,6 +1,7 @@
# Lidarr
[![Build Status](https://dev.azure.com/Lidarr/Lidarr/_apis/build/status/lidarr.Lidarr?branchName=develop)](https://dev.azure.com/Lidarr/Lidarr/_build/latest?definitionId=1&branchName=develop)
[![Translation status](https://translate.servarr.com/widget/servarr/lidarr/svg-badge.svg)](https://translate.servarr.com/engage/servarr/?utm_source=widget)
[![Docker Pulls](https://img.shields.io/docker/pulls/linuxserver/lidarr.svg)](https://wiki.servarr.com/lidarr/installation#docker)
![Github Downloads](https://img.shields.io/github/downloads/lidarr/lidarr/total.svg)
[![Backers on Open Collective](https://opencollective.com/lidarr/backers/badge.svg)](#backers)

View file

@ -9,18 +9,18 @@ variables:
testsFolder: './_tests'
yarnCacheFolder: $(Pipeline.Workspace)/.yarn
nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages
majorVersion: '2.5.1'
majorVersion: '2.13.1'
minorVersion: $[counter('minorVersion', 1076)]
lidarrVersion: '$(majorVersion).$(minorVersion)'
buildName: '$(Build.SourceBranchName).$(lidarrVersion)'
sentryOrg: 'servarr'
sentryUrl: 'https://sentry.servarr.com'
dotnetVersion: '6.0.424'
dotnetVersion: '6.0.427'
nodeVersion: '20.X'
innoVersion: '6.2.0'
windowsImage: 'windows-2022'
linuxImage: 'ubuntu-20.04'
macImage: 'macOS-12'
linuxImage: 'ubuntu-22.04'
macImage: 'macOS-13'
trigger:
branches:
@ -1120,19 +1120,19 @@ stages:
vmImage: ${{ variables.windowsImage }}
steps:
- checkout: self # Need history for Sonar analysis
- task: SonarCloudPrepare@2
- task: SonarCloudPrepare@3
env:
SONAR_SCANNER_OPTS: ''
inputs:
SonarCloud: 'SonarCloud'
organization: 'lidarr'
scannerMode: 'CLI'
scannerMode: 'cli'
configMode: 'manual'
cliProjectKey: 'lidarr_Lidarr.UI'
cliProjectName: 'LidarrUI'
cliProjectVersion: '$(lidarrVersion)'
cliSources: './frontend'
- task: SonarCloudAnalyze@2
- task: SonarCloudAnalyze@3
- job: Api_Docs
displayName: API Docs
@ -1208,12 +1208,12 @@ stages:
submodules: true
- powershell: Set-Service SCardSvr -StartupType Manual
displayName: Enable Windows Test Service
- task: SonarCloudPrepare@2
- task: SonarCloudPrepare@3
condition: eq(variables['System.PullRequest.IsFork'], 'False')
inputs:
SonarCloud: 'SonarCloud'
organization: 'lidarr'
scannerMode: 'MSBuild'
scannerMode: 'dotnet'
projectKey: 'lidarr_Lidarr'
projectName: 'Lidarr'
projectVersion: '$(lidarrVersion)'
@ -1226,10 +1226,10 @@ stages:
./build.sh --backend -f net6.0 -r win-x64
TEST_DIR=_tests/net6.0/win-x64/publish/ ./test.sh Windows Unit Coverage
displayName: Coverage Unit Tests
- task: SonarCloudAnalyze@2
- task: SonarCloudAnalyze@3
condition: eq(variables['System.PullRequest.IsFork'], 'False')
displayName: Publish SonarCloud Results
- task: reportgenerator@5
- task: reportgenerator@5.3.11
displayName: Generate Coverage Report
inputs:
reports: '$(Build.SourcesDirectory)/CoverageResults/**/coverage.opencover.xml'

15
docs.sh
View file

@ -1,13 +1,18 @@
#!/bin/bash
set -e
FRAMEWORK="net6.0"
PLATFORM=$1
ARCHITECTURE="${2:-x64}"
if [ "$PLATFORM" = "Windows" ]; then
RUNTIME="win-x64"
RUNTIME="win-$ARCHITECTURE"
elif [ "$PLATFORM" = "Linux" ]; then
RUNTIME="linux-x64"
RUNTIME="linux-$ARCHITECTURE"
elif [ "$PLATFORM" = "Mac" ]; then
RUNTIME="osx-x64"
RUNTIME="osx-$ARCHITECTURE"
else
echo "Platform must be provided as first arguement: Windows, Linux or Mac"
echo "Platform must be provided as first argument: Windows, Linux or Mac"
exit 1
fi
@ -35,7 +40,7 @@ dotnet msbuild -restore $slnFile -p:Configuration=Debug -p:Platform=$platform -p
dotnet new tool-manifest
dotnet tool install --version 6.6.2 Swashbuckle.AspNetCore.Cli
dotnet tool run swagger tofile --output ./src/Lidarr.Api.V1/openapi.json "$outputFolder/net6.0/$RUNTIME/$application" v1 &
dotnet tool run swagger tofile --output ./src/Lidarr.Api.V1/openapi.json "$outputFolder/$FRAMEWORK/$RUNTIME/$application" v1 &
sleep 45

View file

@ -9,7 +9,7 @@
"editor.formatOnSave": false,
"editor.codeActionsOnSave": {
"source.fixAll": true
"source.fixAll": "explicit"
},
"typescript.preferences.quoteStyle": "single",

View file

@ -26,6 +26,7 @@ module.exports = (env) => {
const config = {
mode: isProduction ? 'production' : 'development',
devtool: isProduction ? 'source-map' : 'eval-source-map',
target: 'web',
stats: {
children: false
@ -134,6 +135,12 @@ module.exports = (env) => {
{
source: 'frontend/src/Content/robots.txt',
destination: path.join(distFolder, 'Content/robots.txt')
},
// manifest.json and browserconfig.xml
{
source: 'frontend/src/Content/*.(json|xml)',
destination: path.join(distFolder, 'Content')
}
]
}
@ -181,7 +188,7 @@ module.exports = (env) => {
loose: true,
debug: false,
useBuiltIns: 'entry',
corejs: 3
corejs: '3.41'
}
]
]

View file

@ -16,6 +16,7 @@ const mixinsFiles = [
module.exports = {
plugins: [
'autoprefixer',
['postcss-mixins', {
mixinsFiles
}],

View file

@ -172,7 +172,8 @@ function HistoryDetails(props) {
if (eventType === 'downloadFailed') {
const {
message
message,
indexer
} = data;
return (
@ -192,6 +193,14 @@ function HistoryDetails(props) {
null
}
{
indexer ? (
<DescriptionListItem
title={translate('Indexer')}
data={indexer}
/>
) : null}
{
message ?
<DescriptionListItem

View file

@ -26,4 +26,5 @@
composes: cell from '~Components/Table/Cells/TableRowCell.css';
width: 90px;
text-align: right;
}

View file

@ -57,30 +57,40 @@ function QueueStatusCell(props) {
if (status === 'paused') {
iconName = icons.PAUSED;
title = 'Paused';
title = translate('Paused');
}
if (status === 'queued') {
iconName = icons.QUEUED;
title = 'Queued';
title = translate('Queued');
}
if (status === 'completed') {
iconName = icons.DOWNLOADED;
title = 'Downloaded';
title = translate('Downloaded');
if (trackedDownloadState === 'importBlocked') {
title += ` - ${translate('UnableToImportAutomatically')}`;
iconKind = kinds.WARNING;
}
if (trackedDownloadState === 'importFailed') {
title += ` - ${translate('ImportFailed', { sourceTitle })}`;
iconKind = kinds.WARNING;
}
if (trackedDownloadState === 'importPending') {
title += ' - Waiting to Import';
title += ` - ${translate('WaitingToImport')}`;
iconKind = kinds.PURPLE;
}
if (trackedDownloadState === 'importing') {
title += ' - Importing';
title += ` - ${translate('Importing')}`;
iconKind = kinds.PURPLE;
}
if (trackedDownloadState === 'failedPending') {
title += ' - Waiting to Process';
title += ` - ${translate('WaitingToProcess')}`;
iconKind = kinds.DANGER;
}
}
@ -91,36 +101,38 @@ function QueueStatusCell(props) {
if (status === 'delay') {
iconName = icons.PENDING;
title = 'Pending';
title = translate('Pending');
}
if (status === 'downloadClientUnavailable') {
iconName = icons.PENDING;
iconKind = kinds.WARNING;
title = 'Pending - Download client is unavailable';
title = translate('PendingDownloadClientUnavailable');
}
if (status === 'failed') {
iconName = icons.DOWNLOADING;
iconKind = kinds.DANGER;
title = 'Download failed';
title = translate('DownloadFailed');
}
if (status === 'warning') {
iconName = icons.DOWNLOADING;
iconKind = kinds.WARNING;
title = `Download warning: ${errorMessage || 'check download client for more details'}`;
const warningMessage =
errorMessage || translate('CheckDownloadClientForDetails');
title = translate('DownloadWarning', { warningMessage });
}
if (hasError) {
if (status === 'completed') {
iconName = icons.DOWNLOAD;
iconKind = kinds.DANGER;
title = `Import failed: ${sourceTitle}`;
title = translate('ImportFailed', { sourceTitle });
} else {
iconName = icons.DOWNLOADING;
iconKind = kinds.DANGER;
title = 'Download failed';
title = translate('DownloadFailed');
}
}

View file

@ -20,6 +20,7 @@ interface Album extends ModelBase {
monitored: boolean;
releaseDate: string;
statistics: Statistics;
lastSearchTime?: string;
isSaving?: boolean;
}

View file

@ -121,6 +121,8 @@
.releaseDate,
.sizeOnDisk,
.albumType,
.secondaryTypes,
.qualityProfileName,
.links,
.tags {

View file

@ -3,6 +3,7 @@
interface CssExports {
'albumNavigationButton': string;
'albumNavigationButtons': string;
'albumType': string;
'alternateTitlesIconContainer': string;
'backdrop': string;
'backdropOverlay': string;
@ -20,6 +21,7 @@ interface CssExports {
'overview': string;
'qualityProfileName': string;
'releaseDate': string;
'secondaryTypes': string;
'sizeOnDisk': string;
'tags': string;
'title': string;

View file

@ -192,6 +192,7 @@ class AlbumDetails extends Component {
duration,
overview,
albumType,
secondaryTypes,
statistics = {},
monitored,
releaseDate,
@ -204,6 +205,7 @@ class AlbumDetails extends Component {
isFetching,
isPopulated,
albumsError,
tracksError,
trackFilesError,
hasTrackFiles,
shortDateFormat,
@ -396,10 +398,11 @@ class AlbumDetails extends Component {
<div className={styles.details}>
<div>
{
!!duration &&
duration ?
<span className={styles.duration}>
{formatDuration(duration)}
</span>
</span> :
null
}
<HeartRating
@ -418,14 +421,15 @@ class AlbumDetails extends Component {
title={translate('ReleaseDate')}
size={sizes.LARGE}
>
<div>
<Icon
name={icons.CALENDAR}
size={17}
/>
<span className={styles.releaseDate}>
{moment(releaseDate).format(shortDateFormat)}
</span>
</div>
</Label>
<Tooltip
@ -434,16 +438,15 @@ class AlbumDetails extends Component {
className={styles.detailsLabel}
size={sizes.LARGE}
>
<div>
<Icon
name={icons.DRIVE}
size={17}
/>
<span className={styles.sizeOnDisk}>
{
formatBytes(sizeOnDisk || 0)
}
{formatBytes(sizeOnDisk)}
</span>
</div>
</Label>
}
tooltip={
@ -459,32 +462,55 @@ class AlbumDetails extends Component {
className={styles.detailsLabel}
size={sizes.LARGE}
>
<div>
<Icon
name={monitored ? icons.MONITORED : icons.UNMONITORED}
size={17}
/>
<span className={styles.qualityProfileName}>
{monitored ? translate('Monitored') : translate('Unmonitored')}
</span>
</div>
</Label>
{
!!albumType &&
albumType ?
<Label
className={styles.detailsLabel}
title={translate('Type')}
size={sizes.LARGE}
>
<div>
<Icon
name={icons.INFO}
size={17}
/>
<span className={styles.qualityProfileName}>
<span className={styles.albumType}>
{albumType}
</span>
</Label>
</div>
</Label> :
null
}
{
secondaryTypes.length ?
<Label
className={styles.detailsLabel}
title={translate('SecondaryTypes')}
size={sizes.LARGE}
>
<div>
<Icon
name={icons.INFO}
size={17}
/>
<span className={styles.secondaryTypes}>
{secondaryTypes.join(', ')}
</span>
</div>
</Label> :
null
}
<Tooltip
@ -493,14 +519,15 @@ class AlbumDetails extends Component {
className={styles.detailsLabel}
size={sizes.LARGE}
>
<div>
<Icon
name={icons.EXTERNAL_LINK}
size={17}
/>
<span className={styles.links}>
{translate('Links')}
</span>
</div>
</Label>
}
tooltip={
@ -526,8 +553,9 @@ class AlbumDetails extends Component {
<div className={styles.contentContainer}>
{
!isPopulated && !albumsError && !trackFilesError &&
<LoadingIndicator />
!isPopulated && !albumsError && !tracksError && !trackFilesError ?
<LoadingIndicator /> :
null
}
{
@ -538,6 +566,14 @@ class AlbumDetails extends Component {
null
}
{
!isFetching && tracksError ?
<Alert kind={kinds.DANGER}>
{translate('TracksLoadError')}
</Alert> :
null
}
{
!isFetching && trackFilesError ?
<Alert kind={kinds.DANGER}>
@ -566,6 +602,14 @@ class AlbumDetails extends Component {
</div>
}
{
isPopulated && !media.length ?
<Alert kind={kinds.WARNING}>
{translate('NoMediumInformation')}
</Alert> :
null
}
</div>
<OrganizePreviewModalConnector
@ -632,6 +676,7 @@ AlbumDetails.propTypes = {
duration: PropTypes.number,
overview: PropTypes.string,
albumType: PropTypes.string.isRequired,
secondaryTypes: PropTypes.arrayOf(PropTypes.string).isRequired,
statistics: PropTypes.object.isRequired,
releaseDate: PropTypes.string.isRequired,
ratings: PropTypes.object.isRequired,
@ -658,6 +703,8 @@ AlbumDetails.propTypes = {
};
AlbumDetails.defaultProps = {
secondaryTypes: [],
statistics: {},
isSaving: false
};

View file

@ -29,7 +29,7 @@ import LogsTableConnector from 'System/Events/LogsTableConnector';
import Logs from 'System/Logs/Logs';
import Status from 'System/Status/Status';
import Tasks from 'System/Tasks/Tasks';
import UpdatesConnector from 'System/Updates/UpdatesConnector';
import Updates from 'System/Updates/Updates';
import UnmappedFilesTableConnector from 'UnmappedFiles/UnmappedFilesTableConnector';
import getPathWithUrlBase from 'Utilities/getPathWithUrlBase';
import CutoffUnmetConnector from 'Wanted/CutoffUnmet/CutoffUnmetConnector';
@ -248,7 +248,7 @@ function AppRoutes(props) {
<Route
path="/system/updates"
component={UpdatesConnector}
component={Updates}
/>
<Route

View file

@ -44,6 +44,7 @@ export interface CustomFilter {
}
export interface AppSectionState {
version: string;
dimensions: {
isSmallScreen: boolean;
width: number;

View file

@ -4,6 +4,7 @@ import AppSectionState, {
AppSectionSaveState,
AppSectionSchemaState,
} from 'App/State/AppSectionState';
import CustomFormat from 'typings/CustomFormat';
import DownloadClient from 'typings/DownloadClient';
import ImportList from 'typings/ImportList';
import Indexer from 'typings/Indexer';
@ -12,13 +13,16 @@ import MetadataProfile from 'typings/MetadataProfile';
import Notification from 'typings/Notification';
import QualityProfile from 'typings/QualityProfile';
import RootFolder from 'typings/RootFolder';
import { UiSettings } from 'typings/UiSettings';
import General from 'typings/Settings/General';
import UiSettings from 'typings/Settings/UiSettings';
export interface DownloadClientAppState
extends AppSectionState<DownloadClient>,
AppSectionDeleteState,
AppSectionSaveState {}
export type GeneralAppState = AppSectionItemState<General>;
export interface ImportListAppState
extends AppSectionState<ImportList>,
AppSectionDeleteState,
@ -41,6 +45,11 @@ export interface MetadataProfilesAppState
extends AppSectionState<MetadataProfile>,
AppSectionSchemaState<MetadataProfile> {}
export interface CustomFormatAppState
extends AppSectionState<CustomFormat>,
AppSectionDeleteState,
AppSectionSaveState {}
export interface RootFolderAppState
extends AppSectionState<RootFolder>,
AppSectionDeleteState,
@ -50,7 +59,10 @@ export type IndexerFlagSettingsAppState = AppSectionState<IndexerFlag>;
export type UiSettingsAppState = AppSectionItemState<UiSettings>;
interface SettingsAppState {
advancedSettings: boolean;
customFormats: CustomFormatAppState;
downloadClients: DownloadClientAppState;
general: GeneralAppState;
importLists: ImportListAppState;
indexerFlags: IndexerFlagSettingsAppState;
indexers: IndexerAppState;

View file

@ -1,9 +1,12 @@
import SystemStatus from 'typings/SystemStatus';
import { AppSectionItemState } from './AppSectionState';
import Update from 'typings/Update';
import AppSectionState, { AppSectionItemState } from './AppSectionState';
export type SystemStatusAppState = AppSectionItemState<SystemStatus>;
export type UpdateAppState = AppSectionState<Update>;
interface SystemAppState {
updates: UpdateAppState;
status: SystemStatusAppState;
}

View file

@ -149,9 +149,7 @@ class AlbumRow extends Component {
if (name === 'secondaryTypes') {
return (
<TableRowCell key={name}>
{
secondaryTypes
}
{secondaryTypes.join(', ')}
</TableRowCell>
);
}

View file

@ -15,7 +15,7 @@ import ModalContent from 'Components/Modal/ModalContent';
import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader';
import Popover from 'Components/Tooltip/Popover';
import { icons, inputTypes, kinds, tooltipPositions } from 'Helpers/Props';
import { icons, inputTypes, kinds, sizes, tooltipPositions } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import styles from './EditArtistModalContent.css';
@ -93,7 +93,7 @@ class EditArtistModalContent extends Component {
<ModalBody>
<Form {...otherProps}>
<FormGroup>
<FormGroup size={sizes.MEDIUM}>
<FormLabel>
{translate('Monitored')}
</FormLabel>
@ -107,9 +107,10 @@ class EditArtistModalContent extends Component {
/>
</FormGroup>
<FormGroup>
<FormGroup size={sizes.MEDIUM}>
<FormLabel>
{translate('MonitorNewItems')}
<Popover
anchor={
<Icon
@ -132,7 +133,7 @@ class EditArtistModalContent extends Component {
/>
</FormGroup>
<FormGroup>
<FormGroup size={sizes.MEDIUM}>
<FormLabel>
{translate('QualityProfile')}
</FormLabel>
@ -146,10 +147,10 @@ class EditArtistModalContent extends Component {
</FormGroup>
{
showMetadataProfile &&
<FormGroup>
showMetadataProfile ?
<FormGroup size={sizes.MEDIUM}>
<FormLabel>
Metadata Profile
{translate('MetadataProfile')}
<Popover
anchor={
@ -173,10 +174,11 @@ class EditArtistModalContent extends Component {
{...metadataProfileId}
onChange={onInputChange}
/>
</FormGroup>
</FormGroup> :
null
}
<FormGroup>
<FormGroup size={sizes.MEDIUM}>
<FormLabel>
{translate('Path')}
</FormLabel>
@ -189,7 +191,7 @@ class EditArtistModalContent extends Component {
/>
</FormGroup>
<FormGroup>
<FormGroup size={sizes.MEDIUM}>
<FormLabel>
{translate('Tags')}
</FormLabel>
@ -209,7 +211,7 @@ class EditArtistModalContent extends Component {
kind={kinds.DANGER}
onPress={onDeleteArtistPress}
>
Delete
{translate('Delete')}
</Button>
<Button

View file

@ -6,7 +6,7 @@ import { icons } from 'Helpers/Props';
import createUISettingsSelector from 'Store/Selectors/createUISettingsSelector';
import dimensions from 'Styles/Variables/dimensions';
import QualityProfile from 'typings/QualityProfile';
import { UiSettings } from 'typings/UiSettings';
import UiSettings from 'typings/Settings/UiSettings';
import formatDateTime from 'Utilities/Date/formatDateTime';
import getRelativeDate from 'Utilities/Date/getRelativeDate';
import formatBytes from 'Utilities/Number/formatBytes';

View file

@ -164,7 +164,7 @@ class CalendarLinkModalContent extends Component {
type={inputTypes.TAG}
name="tags"
value={tags}
helpText={translate('TagsHelpText')}
helpText={translate('ICalTagsArtistHelpText')}
onChange={this.onInputChange}
/>
</FormGroup>

View file

@ -3,8 +3,8 @@ import React, { Component } from 'react';
import Alert from 'Components/Alert';
import PathInput from 'Components/Form/PathInput';
import Button from 'Components/Link/Button';
import Link from 'Components/Link/Link';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import InlineMarkdown from 'Components/Markdown/InlineMarkdown';
import ModalBody from 'Components/Modal/ModalBody';
import ModalContent from 'Components/Modal/ModalContent';
import ModalFooter from 'Components/Modal/ModalFooter';
@ -117,7 +117,7 @@ class FileBrowserModalContent extends Component {
className={styles.mappedDrivesWarning}
kind={kinds.WARNING}
>
Mapped network drives are not available when running as a Windows Service, see the <Link className={styles.faqLink} to="https://wiki.servarr.com/lidarr/faq">FAQ</Link> for more information.
<InlineMarkdown data={translate('MappedNetworkDrivesWindowsService', { url: 'https://wiki.servarr.com/lidarr/faq#why-cant-lidarr-see-my-files-on-a-remote-server' })} />
</Alert>
}

View file

@ -11,11 +11,11 @@ import DateFilterBuilderRowValue from './DateFilterBuilderRowValue';
import FilterBuilderRowValueConnector from './FilterBuilderRowValueConnector';
import HistoryEventTypeFilterBuilderRowValue from './HistoryEventTypeFilterBuilderRowValue';
import IndexerFilterBuilderRowValueConnector from './IndexerFilterBuilderRowValueConnector';
import MetadataProfileFilterBuilderRowValueConnector from './MetadataProfileFilterBuilderRowValueConnector';
import MetadataProfileFilterBuilderRowValue from './MetadataProfileFilterBuilderRowValue';
import MonitorNewItemsFilterBuilderRowValue from './MonitorNewItemsFilterBuilderRowValue';
import ProtocolFilterBuilderRowValue from './ProtocolFilterBuilderRowValue';
import QualityFilterBuilderRowValueConnector from './QualityFilterBuilderRowValueConnector';
import QualityProfileFilterBuilderRowValueConnector from './QualityProfileFilterBuilderRowValueConnector';
import QualityProfileFilterBuilderRowValue from './QualityProfileFilterBuilderRowValue';
import TagFilterBuilderRowValueConnector from './TagFilterBuilderRowValueConnector';
import styles from './FilterBuilderRow.css';
@ -68,7 +68,7 @@ function getRowValueConnector(selectedFilterBuilderProp) {
return IndexerFilterBuilderRowValueConnector;
case filterBuilderValueTypes.METADATA_PROFILE:
return MetadataProfileFilterBuilderRowValueConnector;
return MetadataProfileFilterBuilderRowValue;
case filterBuilderValueTypes.MONITOR_NEW_ITEMS:
return MonitorNewItemsFilterBuilderRowValue;
@ -80,7 +80,7 @@ function getRowValueConnector(selectedFilterBuilderProp) {
return QualityFilterBuilderRowValueConnector;
case filterBuilderValueTypes.QUALITY_PROFILE:
return QualityProfileFilterBuilderRowValueConnector;
return QualityProfileFilterBuilderRowValue;
case filterBuilderValueTypes.ARTIST:
return ArtistFilterBuilderRowValue;

View file

@ -25,7 +25,7 @@ const EVENT_TYPE_OPTIONS = [
{
id: 7,
get name() {
return translate('ImportFailed');
return translate('ImportCompleteFailed');
},
},
{

View file

@ -0,0 +1,30 @@
import React from 'react';
import { useSelector } from 'react-redux';
import { createSelector } from 'reselect';
import AppState from 'App/State/AppState';
import FilterBuilderRowValueProps from 'Components/Filter/Builder/FilterBuilderRowValueProps';
import sortByProp from 'Utilities/Array/sortByProp';
import FilterBuilderRowValue from './FilterBuilderRowValue';
function createMetadataProfilesSelector() {
return createSelector(
(state: AppState) => state.settings.metadataProfiles.items,
(metadataProfiles) => {
return metadataProfiles;
}
);
}
function MetadataProfileFilterBuilderRowValue(
props: FilterBuilderRowValueProps
) {
const metadataProfiles = useSelector(createMetadataProfilesSelector());
const tagList = metadataProfiles
.map(({ id, name }) => ({ id, name }))
.sort(sortByProp('name'));
return <FilterBuilderRowValue {...props} tagList={tagList} />;
}
export default MetadataProfileFilterBuilderRowValue;

View file

@ -1,28 +0,0 @@
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import FilterBuilderRowValue from './FilterBuilderRowValue';
function createMapStateToProps() {
return createSelector(
(state) => state.settings.metadataProfiles,
(metadataProfiles) => {
const tagList = metadataProfiles.items.map((metadataProfile) => {
const {
id,
name
} = metadataProfile;
return {
id,
name
};
});
return {
tagList
};
}
);
}
export default connect(createMapStateToProps)(FilterBuilderRowValue);

View file

@ -0,0 +1,30 @@
import React from 'react';
import { useSelector } from 'react-redux';
import { createSelector } from 'reselect';
import AppState from 'App/State/AppState';
import FilterBuilderRowValueProps from 'Components/Filter/Builder/FilterBuilderRowValueProps';
import sortByProp from 'Utilities/Array/sortByProp';
import FilterBuilderRowValue from './FilterBuilderRowValue';
function createQualityProfilesSelector() {
return createSelector(
(state: AppState) => state.settings.qualityProfiles.items,
(qualityProfiles) => {
return qualityProfiles;
}
);
}
function QualityProfileFilterBuilderRowValue(
props: FilterBuilderRowValueProps
) {
const qualityProfiles = useSelector(createQualityProfilesSelector());
const tagList = qualityProfiles
.map(({ id, name }) => ({ id, name }))
.sort(sortByProp('name'));
return <FilterBuilderRowValue {...props} tagList={tagList} />;
}
export default QualityProfileFilterBuilderRowValue;

View file

@ -1,28 +0,0 @@
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import FilterBuilderRowValue from './FilterBuilderRowValue';
function createMapStateToProps() {
return createSelector(
(state) => state.settings.qualityProfiles,
(qualityProfiles) => {
const tagList = qualityProfiles.items.map((qualityProfile) => {
const {
id,
name
} = qualityProfile;
return {
id,
name
};
});
return {
tagList
};
}
);
}
export default connect(createMapStateToProps)(FilterBuilderRowValue);

View file

@ -20,6 +20,8 @@ import HintedSelectInputSelectedValue from './HintedSelectInputSelectedValue';
import TextInput from './TextInput';
import styles from './EnhancedSelectInput.css';
const MINIMUM_DISTANCE_FROM_EDGE = 10;
function isArrowKey(keyCode) {
return keyCode === keyCodes.UP_ARROW || keyCode === keyCodes.DOWN_ARROW;
}
@ -137,18 +139,9 @@ class EnhancedSelectInput extends Component {
// Listeners
onComputeMaxHeight = (data) => {
const {
top,
bottom
} = data.offsets.reference;
const windowHeight = window.innerHeight;
if ((/^botton/).test(data.placement)) {
data.styles.maxHeight = windowHeight - bottom;
} else {
data.styles.maxHeight = top;
}
data.styles.maxHeight = windowHeight - MINIMUM_DISTANCE_FROM_EDGE;
return data;
};
@ -457,6 +450,10 @@ class EnhancedSelectInput extends Component {
order: 851,
enabled: true,
fn: this.onComputeMaxHeight
},
preventOverflow: {
enabled: true,
boundariesElement: 'viewport'
}
}}
>

View file

@ -49,12 +49,12 @@ function getComponent(type) {
case inputTypes.DEVICE:
return DeviceInputConnector;
case inputTypes.PLAYLIST:
return PlaylistInputConnector;
case inputTypes.KEY_VALUE_LIST:
return KeyValueListInput;
case inputTypes.PLAYLIST:
return PlaylistInputConnector;
case inputTypes.MONITOR_ALBUMS_SELECT:
return MonitorAlbumsSelectInput;

View file

@ -1,156 +0,0 @@
import classNames from 'classnames';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import KeyValueListInputItem from './KeyValueListInputItem';
import styles from './KeyValueListInput.css';
class KeyValueListInput extends Component {
//
// Lifecycle
constructor(props, context) {
super(props, context);
this.state = {
isFocused: false
};
}
//
// Listeners
onItemChange = (index, itemValue) => {
const {
name,
value,
onChange
} = this.props;
const newValue = [...value];
if (index == null) {
newValue.push(itemValue);
} else {
newValue.splice(index, 1, itemValue);
}
onChange({
name,
value: newValue
});
};
onRemoveItem = (index) => {
const {
name,
value,
onChange
} = this.props;
const newValue = [...value];
newValue.splice(index, 1);
onChange({
name,
value: newValue
});
};
onFocus = () => {
this.setState({
isFocused: true
});
};
onBlur = () => {
this.setState({
isFocused: false
});
const {
name,
value,
onChange
} = this.props;
const newValue = value.reduce((acc, v) => {
if (v.key || v.value) {
acc.push(v);
}
return acc;
}, []);
if (newValue.length !== value.length) {
onChange({
name,
value: newValue
});
}
};
//
// Render
render() {
const {
className,
value,
keyPlaceholder,
valuePlaceholder,
hasError,
hasWarning
} = this.props;
const { isFocused } = this.state;
return (
<div className={classNames(
className,
isFocused && styles.isFocused,
hasError && styles.hasError,
hasWarning && styles.hasWarning
)}
>
{
[...value, { key: '', value: '' }].map((v, index) => {
return (
<KeyValueListInputItem
key={index}
index={index}
keyValue={v.key}
value={v.value}
keyPlaceholder={keyPlaceholder}
valuePlaceholder={valuePlaceholder}
isNew={index === value.length}
onChange={this.onItemChange}
onRemove={this.onRemoveItem}
onFocus={this.onFocus}
onBlur={this.onBlur}
/>
);
})
}
</div>
);
}
}
KeyValueListInput.propTypes = {
className: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
value: PropTypes.arrayOf(PropTypes.object).isRequired,
hasError: PropTypes.bool,
hasWarning: PropTypes.bool,
keyPlaceholder: PropTypes.string,
valuePlaceholder: PropTypes.string,
onChange: PropTypes.func.isRequired
};
KeyValueListInput.defaultProps = {
className: styles.inputContainer,
value: []
};
export default KeyValueListInput;

View file

@ -0,0 +1,104 @@
import classNames from 'classnames';
import React, { useCallback, useState } from 'react';
import { InputOnChange } from 'typings/inputs';
import KeyValueListInputItem from './KeyValueListInputItem';
import styles from './KeyValueListInput.css';
interface KeyValue {
key: string;
value: string;
}
export interface KeyValueListInputProps {
className?: string;
name: string;
value: KeyValue[];
hasError?: boolean;
hasWarning?: boolean;
keyPlaceholder?: string;
valuePlaceholder?: string;
onChange: InputOnChange<KeyValue[]>;
}
function KeyValueListInput({
className = styles.inputContainer,
name,
value = [],
hasError = false,
hasWarning = false,
keyPlaceholder,
valuePlaceholder,
onChange,
}: KeyValueListInputProps): JSX.Element {
const [isFocused, setIsFocused] = useState(false);
const handleItemChange = useCallback(
(index: number | null, itemValue: KeyValue) => {
const newValue = [...value];
if (index === null) {
newValue.push(itemValue);
} else {
newValue.splice(index, 1, itemValue);
}
onChange({ name, value: newValue });
},
[value, name, onChange]
);
const handleRemoveItem = useCallback(
(index: number) => {
const newValue = [...value];
newValue.splice(index, 1);
onChange({ name, value: newValue });
},
[value, name, onChange]
);
const onFocus = useCallback(() => setIsFocused(true), []);
const onBlur = useCallback(() => {
setIsFocused(false);
const newValue = value.reduce((acc: KeyValue[], v) => {
if (v.key || v.value) {
acc.push(v);
}
return acc;
}, []);
if (newValue.length !== value.length) {
onChange({ name, value: newValue });
}
}, [value, name, onChange]);
return (
<div
className={classNames(
className,
isFocused && styles.isFocused,
hasError && styles.hasError,
hasWarning && styles.hasWarning
)}
>
{[...value, { key: '', value: '' }].map((v, index) => (
<KeyValueListInputItem
key={index}
index={index}
keyValue={v.key}
value={v.value}
keyPlaceholder={keyPlaceholder}
valuePlaceholder={valuePlaceholder}
isNew={index === value.length}
onChange={handleItemChange}
onRemove={handleRemoveItem}
onFocus={onFocus}
onBlur={onBlur}
/>
))}
</div>
);
}
export default KeyValueListInput;

View file

@ -5,13 +5,19 @@
&:last-child {
margin-bottom: 0;
border-bottom: 0;
}
}
.inputWrapper {
.keyInputWrapper {
flex: 1 0 0;
}
.valueInputWrapper {
flex: 1 0 0;
min-width: 40px;
}
.buttonWrapper {
flex: 0 0 22px;
}
@ -20,6 +26,10 @@
.valueInput {
width: 100%;
border: none;
background-color: var(--inputBackgroundColor);
background-color: transparent;
color: var(--textColor);
&::placeholder {
color: var(--helpTextColor);
}
}

View file

@ -2,10 +2,11 @@
// Please do not change this file!
interface CssExports {
'buttonWrapper': string;
'inputWrapper': string;
'itemContainer': string;
'keyInput': string;
'keyInputWrapper': string;
'valueInput': string;
'valueInputWrapper': string;
}
export const cssExports: CssExports;
export default cssExports;

View file

@ -1,124 +0,0 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import IconButton from 'Components/Link/IconButton';
import { icons } from 'Helpers/Props';
import TextInput from './TextInput';
import styles from './KeyValueListInputItem.css';
class KeyValueListInputItem extends Component {
//
// Listeners
onKeyChange = ({ value: keyValue }) => {
const {
index,
value,
onChange
} = this.props;
onChange(index, { key: keyValue, value });
};
onValueChange = ({ value }) => {
// TODO: Validate here or validate at a lower level component
const {
index,
keyValue,
onChange
} = this.props;
onChange(index, { key: keyValue, value });
};
onRemovePress = () => {
const {
index,
onRemove
} = this.props;
onRemove(index);
};
onFocus = () => {
this.props.onFocus();
};
onBlur = () => {
this.props.onBlur();
};
//
// Render
render() {
const {
keyValue,
value,
keyPlaceholder,
valuePlaceholder,
isNew
} = this.props;
return (
<div className={styles.itemContainer}>
<div className={styles.inputWrapper}>
<TextInput
className={styles.keyInput}
name="key"
value={keyValue}
placeholder={keyPlaceholder}
onChange={this.onKeyChange}
onFocus={this.onFocus}
onBlur={this.onBlur}
/>
</div>
<div className={styles.inputWrapper}>
<TextInput
className={styles.valueInput}
name="value"
value={value}
placeholder={valuePlaceholder}
onChange={this.onValueChange}
onFocus={this.onFocus}
onBlur={this.onBlur}
/>
</div>
<div className={styles.buttonWrapper}>
{
isNew ?
null :
<IconButton
name={icons.REMOVE}
tabIndex={-1}
onPress={this.onRemovePress}
/>
}
</div>
</div>
);
}
}
KeyValueListInputItem.propTypes = {
index: PropTypes.number,
keyValue: PropTypes.string.isRequired,
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
keyPlaceholder: PropTypes.string.isRequired,
valuePlaceholder: PropTypes.string.isRequired,
isNew: PropTypes.bool.isRequired,
onChange: PropTypes.func.isRequired,
onRemove: PropTypes.func.isRequired,
onFocus: PropTypes.func.isRequired,
onBlur: PropTypes.func.isRequired
};
KeyValueListInputItem.defaultProps = {
keyPlaceholder: 'Key',
valuePlaceholder: 'Value'
};
export default KeyValueListInputItem;

View file

@ -0,0 +1,89 @@
import React, { useCallback } from 'react';
import IconButton from 'Components/Link/IconButton';
import { icons } from 'Helpers/Props';
import TextInput from './TextInput';
import styles from './KeyValueListInputItem.css';
interface KeyValueListInputItemProps {
index: number;
keyValue: string;
value: string;
keyPlaceholder?: string;
valuePlaceholder?: string;
isNew: boolean;
onChange: (index: number, itemValue: { key: string; value: string }) => void;
onRemove: (index: number) => void;
onFocus: () => void;
onBlur: () => void;
}
function KeyValueListInputItem({
index,
keyValue,
value,
keyPlaceholder = 'Key',
valuePlaceholder = 'Value',
isNew,
onChange,
onRemove,
onFocus,
onBlur,
}: KeyValueListInputItemProps): JSX.Element {
const handleKeyChange = useCallback(
({ value: keyValue }: { value: string }) => {
onChange(index, { key: keyValue, value });
},
[index, value, onChange]
);
const handleValueChange = useCallback(
({ value }: { value: string }) => {
onChange(index, { key: keyValue, value });
},
[index, keyValue, onChange]
);
const handleRemovePress = useCallback(() => {
onRemove(index);
}, [index, onRemove]);
return (
<div className={styles.itemContainer}>
<div className={styles.keyInputWrapper}>
<TextInput
className={styles.keyInput}
name="key"
value={keyValue}
placeholder={keyPlaceholder}
onChange={handleKeyChange}
onFocus={onFocus}
onBlur={onBlur}
/>
</div>
<div className={styles.valueInputWrapper}>
<TextInput
className={styles.valueInput}
name="value"
value={value}
placeholder={valuePlaceholder}
onChange={handleValueChange}
onFocus={onFocus}
onBlur={onBlur}
/>
</div>
<div className={styles.buttonWrapper}>
{isNew ? null : (
<IconButton
name={icons.REMOVE}
tabIndex={-1}
onPress={handleRemovePress}
/>
)}
</div>
</div>
);
}
export default KeyValueListInputItem;

View file

@ -14,6 +14,8 @@ function getType({ type, selectOptionsProviderAction }) {
return inputTypes.CHECK;
case 'device':
return inputTypes.DEVICE;
case 'keyValueList':
return inputTypes.KEY_VALUE_LIST;
case 'playlist':
return inputTypes.PLAYLIST;
case 'password':

View file

@ -83,13 +83,6 @@
}
@media only screen and (max-width: $breakpointMedium) {
.modal.small,
.modal.medium {
width: 90%;
}
}
@media only screen and (max-width: $breakpointSmall) {
.modalContainer {
position: fixed;
}

View file

@ -3,9 +3,9 @@
padding: 0;
font-size: inherit;
}
.isDisabled {
&.isDisabled {
color: var(--disabledColor);
cursor: not-allowed;
}
}

View file

@ -7,7 +7,7 @@ import { icons } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import ArtistSearchInputConnector from './ArtistSearchInputConnector';
import KeyboardShortcutsModal from './KeyboardShortcutsModal';
import PageHeaderActionsMenuConnector from './PageHeaderActionsMenuConnector';
import PageHeaderActionsMenu from './PageHeaderActionsMenu';
import styles from './PageHeader.css';
class PageHeader extends Component {
@ -83,6 +83,7 @@ class PageHeader extends Component {
size={14}
title={translate('Donate')}
/>
<IconButton
className={styles.translation}
title={translate('SuggestTranslationChange')}
@ -90,7 +91,8 @@ class PageHeader extends Component {
to="https://translate.servarr.com/projects/servarr/lidarr/"
size={24}
/>
<PageHeaderActionsMenuConnector
<PageHeaderActionsMenu
onKeyboardShortcutsPress={this.onOpenKeyboardShortcutsModal}
/>
</div>

View file

@ -1,90 +0,0 @@
import PropTypes from 'prop-types';
import React from 'react';
import Icon from 'Components/Icon';
import Menu from 'Components/Menu/Menu';
import MenuButton from 'Components/Menu/MenuButton';
import MenuContent from 'Components/Menu/MenuContent';
import MenuItem from 'Components/Menu/MenuItem';
import MenuItemSeparator from 'Components/Menu/MenuItemSeparator';
import { align, icons, kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import styles from './PageHeaderActionsMenu.css';
function PageHeaderActionsMenu(props) {
const {
formsAuth,
onKeyboardShortcutsPress,
onRestartPress,
onShutdownPress
} = props;
return (
<div>
<Menu alignMenu={align.RIGHT}>
<MenuButton className={styles.menuButton} aria-label="Menu Button">
<Icon
name={icons.INTERACTIVE}
title={translate('Menu')}
/>
</MenuButton>
<MenuContent>
<MenuItem onPress={onKeyboardShortcutsPress}>
<Icon
className={styles.itemIcon}
name={icons.KEYBOARD}
/>
{translate('KeyboardShortcuts')}
</MenuItem>
<MenuItemSeparator />
<MenuItem onPress={onRestartPress}>
<Icon
className={styles.itemIcon}
name={icons.RESTART}
/>
{translate('Restart')}
</MenuItem>
<MenuItem onPress={onShutdownPress}>
<Icon
className={styles.itemIcon}
name={icons.SHUTDOWN}
kind={kinds.DANGER}
/>
Shutdown
</MenuItem>
{
formsAuth &&
<div className={styles.separator} />
}
{
formsAuth &&
<MenuItem
to={`${window.Lidarr.urlBase}/logout`}
noRouter={true}
>
<Icon
className={styles.itemIcon}
name={icons.LOGOUT}
/>
{translate('Logout')}
</MenuItem>
}
</MenuContent>
</Menu>
</div>
);
}
PageHeaderActionsMenu.propTypes = {
formsAuth: PropTypes.bool.isRequired,
onKeyboardShortcutsPress: PropTypes.func.isRequired,
onRestartPress: PropTypes.func.isRequired,
onShutdownPress: PropTypes.func.isRequired
};
export default PageHeaderActionsMenu;

View file

@ -0,0 +1,87 @@
import React, { useCallback } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import AppState from 'App/State/AppState';
import Icon from 'Components/Icon';
import Menu from 'Components/Menu/Menu';
import MenuButton from 'Components/Menu/MenuButton';
import MenuContent from 'Components/Menu/MenuContent';
import MenuItem from 'Components/Menu/MenuItem';
import MenuItemSeparator from 'Components/Menu/MenuItemSeparator';
import { align, icons, kinds } from 'Helpers/Props';
import { restart, shutdown } from 'Store/Actions/systemActions';
import translate from 'Utilities/String/translate';
import styles from './PageHeaderActionsMenu.css';
interface PageHeaderActionsMenuProps {
onKeyboardShortcutsPress(): void;
}
function PageHeaderActionsMenu(props: PageHeaderActionsMenuProps) {
const { onKeyboardShortcutsPress } = props;
const dispatch = useDispatch();
const { authentication, isDocker } = useSelector(
(state: AppState) => state.system.status.item
);
const formsAuth = authentication === 'forms';
const handleRestartPress = useCallback(() => {
dispatch(restart());
}, [dispatch]);
const handleShutdownPress = useCallback(() => {
dispatch(shutdown());
}, [dispatch]);
return (
<div>
<Menu alignMenu={align.RIGHT}>
<MenuButton className={styles.menuButton} aria-label="Menu Button">
<Icon name={icons.INTERACTIVE} title={translate('Menu')} />
</MenuButton>
<MenuContent>
<MenuItem onPress={onKeyboardShortcutsPress}>
<Icon className={styles.itemIcon} name={icons.KEYBOARD} />
{translate('KeyboardShortcuts')}
</MenuItem>
{isDocker ? null : (
<>
<MenuItemSeparator />
<MenuItem onPress={handleRestartPress}>
<Icon className={styles.itemIcon} name={icons.RESTART} />
{translate('Restart')}
</MenuItem>
<MenuItem onPress={handleShutdownPress}>
<Icon
className={styles.itemIcon}
name={icons.SHUTDOWN}
kind={kinds.DANGER}
/>
{translate('Shutdown')}
</MenuItem>
</>
)}
{formsAuth ? (
<>
<MenuItemSeparator />
<MenuItem to={`${window.Lidarr.urlBase}/logout`} noRouter={true}>
<Icon className={styles.itemIcon} name={icons.LOGOUT} />
{translate('Logout')}
</MenuItem>
</>
) : null}
</MenuContent>
</Menu>
</div>
);
}
export default PageHeaderActionsMenu;

View file

@ -1,56 +0,0 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { restart, shutdown } from 'Store/Actions/systemActions';
import PageHeaderActionsMenu from './PageHeaderActionsMenu';
function createMapStateToProps() {
return createSelector(
(state) => state.system.status,
(status) => {
return {
formsAuth: status.item.authentication === 'forms'
};
}
);
}
const mapDispatchToProps = {
restart,
shutdown
};
class PageHeaderActionsMenuConnector extends Component {
//
// Listeners
onRestartPress = () => {
this.props.restart();
};
onShutdownPress = () => {
this.props.shutdown();
};
//
// Render
render() {
return (
<PageHeaderActionsMenu
{...this.props}
onRestartPress={this.onRestartPress}
onShutdownPress={this.onShutdownPress}
/>
);
}
}
PageHeaderActionsMenuConnector.propTypes = {
restart: PropTypes.func.isRequired,
shutdown: PropTypes.func.isRequired
};
export default connect(createMapStateToProps, mapDispatchToProps)(PageHeaderActionsMenuConnector);

View file

@ -224,10 +224,58 @@ class SignalRConnector extends Component {
repopulatePage('trackFileUpdated');
};
handleDownloadclient = ({ action, resource }) => {
const section = 'settings.downloadClients';
if (action === 'created' || action === 'updated') {
this.props.dispatchUpdateItem({ section, ...resource });
} else if (action === 'deleted') {
this.props.dispatchRemoveItem({ section, id: resource.id });
}
};
handleHealth = () => {
this.props.dispatchFetchHealth();
};
handleImportlist = ({ action, resource }) => {
const section = 'settings.importLists';
if (action === 'created' || action === 'updated') {
this.props.dispatchUpdateItem({ section, ...resource });
} else if (action === 'deleted') {
this.props.dispatchRemoveItem({ section, id: resource.id });
}
};
handleIndexer = ({ action, resource }) => {
const section = 'settings.indexers';
if (action === 'created' || action === 'updated') {
this.props.dispatchUpdateItem({ section, ...resource });
} else if (action === 'deleted') {
this.props.dispatchRemoveItem({ section, id: resource.id });
}
};
handleMetadata = ({ action, resource }) => {
const section = 'settings.metadata';
if (action === 'updated') {
this.props.dispatchUpdateItem({ section, ...resource });
}
};
handleNotification = ({ action, resource }) => {
const section = 'settings.notifications';
if (action === 'created' || action === 'updated') {
this.props.dispatchUpdateItem({ section, ...resource });
} else if (action === 'deleted') {
this.props.dispatchRemoveItem({ section, id: resource.id });
}
};
handleArtist = (body) => {
const action = body.action;
const section = 'artist';

View file

@ -4,7 +4,7 @@
line-height: 1.52857143;
}
@media only screen and (max-width: $breakpointSmall) {
@media only screen and (max-width: $breakpointMedium) {
.cell {
white-space: nowrap;
}

View file

@ -7,7 +7,7 @@
white-space: nowrap;
}
@media only screen and (max-width: $breakpointSmall) {
@media only screen and (max-width: $breakpointMedium) {
.cell {
white-space: nowrap;
}

View file

@ -10,7 +10,7 @@
border-collapse: collapse;
}
@media only screen and (max-width: $breakpointSmall) {
@media only screen and (max-width: $breakpointMedium) {
.tableContainer {
min-width: 100%;
width: fit-content;

View file

@ -9,7 +9,7 @@
margin-left: 10px;
}
@media only screen and (max-width: $breakpointSmall) {
@media only screen and (max-width: $breakpointMedium) {
.headerCell {
white-space: nowrap;
}

View file

@ -60,7 +60,7 @@
height: 25px;
}
@media only screen and (max-width: $breakpointSmall) {
@media only screen and (max-width: $breakpointMedium) {
.pager {
flex-wrap: wrap;
}

View file

@ -9,7 +9,7 @@
margin-left: 10px;
}
@media only screen and (max-width: $breakpointSmall) {
@media only screen and (max-width: $breakpointMedium) {
.headerCell {
white-space: nowrap;
}

View file

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square150x150logo src="/Content/Images/Icons/mstile-150x150.png"/>
<TileColor>#00ccff</TileColor>
</tile>
</msapplication>
</browserconfig>

View file

@ -1,19 +0,0 @@
{
"name": "Lidarr",
"icons": [
{
"src": "android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"start_url": "../../../../",
"theme_color": "#3a3f51",
"background_color": "#3a3f51",
"display": "standalone"
}

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square150x150logo src="__URL_BASE__/Content/Images/Icons/mstile-150x150.png" />
<TileColor>
#00ccff
</TileColor>
</tile>
</msapplication>
</browserconfig>

View file

@ -0,0 +1,19 @@
{
"name": "__INSTANCE_NAME__",
"icons": [
{
"src": "__URL_BASE__/Content/Images/Icons/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "__URL_BASE__/Content/Images/Icons/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"start_url": "__URL_BASE__/",
"theme_color": "#3a3f51",
"background_color": "#3a3f51",
"display": "standalone"
}

View file

@ -2,8 +2,8 @@ export const AUTO_COMPLETE = 'autoComplete';
export const CAPTCHA = 'captcha';
export const CHECK = 'check';
export const DEVICE = 'device';
export const PLAYLIST = 'playlist';
export const KEY_VALUE_LIST = 'keyValueList';
export const PLAYLIST = 'playlist';
export const MONITOR_ALBUMS_SELECT = 'monitorAlbumsSelect';
export const MONITOR_NEW_ITEMS_SELECT = 'monitorNewItemsSelect';
export const FLOAT = 'float';
@ -34,8 +34,8 @@ export const all = [
CAPTCHA,
CHECK,
DEVICE,
PLAYLIST,
KEY_VALUE_LIST,
PLAYLIST,
MONITOR_ALBUMS_SELECT,
MONITOR_NEW_ITEMS_SELECT,
FLOAT,

View file

@ -11,6 +11,7 @@ import Scroller from 'Components/Scroller/Scroller';
import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody';
import { scrollDirections } from 'Helpers/Props';
import getErrorMessage from 'Utilities/Object/getErrorMessage';
import translate from 'Utilities/String/translate';
import SelectAlbumRow from './SelectAlbumRow';
import styles from './SelectAlbumModalContent.css';
@ -19,6 +20,7 @@ const columns = [
{
name: 'title',
label: () => translate('AlbumTitle'),
isSortable: true,
isVisible: true
},
{
@ -29,6 +31,7 @@ const columns = [
{
name: 'releaseDate',
label: () => translate('ReleaseDate'),
isSortable: true,
isVisible: true
},
{
@ -63,16 +66,22 @@ class SelectAlbumModalContent extends Component {
render() {
const {
items,
onAlbumSelect,
onModalClose,
isFetching,
...otherProps
isPopulated,
error,
items,
sortKey,
sortDirection,
onSortPress,
onAlbumSelect,
onModalClose
} = this.props;
const filter = this.state.filter;
const filterLower = filter.toLowerCase();
const errorMessage = getErrorMessage(error, 'Unable to load albums');
return (
<ModalContent onModalClose={onModalClose}>
<ModalHeader>
@ -83,10 +92,14 @@ class SelectAlbumModalContent extends Component {
className={styles.modalBody}
scrollDirection={scrollDirections.NONE}
>
{
isFetching &&
<LoadingIndicator />
}
<Scroller
className={styles.scroller}
autoFocus={false}
>
{isFetching ? <LoadingIndicator /> : null}
{error ? <div>{errorMessage}</div> : null}
<TextInput
className={styles.filterInput}
placeholder={translate('FilterAlbumPlaceholder')}
@ -96,14 +109,12 @@ class SelectAlbumModalContent extends Component {
onChange={this.onFilterChange}
/>
<Scroller
className={styles.scroller}
autoFocus={false}
>
{
{isPopulated && !!items.length ? (
<Table
columns={columns}
{...otherProps}
sortKey={sortKey}
sortDirection={sortDirection}
onSortPress={onSortPress}
>
<TableBody>
{
@ -122,7 +133,7 @@ class SelectAlbumModalContent extends Component {
}
</TableBody>
</Table>
}
) : null}
</Scroller>
</ModalBody>
@ -137,8 +148,13 @@ class SelectAlbumModalContent extends Component {
}
SelectAlbumModalContent.propTypes = {
items: PropTypes.arrayOf(PropTypes.object).isRequired,
isFetching: PropTypes.bool.isRequired,
isPopulated: PropTypes.bool.isRequired,
error: PropTypes.object,
items: PropTypes.arrayOf(PropTypes.object).isRequired,
sortKey: PropTypes.string,
sortDirection: PropTypes.string,
onSortPress: PropTypes.func.isRequired,
onAlbumSelect: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired
};

View file

@ -3,18 +3,14 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import {
clearInteractiveImportAlbums,
fetchInteractiveImportAlbums,
saveInteractiveImportItem,
setInteractiveImportAlbumsSort,
updateInteractiveImportItem } from 'Store/Actions/interactiveImportActions';
import { clearAlbums, fetchAlbums, setAlbumsSort } from 'Store/Actions/albumSelectionActions';
import { saveInteractiveImportItem, updateInteractiveImportItem } from 'Store/Actions/interactiveImportActions';
import createClientSideCollectionSelector from 'Store/Selectors/createClientSideCollectionSelector';
import SelectAlbumModalContent from './SelectAlbumModalContent';
function createMapStateToProps() {
return createSelector(
createClientSideCollectionSelector('interactiveImport.albums'),
createClientSideCollectionSelector('albumSelection'),
(albums) => {
return albums;
}
@ -22,9 +18,9 @@ function createMapStateToProps() {
}
const mapDispatchToProps = {
fetchInteractiveImportAlbums,
setInteractiveImportAlbumsSort,
clearInteractiveImportAlbums,
fetchAlbums,
setAlbumsSort,
clearAlbums,
updateInteractiveImportItem,
saveInteractiveImportItem
};
@ -39,20 +35,20 @@ class SelectAlbumModalContentConnector extends Component {
artistId
} = this.props;
this.props.fetchInteractiveImportAlbums({ artistId });
this.props.fetchAlbums({ artistId });
}
componentWillUnmount() {
// This clears the albums for the queue and hides the queue
// We'll need another place to store albums for manual import
this.props.clearInteractiveImportAlbums();
this.props.clearAlbums();
}
//
// Listeners
onSortPress = (sortKey, sortDirection) => {
this.props.setInteractiveImportAlbumsSort({ sortKey, sortDirection });
this.props.setAlbumsSort({ sortKey, sortDirection });
};
onAlbumSelect = (albumId) => {
@ -82,6 +78,7 @@ class SelectAlbumModalContentConnector extends Component {
return (
<SelectAlbumModalContent
{...this.props}
onSortPress={this.onSortPress}
onAlbumSelect={this.onAlbumSelect}
/>
);
@ -92,9 +89,9 @@ SelectAlbumModalContentConnector.propTypes = {
ids: PropTypes.arrayOf(PropTypes.number).isRequired,
artistId: PropTypes.number.isRequired,
items: PropTypes.arrayOf(PropTypes.object).isRequired,
fetchInteractiveImportAlbums: PropTypes.func.isRequired,
setInteractiveImportAlbumsSort: PropTypes.func.isRequired,
clearInteractiveImportAlbums: PropTypes.func.isRequired,
fetchAlbums: PropTypes.func.isRequired,
setAlbumsSort: PropTypes.func.isRequired,
clearAlbums: PropTypes.func.isRequired,
saveInteractiveImportItem: PropTypes.func.isRequired,
updateInteractiveImportItem: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired

View file

@ -1,5 +1,6 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import TextInput from 'Components/Form/TextInput';
import Icon from 'Components/Icon';
import Button from 'Components/Link/Button';
@ -130,7 +131,8 @@ class AddNewItem extends Component {
<div className={styles.helpText}>
{translate('FailedLoadingSearchResults')}
</div>
<div>{getErrorMessage(error)}</div>
<Alert kind={kinds.DANGER}>{getErrorMessage(error)}</Alert>
</div> : null
}

View file

@ -1,4 +1,4 @@
import React, { Fragment } from 'react';
import React from 'react';
import { DndProvider } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
import PageContent from 'Components/Page/PageContent';
@ -8,6 +8,7 @@ import ParseToolbarButton from 'Parse/ParseToolbarButton';
import SettingsToolbarConnector from 'Settings/SettingsToolbarConnector';
import translate from 'Utilities/String/translate';
import CustomFormatsConnector from './CustomFormats/CustomFormatsConnector';
import ManageCustomFormatsToolbarButton from './CustomFormats/Manage/ManageCustomFormatsToolbarButton';
function CustomFormatSettingsPage() {
return (
@ -17,11 +18,13 @@ function CustomFormatSettingsPage() {
// @ts-ignore
showSave={false}
additionalButtons={
<Fragment>
<>
<PageToolbarSeparator />
<ParseToolbarButton />
</Fragment>
<ManageCustomFormatsToolbarButton />
</>
}
/>

View file

@ -3,6 +3,7 @@ import React, { Component } from 'react';
import { connect } from 'react-redux';
import { clearPendingChanges } from 'Store/Actions/baseActions';
import EditCustomFormatModal from './EditCustomFormatModal';
import EditCustomFormatModalContentConnector from './EditCustomFormatModalContentConnector';
function mapStateToProps() {
return {};
@ -36,6 +37,7 @@ class EditCustomFormatModalConnector extends Component {
}
EditCustomFormatModalConnector.propTypes = {
...EditCustomFormatModalContentConnector.propTypes,
onModalClose: PropTypes.func.isRequired,
clearPendingChanges: PropTypes.func.isRequired
};

View file

@ -0,0 +1,28 @@
import React from 'react';
import Modal from 'Components/Modal/Modal';
import ManageCustomFormatsEditModalContent from './ManageCustomFormatsEditModalContent';
interface ManageCustomFormatsEditModalProps {
isOpen: boolean;
customFormatIds: number[];
onSavePress(payload: object): void;
onModalClose(): void;
}
function ManageCustomFormatsEditModal(
props: ManageCustomFormatsEditModalProps
) {
const { isOpen, customFormatIds, onSavePress, onModalClose } = props;
return (
<Modal isOpen={isOpen} onModalClose={onModalClose}>
<ManageCustomFormatsEditModalContent
customFormatIds={customFormatIds}
onSavePress={onSavePress}
onModalClose={onModalClose}
/>
</Modal>
);
}
export default ManageCustomFormatsEditModal;

View file

@ -0,0 +1,16 @@
.modalFooter {
composes: modalFooter from '~Components/Modal/ModalFooter.css';
justify-content: space-between;
}
.selected {
font-weight: bold;
}
@media only screen and (max-width: $breakpointExtraSmall) {
.modalFooter {
flex-direction: column;
gap: 10px;
}
}

View file

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

View file

@ -0,0 +1,125 @@
import React, { useCallback, useState } from 'react';
import FormGroup from 'Components/Form/FormGroup';
import FormInputGroup from 'Components/Form/FormInputGroup';
import FormLabel from 'Components/Form/FormLabel';
import Button from 'Components/Link/Button';
import ModalBody from 'Components/Modal/ModalBody';
import ModalContent from 'Components/Modal/ModalContent';
import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader';
import { inputTypes } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import styles from './ManageCustomFormatsEditModalContent.css';
interface SavePayload {
includeCustomFormatWhenRenaming?: boolean;
}
interface ManageCustomFormatsEditModalContentProps {
customFormatIds: number[];
onSavePress(payload: object): void;
onModalClose(): void;
}
const NO_CHANGE = 'noChange';
const enableOptions = [
{
key: NO_CHANGE,
get value() {
return translate('NoChange');
},
isDisabled: true,
},
{
key: 'enabled',
get value() {
return translate('Enabled');
},
},
{
key: 'disabled',
get value() {
return translate('Disabled');
},
},
];
function ManageCustomFormatsEditModalContent(
props: ManageCustomFormatsEditModalContentProps
) {
const { customFormatIds, onSavePress, onModalClose } = props;
const [includeCustomFormatWhenRenaming, setIncludeCustomFormatWhenRenaming] =
useState(NO_CHANGE);
const save = useCallback(() => {
let hasChanges = false;
const payload: SavePayload = {};
if (includeCustomFormatWhenRenaming !== NO_CHANGE) {
hasChanges = true;
payload.includeCustomFormatWhenRenaming =
includeCustomFormatWhenRenaming === 'enabled';
}
if (hasChanges) {
onSavePress(payload);
}
onModalClose();
}, [includeCustomFormatWhenRenaming, onSavePress, onModalClose]);
const onInputChange = useCallback(
({ name, value }: { name: string; value: string }) => {
switch (name) {
case 'includeCustomFormatWhenRenaming':
setIncludeCustomFormatWhenRenaming(value);
break;
default:
console.warn(
`EditCustomFormatsModalContent Unknown Input: '${name}'`
);
}
},
[]
);
const selectedCount = customFormatIds.length;
return (
<ModalContent onModalClose={onModalClose}>
<ModalHeader>{translate('EditSelectedCustomFormats')}</ModalHeader>
<ModalBody>
<FormGroup>
<FormLabel>{translate('IncludeCustomFormatWhenRenaming')}</FormLabel>
<FormInputGroup
type={inputTypes.SELECT}
name="includeCustomFormatWhenRenaming"
value={includeCustomFormatWhenRenaming}
values={enableOptions}
onChange={onInputChange}
/>
</FormGroup>
</ModalBody>
<ModalFooter className={styles.modalFooter}>
<div className={styles.selected}>
{translate('CountCustomFormatsSelected', {
count: selectedCount,
})}
</div>
<div>
<Button onPress={onModalClose}>{translate('Cancel')}</Button>
<Button onPress={save}>{translate('ApplyChanges')}</Button>
</div>
</ModalFooter>
</ModalContent>
);
}
export default ManageCustomFormatsEditModalContent;

View file

@ -0,0 +1,20 @@
import React from 'react';
import Modal from 'Components/Modal/Modal';
import ManageCustomFormatsModalContent from './ManageCustomFormatsModalContent';
interface ManageCustomFormatsModalProps {
isOpen: boolean;
onModalClose(): void;
}
function ManageCustomFormatsModal(props: ManageCustomFormatsModalProps) {
const { isOpen, onModalClose } = props;
return (
<Modal isOpen={isOpen} onModalClose={onModalClose}>
<ManageCustomFormatsModalContent onModalClose={onModalClose} />
</Modal>
);
}
export default ManageCustomFormatsModal;

View file

@ -0,0 +1,16 @@
.leftButtons,
.rightButtons {
display: flex;
flex: 1 0 50%;
flex-wrap: wrap;
}
.rightButtons {
justify-content: flex-end;
}
.deleteButton {
composes: button from '~Components/Link/Button.css';
margin-right: 10px;
}

View file

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

View file

@ -0,0 +1,244 @@
import React, { useCallback, useMemo, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { CustomFormatAppState } from 'App/State/SettingsAppState';
import Alert from 'Components/Alert';
import Button from 'Components/Link/Button';
import SpinnerButton from 'Components/Link/SpinnerButton';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import ConfirmModal from 'Components/Modal/ConfirmModal';
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 Column from 'Components/Table/Column';
import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody';
import useSelectState from 'Helpers/Hooks/useSelectState';
import { kinds } from 'Helpers/Props';
import {
bulkDeleteCustomFormats,
bulkEditCustomFormats,
setManageCustomFormatsSort,
} from 'Store/Actions/settingsActions';
import createClientSideCollectionSelector from 'Store/Selectors/createClientSideCollectionSelector';
import { SelectStateInputProps } from 'typings/props';
import getErrorMessage from 'Utilities/Object/getErrorMessage';
import translate from 'Utilities/String/translate';
import getSelectedIds from 'Utilities/Table/getSelectedIds';
import ManageCustomFormatsEditModal from './Edit/ManageCustomFormatsEditModal';
import ManageCustomFormatsModalRow from './ManageCustomFormatsModalRow';
import styles from './ManageCustomFormatsModalContent.css';
// TODO: This feels janky to do, but not sure of a better way currently
type OnSelectedChangeCallback = React.ComponentProps<
typeof ManageCustomFormatsModalRow
>['onSelectedChange'];
const COLUMNS: Column[] = [
{
name: 'name',
label: () => translate('Name'),
isSortable: true,
isVisible: true,
},
{
name: 'includeCustomFormatWhenRenaming',
label: () => translate('IncludeCustomFormatWhenRenaming'),
isSortable: true,
isVisible: true,
},
{
name: 'actions',
label: '',
isVisible: true,
},
];
interface ManageCustomFormatsModalContentProps {
onModalClose(): void;
}
function ManageCustomFormatsModalContent(
props: ManageCustomFormatsModalContentProps
) {
const { onModalClose } = props;
const {
isFetching,
isPopulated,
isDeleting,
isSaving,
error,
items,
sortKey,
sortDirection,
}: CustomFormatAppState = useSelector(
createClientSideCollectionSelector('settings.customFormats')
);
const dispatch = useDispatch();
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
const [isEditModalOpen, setIsEditModalOpen] = useState(false);
const [selectState, setSelectState] = useSelectState();
const { allSelected, allUnselected, selectedState } = selectState;
const selectedIds: number[] = useMemo(() => {
return getSelectedIds(selectedState);
}, [selectedState]);
const selectedCount = selectedIds.length;
const onSortPress = useCallback(
(value: string) => {
dispatch(setManageCustomFormatsSort({ sortKey: value }));
},
[dispatch]
);
const onDeletePress = useCallback(() => {
setIsDeleteModalOpen(true);
}, [setIsDeleteModalOpen]);
const onDeleteModalClose = useCallback(() => {
setIsDeleteModalOpen(false);
}, [setIsDeleteModalOpen]);
const onEditPress = useCallback(() => {
setIsEditModalOpen(true);
}, [setIsEditModalOpen]);
const onEditModalClose = useCallback(() => {
setIsEditModalOpen(false);
}, [setIsEditModalOpen]);
const onConfirmDelete = useCallback(() => {
dispatch(bulkDeleteCustomFormats({ ids: selectedIds }));
setIsDeleteModalOpen(false);
}, [selectedIds, dispatch]);
const onSavePress = useCallback(
(payload: object) => {
setIsEditModalOpen(false);
dispatch(
bulkEditCustomFormats({
ids: selectedIds,
...payload,
})
);
},
[selectedIds, dispatch]
);
const onSelectAllChange = useCallback(
({ value }: SelectStateInputProps) => {
setSelectState({ type: value ? 'selectAll' : 'unselectAll', items });
},
[items, setSelectState]
);
const onSelectedChange = useCallback<OnSelectedChangeCallback>(
({ id, value, shiftKey = false }) => {
setSelectState({
type: 'toggleSelected',
items,
id,
isSelected: value,
shiftKey,
});
},
[items, setSelectState]
);
const errorMessage = getErrorMessage(error, 'Unable to load custom formats.');
const anySelected = selectedCount > 0;
return (
<ModalContent onModalClose={onModalClose}>
<ModalHeader>{translate('ManageCustomFormats')}</ModalHeader>
<ModalBody>
{isFetching ? <LoadingIndicator /> : null}
{error ? <div>{errorMessage}</div> : null}
{isPopulated && !error && !items.length ? (
<Alert kind={kinds.INFO}>{translate('NoCustomFormatsFound')}</Alert>
) : null}
{isPopulated && !!items.length && !isFetching && !isFetching ? (
<Table
columns={COLUMNS}
horizontalScroll={true}
selectAll={true}
allSelected={allSelected}
allUnselected={allUnselected}
sortKey={sortKey}
sortDirection={sortDirection}
onSelectAllChange={onSelectAllChange}
onSortPress={onSortPress}
>
<TableBody>
{items.map((item) => {
return (
<ManageCustomFormatsModalRow
key={item.id}
isSelected={selectedState[item.id]}
{...item}
columns={COLUMNS}
onSelectedChange={onSelectedChange}
/>
);
})}
</TableBody>
</Table>
) : null}
</ModalBody>
<ModalFooter>
<div className={styles.leftButtons}>
<SpinnerButton
kind={kinds.DANGER}
isSpinning={isDeleting}
isDisabled={!anySelected}
onPress={onDeletePress}
>
{translate('Delete')}
</SpinnerButton>
<SpinnerButton
isSpinning={isSaving}
isDisabled={!anySelected}
onPress={onEditPress}
>
{translate('Edit')}
</SpinnerButton>
</div>
<Button onPress={onModalClose}>{translate('Close')}</Button>
</ModalFooter>
<ManageCustomFormatsEditModal
isOpen={isEditModalOpen}
customFormatIds={selectedIds}
onModalClose={onEditModalClose}
onSavePress={onSavePress}
/>
<ConfirmModal
isOpen={isDeleteModalOpen}
kind={kinds.DANGER}
title={translate('DeleteSelectedCustomFormats')}
message={translate('DeleteSelectedCustomFormatsMessageText', {
count: selectedIds.length,
})}
confirmLabel={translate('Delete')}
onConfirm={onConfirmDelete}
onCancel={onDeleteModalClose}
/>
</ModalContent>
);
}
export default ManageCustomFormatsModalContent;

View file

@ -0,0 +1,12 @@
.name,
.includeCustomFormatWhenRenaming {
composes: cell from '~Components/Table/Cells/TableRowCell.css';
word-break: break-all;
}
.actions {
composes: cell from '~Components/Table/Cells/TableRowCell.css';
width: 40px;
}

View file

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

View file

@ -0,0 +1,126 @@
import React, { useCallback, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { createSelector } from 'reselect';
import AppState from 'App/State/AppState';
import IconButton from 'Components/Link/IconButton';
import ConfirmModal from 'Components/Modal/ConfirmModal';
import TableRowCell from 'Components/Table/Cells/TableRowCell';
import TableSelectCell from 'Components/Table/Cells/TableSelectCell';
import Column from 'Components/Table/Column';
import TableRow from 'Components/Table/TableRow';
import { icons } from 'Helpers/Props';
import { deleteCustomFormat } from 'Store/Actions/settingsActions';
import { SelectStateInputProps } from 'typings/props';
import translate from 'Utilities/String/translate';
import EditCustomFormatModalConnector from '../EditCustomFormatModalConnector';
import styles from './ManageCustomFormatsModalRow.css';
interface ManageCustomFormatsModalRowProps {
id: number;
name: string;
includeCustomFormatWhenRenaming: boolean;
columns: Column[];
isSelected?: boolean;
onSelectedChange(result: SelectStateInputProps): void;
}
function isDeletingSelector() {
return createSelector(
(state: AppState) => state.settings.customFormats.isDeleting,
(isDeleting) => {
return isDeleting;
}
);
}
function ManageCustomFormatsModalRow(props: ManageCustomFormatsModalRowProps) {
const {
id,
isSelected,
name,
includeCustomFormatWhenRenaming,
onSelectedChange,
} = props;
const dispatch = useDispatch();
const isDeleting = useSelector(isDeletingSelector());
const [isEditCustomFormatModalOpen, setIsEditCustomFormatModalOpen] =
useState(false);
const [isDeleteCustomFormatModalOpen, setIsDeleteCustomFormatModalOpen] =
useState(false);
const handlelectedChange = useCallback(
(result: SelectStateInputProps) => {
onSelectedChange({
...result,
});
},
[onSelectedChange]
);
const handleEditCustomFormatModalOpen = useCallback(() => {
setIsEditCustomFormatModalOpen(true);
}, [setIsEditCustomFormatModalOpen]);
const handleEditCustomFormatModalClose = useCallback(() => {
setIsEditCustomFormatModalOpen(false);
}, [setIsEditCustomFormatModalOpen]);
const handleDeleteCustomFormatPress = useCallback(() => {
setIsEditCustomFormatModalOpen(false);
setIsDeleteCustomFormatModalOpen(true);
}, [setIsEditCustomFormatModalOpen, setIsDeleteCustomFormatModalOpen]);
const handleDeleteCustomFormatModalClose = useCallback(() => {
setIsDeleteCustomFormatModalOpen(false);
}, [setIsDeleteCustomFormatModalOpen]);
const handleConfirmDeleteCustomFormat = useCallback(() => {
dispatch(deleteCustomFormat({ id }));
}, [id, dispatch]);
return (
<TableRow>
<TableSelectCell
id={id}
isSelected={isSelected}
onSelectedChange={handlelectedChange}
/>
<TableRowCell className={styles.name}>{name}</TableRowCell>
<TableRowCell className={styles.includeCustomFormatWhenRenaming}>
{includeCustomFormatWhenRenaming ? translate('Yes') : translate('No')}
</TableRowCell>
<TableRowCell className={styles.actions}>
<IconButton
name={icons.EDIT}
onPress={handleEditCustomFormatModalOpen}
/>
</TableRowCell>
<EditCustomFormatModalConnector
id={id}
isOpen={isEditCustomFormatModalOpen}
onModalClose={handleEditCustomFormatModalClose}
onDeleteCustomFormatPress={handleDeleteCustomFormatPress}
/>
<ConfirmModal
isOpen={isDeleteCustomFormatModalOpen}
kind="danger"
title={translate('DeleteCustomFormat')}
message={translate('DeleteCustomFormatMessageText', { name })}
confirmLabel={translate('Delete')}
isSpinning={isDeleting}
onConfirm={handleConfirmDeleteCustomFormat}
onCancel={handleDeleteCustomFormatModalClose}
/>
</TableRow>
);
}
export default ManageCustomFormatsModalRow;

View file

@ -0,0 +1,28 @@
import React from 'react';
import PageToolbarButton from 'Components/Page/Toolbar/PageToolbarButton';
import useModalOpenState from 'Helpers/Hooks/useModalOpenState';
import { icons } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import ManageCustomFormatsModal from './ManageCustomFormatsModal';
function ManageCustomFormatsToolbarButton() {
const [isManageModalOpen, openManageModal, closeManageModal] =
useModalOpenState(false);
return (
<>
<PageToolbarButton
label={translate('ManageFormats')}
iconName={icons.MANAGE}
onPress={openManageModal}
/>
<ManageCustomFormatsModal
isOpen={isManageModalOpen}
onModalClose={closeManageModal}
/>
</>
);
}
export default ManageCustomFormatsToolbarButton;

View file

@ -7,8 +7,8 @@ import FormInputGroup from 'Components/Form/FormInputGroup';
import FormLabel from 'Components/Form/FormLabel';
import ProviderFieldFormGroup from 'Components/Form/ProviderFieldFormGroup';
import Button from 'Components/Link/Button';
import Link from 'Components/Link/Link';
import SpinnerErrorButton from 'Components/Link/SpinnerErrorButton';
import InlineMarkdown from 'Components/Markdown/InlineMarkdown';
import ModalBody from 'Components/Modal/ModalBody';
import ModalContent from 'Components/Modal/ModalContent';
import ModalFooter from 'Components/Modal/ModalFooter';
@ -52,12 +52,13 @@ function EditSpecificationModalContent(props) {
fields && fields.some((x) => x.label === translate('CustomFormatsSpecificationRegularExpression')) &&
<Alert kind={kinds.INFO}>
<div>
<div dangerouslySetInnerHTML={{ __html: 'This condition matches using Regular Expressions. Note that the characters <code>\\^$.|?*+()[{</code> have special meanings and need escaping with a <code>\\</code>' }} />
{'More details'} <Link to="https://www.regular-expressions.info/tutorial.html">{'Here'}</Link>
<InlineMarkdown data={translate('ConditionUsingRegularExpressions')} />
</div>
<div>
{'Regular expressions can be tested '}
<Link to="http://regexstorm.net/tester">Here</Link>
<InlineMarkdown data={translate('RegularExpressionsTutorialLink', { url: 'https://www.regular-expressions.info/tutorial.html' })} />
</div>
<div>
<InlineMarkdown data={translate('RegularExpressionsCanBeTested', { url: 'http://regexstorm.net/tester' })} />
</div>
</Alert>
}

View file

@ -10,11 +10,11 @@ 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 Column from 'Components/Table/Column';
import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody';
import useSelectState from 'Helpers/Hooks/useSelectState';
import { kinds } from 'Helpers/Props';
import SortDirection from 'Helpers/Props/SortDirection';
import {
bulkDeleteDownloadClients,
bulkEditDownloadClients,
@ -35,7 +35,7 @@ type OnSelectedChangeCallback = React.ComponentProps<
typeof ManageDownloadClientsModalRow
>['onSelectedChange'];
const COLUMNS = [
const COLUMNS: Column[] = [
{
name: 'name',
label: () => translate('Name'),
@ -82,8 +82,6 @@ const COLUMNS = [
interface ManageDownloadClientsModalContentProps {
onModalClose(): void;
sortKey?: string;
sortDirection?: SortDirection;
}
function ManageDownloadClientsModalContent(
@ -220,9 +218,9 @@ function ManageDownloadClientsModalContent(
{error ? <div>{errorMessage}</div> : null}
{isPopulated && !error && !items.length && (
{isPopulated && !error && !items.length ? (
<Alert kind={kinds.INFO}>{translate('NoDownloadClientsFound')}</Alert>
)}
) : null}
{isPopulated && !!items.length && !isFetching && !isFetching ? (
<Table

View file

@ -156,6 +156,7 @@ class GeneralSettings extends Component {
/>
<LoggingSettings
advancedSettings={advancedSettings}
settings={settings}
onInputChange={onInputChange}
/>

View file

@ -15,12 +15,14 @@ const logLevelOptions = [
function LoggingSettings(props) {
const {
advancedSettings,
settings,
onInputChange
} = props;
const {
logLevel
logLevel,
logSizeLimit
} = settings;
return (
@ -39,11 +41,30 @@ function LoggingSettings(props) {
{...logLevel}
/>
</FormGroup>
<FormGroup
advancedSettings={advancedSettings}
isAdvanced={true}
>
<FormLabel>{translate('LogSizeLimit')}</FormLabel>
<FormInputGroup
type={inputTypes.NUMBER}
name="logSizeLimit"
min={1}
max={10}
unit="MB"
helpText={translate('LogSizeLimitHelpText')}
onChange={onInputChange}
{...logSizeLimit}
/>
</FormGroup>
</FieldSet>
);
}
LoggingSettings.propTypes = {
advancedSettings: PropTypes.bool.isRequired,
settings: PropTypes.object.isRequired,
onInputChange: PropTypes.func.isRequired
};

View file

@ -292,7 +292,7 @@ function EditImportListModalContent(props) {
<FormInputGroup
type={inputTypes.TAG}
name="tags"
helpText={translate('TagsHelpText')}
helpText={translate('ImportListTagsHelpText')}
{...tags}
onChange={onInputChange}
/>

View file

@ -198,9 +198,9 @@ function ManageImportListsModalContent(
{error ? <div>{errorMessage}</div> : null}
{isPopulated && !error && !items.length && (
{isPopulated && !error && !items.length ? (
<Alert kind={kinds.INFO}>{translate('NoImportListsFound')}</Alert>
)}
) : null}
{isPopulated && !!items.length && !isFetching && !isFetching ? (
<Table

View file

@ -10,11 +10,11 @@ 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 Column from 'Components/Table/Column';
import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody';
import useSelectState from 'Helpers/Hooks/useSelectState';
import { kinds } from 'Helpers/Props';
import SortDirection from 'Helpers/Props/SortDirection';
import {
bulkDeleteIndexers,
bulkEditIndexers,
@ -35,7 +35,7 @@ type OnSelectedChangeCallback = React.ComponentProps<
typeof ManageIndexersModalRow
>['onSelectedChange'];
const COLUMNS = [
const COLUMNS: Column[] = [
{
name: 'name',
label: () => translate('Name'),
@ -82,8 +82,6 @@ const COLUMNS = [
interface ManageIndexersModalContentProps {
onModalClose(): void;
sortKey?: string;
sortDirection?: SortDirection;
}
function ManageIndexersModalContent(props: ManageIndexersModalContentProps) {
@ -215,9 +213,9 @@ function ManageIndexersModalContent(props: ManageIndexersModalContentProps) {
{error ? <div>{errorMessage}</div> : null}
{isPopulated && !error && !items.length && (
{isPopulated && !error && !items.length ? (
<Alert kind={kinds.INFO}>{translate('NoIndexersFound')}</Alert>
)}
) : null}
{isPopulated && !!items.length && !isFetching && !isFetching ? (
<Table

View file

@ -191,26 +191,21 @@ class MediaManagement extends Component {
<FieldSet
legend={translate('Importing')}
>
{
!isWindows &&
<FormGroup
advancedSettings={advancedSettings}
isAdvanced={true}
size={sizes.MEDIUM}
>
<FormLabel>
{translate('SkipFreeSpaceCheck')}
</FormLabel>
<FormLabel>{translate('SkipFreeSpaceCheck')}</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="skipFreeSpaceCheckWhenImporting"
helpText={translate('SkipFreeSpaceCheckWhenImportingHelpText')}
helpText={translate('SkipFreeSpaceCheckHelpText')}
onChange={onInputChange}
{...settings.skipFreeSpaceCheckWhenImporting}
/>
</FormGroup>
}
<FormGroup
advancedSettings={advancedSettings}

View file

@ -1,4 +1,3 @@
import _ from 'lodash';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
@ -15,11 +14,11 @@ function createMapStateToProps() {
(state) => state.settings.advancedSettings,
(state) => state.settings.namingExamples,
createSettingsSectionSelector(SECTION),
(advancedSettings, examples, sectionSettings) => {
(advancedSettings, namingExamples, sectionSettings) => {
return {
advancedSettings,
examples: examples.item,
examplesPopulated: !_.isEmpty(examples.item),
examples: namingExamples.item,
examplesPopulated: namingExamples.isPopulated,
...sectionSettings
};
}

View file

@ -94,9 +94,9 @@ class RootFolder extends Component {
<ConfirmModal
isOpen={this.state.isDeleteRootFolderModalOpen}
kind={kinds.DANGER}
title={translate('DeleteRootFolder')}
message={translate('DeleteRootFolderMessageText', { name })}
confirmLabel={translate('Delete')}
title={translate('RemoveRootFolder')}
message={translate('RemoveRootFolderArtistsMessageText', { name })}
confirmLabel={translate('Remove')}
onConfirm={this.onConfirmDeleteRootFolder}
onCancel={this.onDeleteRootFolderModalClose}
/>

View file

@ -105,7 +105,7 @@ function EditNotificationModalContent(props) {
<FormInputGroup
type={inputTypes.TAG}
name="tags"
helpText={translate('TagsHelpText')}
helpText={translate('NotificationsTagsArtistHelpText')}
{...tags}
onChange={onInputChange}
/>

View file

@ -87,9 +87,9 @@ function EditDelayProfileModalContent(props) {
{
!isFetching && !!error ?
<div>
{translate('UnableToAddANewQualityProfilePleaseTryAgain')}
</div> :
<Alert kind={kinds.DANGER}>
{translate('AddDelayProfileError')}
</Alert> :
null
}
@ -186,7 +186,7 @@ function EditDelayProfileModalContent(props) {
{
id === 1 ?
<Alert>
{translate('DefaultDelayProfileHelpText')}
{translate('DefaultDelayProfileArtist')}
</Alert> :
<FormGroup>
@ -196,7 +196,7 @@ function EditDelayProfileModalContent(props) {
type={inputTypes.TAG}
name="tags"
{...tags}
helpText={translate('TagsHelpText')}
helpText={translate('DelayProfileArtistTagsHelpText')}
onChange={onInputChange}
/>
</FormGroup>

View file

@ -119,7 +119,7 @@ function EditReleaseProfileModalContent(props) {
<FormInputGroup
type={inputTypes.TAG}
name="tags"
helpText={translate('TagsHelpText')}
helpText={translate('ReleaseProfileTagArtistHelpText')}
{...tags}
onChange={onInputChange}
/>

View file

@ -24,7 +24,7 @@
height: 20px;
}
.bar {
.track {
top: 9px;
margin: 0 5px;
height: 3px;
@ -36,7 +36,7 @@
}
}
.handle {
.thumb {
top: 1px;
z-index: 0 !important;
width: 18px;

View file

@ -1,8 +1,6 @@
// This file is automatically generated.
// Please do not change this file!
interface CssExports {
'bar': string;
'handle': string;
'kilobitsPerSecond': string;
'quality': string;
'qualityDefinition': string;
@ -10,7 +8,9 @@ interface CssExports {
'sizeLimit': string;
'sizes': string;
'slider': string;
'thumb': string;
'title': string;
'track': string;
}
export const cssExports: CssExports;
export default cssExports;

View file

@ -55,6 +55,27 @@ class QualityDefinition extends Component {
};
}
//
// Control
trackRenderer(props, state) {
return (
<div
{...props}
className={styles.track}
/>
);
}
thumbRenderer(props, state) {
return (
<div
{...props}
className={styles.thumb}
/>
);
}
//
// Listeners
@ -174,6 +195,7 @@ class QualityDefinition extends Component {
<div className={styles.sizeLimit}>
<ReactSlider
className={styles.slider}
min={slider.min}
max={slider.max}
step={slider.step}
@ -182,9 +204,9 @@ class QualityDefinition extends Component {
withTracks={true}
allowCross={false}
snapDragDisabled={true}
className={styles.slider}
trackClassName={styles.bar}
thumbClassName={styles.handle}
pearling={true}
renderThumb={this.thumbRenderer}
renderTrack={this.trackRenderer}
onChange={this.onSliderChange}
onAfterChange={this.onAfterSliderChange}
/>

View file

@ -86,10 +86,10 @@ function EditSpecificationModalContent(props) {
<InlineMarkdown data={translate('ConditionUsingRegularExpressions')} />
</div>
<div>
<InlineMarkdown data={translate('RegularExpressionsTutorialLink')} />
<InlineMarkdown data={translate('RegularExpressionsTutorialLink', { url: 'https://www.regular-expressions.info/tutorial.html' })} />
</div>
<div>
<InlineMarkdown data={translate('RegularExpressionsCanBeTested')} />
<InlineMarkdown data={translate('RegularExpressionsCanBeTested', { url: 'http://regexstorm.net/tester' })} />
</div>
</Alert>
}

View file

@ -4,11 +4,13 @@ import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { fetchDelayProfiles, fetchDownloadClients, fetchImportLists, fetchIndexers, fetchNotifications, fetchReleaseProfiles } from 'Store/Actions/settingsActions';
import { fetchTagDetails, fetchTags } from 'Store/Actions/tagActions';
import createSortedSectionSelector from 'Store/Selectors/createSortedSectionSelector';
import sortByProp from 'Utilities/Array/sortByProp';
import Tags from './Tags';
function createMapStateToProps() {
return createSelector(
(state) => state.tags,
createSortedSectionSelector('tags', sortByProp('label')),
(tags) => {
const isFetching = tags.isFetching || tags.details.isFetching;
const error = tags.error || tags.details.error;

View file

@ -1,7 +1,12 @@
import { createAction } from 'redux-actions';
import { sortDirections } from 'Helpers/Props';
import createBulkEditItemHandler from 'Store/Actions/Creators/createBulkEditItemHandler';
import createBulkRemoveItemHandler from 'Store/Actions/Creators/createBulkRemoveItemHandler';
import createFetchHandler from 'Store/Actions/Creators/createFetchHandler';
import createRemoveItemHandler from 'Store/Actions/Creators/createRemoveItemHandler';
import createSaveProviderHandler from 'Store/Actions/Creators/createSaveProviderHandler';
import createSetClientSideCollectionSortReducer
from 'Store/Actions/Creators/Reducers/createSetClientSideCollectionSortReducer';
import createSetSettingValueReducer from 'Store/Actions/Creators/Reducers/createSetSettingValueReducer';
import { createThunk } from 'Store/thunks';
import getSectionState from 'Utilities/State/getSectionState';
@ -21,6 +26,9 @@ export const SAVE_CUSTOM_FORMAT = 'settings/customFormats/saveCustomFormat';
export const DELETE_CUSTOM_FORMAT = 'settings/customFormats/deleteCustomFormat';
export const SET_CUSTOM_FORMAT_VALUE = 'settings/customFormats/setCustomFormatValue';
export const CLONE_CUSTOM_FORMAT = 'settings/customFormats/cloneCustomFormat';
export const BULK_EDIT_CUSTOM_FORMATS = 'settings/downloadClients/bulkEditCustomFormats';
export const BULK_DELETE_CUSTOM_FORMATS = 'settings/downloadClients/bulkDeleteCustomFormats';
export const SET_MANAGE_CUSTOM_FORMATS_SORT = 'settings/downloadClients/setManageCustomFormatsSort';
//
// Action Creators
@ -28,6 +36,9 @@ export const CLONE_CUSTOM_FORMAT = 'settings/customFormats/cloneCustomFormat';
export const fetchCustomFormats = createThunk(FETCH_CUSTOM_FORMATS);
export const saveCustomFormat = createThunk(SAVE_CUSTOM_FORMAT);
export const deleteCustomFormat = createThunk(DELETE_CUSTOM_FORMAT);
export const bulkEditCustomFormats = createThunk(BULK_EDIT_CUSTOM_FORMATS);
export const bulkDeleteCustomFormats = createThunk(BULK_DELETE_CUSTOM_FORMATS);
export const setManageCustomFormatsSort = createAction(SET_MANAGE_CUSTOM_FORMATS_SORT);
export const setCustomFormatValue = createAction(SET_CUSTOM_FORMAT_VALUE, (payload) => {
return {
@ -47,20 +58,30 @@ export default {
// State
defaultState: {
isSchemaFetching: false,
isSchemaPopulated: false,
isFetching: false,
isPopulated: false,
error: null,
isSaving: false,
saveError: null,
isDeleting: false,
deleteError: null,
items: [],
pendingChanges: {},
isSchemaFetching: false,
isSchemaPopulated: false,
schemaError: null,
schema: {
includeCustomFormatWhenRenaming: false
},
error: null,
isDeleting: false,
deleteError: null,
isSaving: false,
saveError: null,
items: [],
pendingChanges: {}
sortKey: 'name',
sortDirection: sortDirections.ASCENDING,
sortPredicates: {
name: ({ name }) => {
return name.toLocaleLowerCase();
}
}
},
//
@ -82,7 +103,10 @@ export default {
}));
createSaveProviderHandler(section, '/customformat')(getState, payload, dispatch);
}
},
[BULK_EDIT_CUSTOM_FORMATS]: createBulkEditItemHandler(section, '/customformat/bulk'),
[BULK_DELETE_CUSTOM_FORMATS]: createBulkRemoveItemHandler(section, '/customformat/bulk')
},
//
@ -102,7 +126,9 @@ export default {
newState.pendingChanges = pendingChanges;
return updateSectionState(state, section, newState);
}
},
[SET_MANAGE_CUSTOM_FORMATS_SORT]: createSetClientSideCollectionSortReducer(section)
}
};

View file

@ -96,8 +96,8 @@ export default {
sortKey: 'name',
sortDirection: sortDirections.ASCENDING,
sortPredicates: {
name: function(item) {
return item.name.toLowerCase();
name: ({ name }) => {
return name.toLocaleLowerCase();
}
}
},

View file

@ -100,8 +100,8 @@ export default {
sortKey: 'name',
sortDirection: sortDirections.ASCENDING,
sortPredicates: {
name: function(item) {
return item.name.toLowerCase();
name: ({ name }) => {
return name.toLocaleLowerCase();
}
}
},

View file

@ -0,0 +1,86 @@
import moment from 'moment';
import { createAction } from 'redux-actions';
import { sortDirections } from 'Helpers/Props';
import { createThunk, handleThunks } from 'Store/thunks';
import updateSectionState from 'Utilities/State/updateSectionState';
import createFetchHandler from './Creators/createFetchHandler';
import createHandleActions from './Creators/createHandleActions';
import createSetClientSideCollectionSortReducer from './Creators/Reducers/createSetClientSideCollectionSortReducer';
//
// Variables
export const section = 'albumSelection';
//
// State
export const defaultState = {
isFetching: false,
isReprocessing: false,
isPopulated: false,
error: null,
sortKey: 'title',
sortDirection: sortDirections.ASCENDING,
items: [],
sortPredicates: {
title: ({ title }) => {
return title.toLocaleLowerCase();
},
releaseDate: function({ releaseDate }, direction) {
if (releaseDate) {
return moment(releaseDate).unix();
}
if (direction === sortDirections.DESCENDING) {
return 0;
}
return Number.MAX_VALUE;
}
}
};
export const persistState = [
'albumSelection.sortKey',
'albumSelection.sortDirection'
];
//
// Actions Types
export const FETCH_ALBUMS = 'albumSelection/fetchAlbums';
export const SET_ALBUMS_SORT = 'albumSelection/setAlbumsSort';
export const CLEAR_ALBUMS = 'albumSelection/clearAlbums';
//
// Action Creators
export const fetchAlbums = createThunk(FETCH_ALBUMS);
export const setAlbumsSort = createAction(SET_ALBUMS_SORT);
export const clearAlbums = createAction(CLEAR_ALBUMS);
//
// Action Handlers
export const actionHandlers = handleThunks({
[FETCH_ALBUMS]: createFetchHandler(section, '/album')
});
//
// Reducers
export const reducers = createHandleActions({
[SET_ALBUMS_SORT]: createSetClientSideCollectionSortReducer(section),
[CLEAR_ALBUMS]: (state) => {
return updateSectionState(state, section, {
...defaultState,
sortKey: state.sortKey,
sortDirection: state.sortDirection
});
}
}, defaultState, section);

View file

@ -151,7 +151,7 @@ export const defaultState = {
{
name: 'genres',
label: () => translate('Genres'),
isSortable: false,
isSortable: true,
isVisible: false
},
{

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