Compare commits

...

97 Commits

Author SHA1 Message Date
Bogdan 950949e4bc Bump Polly to 8.6.0 2025-06-12 09:56:52 +03:00
Bogdan fe198352a3 Fixed: Fallback to Forms for removed Basic auth method 2025-06-11 20:13:03 +03:00
Bogdan 88502cd020 Fixed: (AnimeTosho) Mapping of Subcategory as Parent 2025-06-11 10:32:21 +03:00
Bogdan 4924b45b56 Fix various typos 2025-06-10 18:36:14 +03:00
Bogdan aea8b7cd7e Fixed: Redirect loop for removed basic auth method 2025-06-10 12:33:52 +03:00
Bogdan aafadb6111 Fix fullscreen automation screenshots 2025-06-09 22:08:00 +03:00
Mark McDowall c82f904d49 New: Add exception to SSL Certificate validation message
(cherry picked from commit d84c4500949a530fac92d73f7f2f8e8462b37244)
2025-06-08 16:37:52 +03:00
Servarr 60740fa259 Automated API Docs update 2025-06-08 10:33:02 +03:00
Mark McDowall d36b32f414 New: Remove Basic Auth
(cherry picked from commit 0f9e063e2146812f6e963363eee70a524612f354)
2025-06-07 19:23:03 +03:00
Bogdan 14ccd6d2a5 Fixed: Validation for tags label 2025-06-07 19:23:03 +03:00
Bogdan bdc3b63df2 Upgrade StyleCop.Analyzers to Unstable 1.2.0.556 2025-06-07 19:23:03 +03:00
Bogdan 8eec321a0e Bump Swashbuckle to 8.1.4 2025-06-07 19:23:03 +03:00
Bogdan 06de2313ab Bump version to 2.0.0 2025-06-07 19:23:03 +03:00
Bogdan a3f713bad8 New: Support removed for linux-x86 2025-06-07 19:23:03 +03:00
Bogdan 7a1fca5e23 New: Migrate appdata folder for .NET 8 on OSX 2025-06-07 19:23:03 +03:00
Bogdan 21c408a7da New: Bump to .NET 8 2025-06-07 19:23:03 +03:00
Weblate 0e92108970 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Ilbebino <tommasobellandi08@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/prowlarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_CN/
Translation: Servarr/Prowlarr
2025-06-06 14:41:02 +03:00
Bogdan 7d813ef97a Bump version to 1.38.0 2025-06-04 14:05:21 +03:00
Bogdan c87995250a Fixed: Sync indexers with basic search to Radarr and Sonarr
Fixes #2404
2025-06-03 14:26:09 +03:00
Bogdan a9f7a376c7 Bump version to 1.37.0 2025-05-25 17:00:17 +03:00
Bogdan c3ee3f2320 Fix jump to character for Search page 2025-05-25 14:04:33 +03:00
Weblate e8c26d0fea Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: thelooter <evekolb2204@gmail.com>
Co-authored-by: warkurre86 <tom.novo.86@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/cs/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/de/
Translation: Servarr/Prowlarr
2025-05-25 12:05:56 +03:00
Bogdan 9c936121e8 Fixed: Sync indexers with basic search to Lidarr and Readarr
Fixes #2402
2025-05-22 13:30:41 +03:00
Bogdan 40d2e40d94 Fail build on missing test results
Ignore missing test results failure on FreeBSD
2025-05-18 18:01:13 +03:00
Weblate 837f50c91c Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Fixer <ygj59783@zslsz.com>
Co-authored-by: Hugoren Martinako <aumpfbahn@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/el/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/nl/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pl/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/uk/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_CN/
Translation: Servarr/Prowlarr
2025-05-18 14:10:34 +03:00
Bogdan f0a0202e5c Bump version to 1.36.3 2025-05-18 14:10:14 +03:00
Bogdan 708c94bc56 Fixed PTP test 2025-05-15 00:47:46 +03:00
Bogdan 5ed82eaf09 Fixed: (PTP) Download torrent files with API credentials 2025-05-14 22:44:26 +03:00
Bogdan 7d77ad68fd Bump caniuse db 2025-05-14 21:25:20 +03:00
Bogdan 6725358db5 Bump babel, fontawesome icons, react-use-measure, react-virtualized and react-window 2025-05-14 21:25:20 +03:00
Bogdan c410e23460 Bump core-js to 3.42 2025-05-14 21:25:20 +03:00
Bogdan 903b86b9a2 Bump version to 1.36.2 2025-05-11 14:48:48 +03:00
Weblate 52a49e6a34 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Discover999 <13189912235@163.com>
Co-authored-by: GkhnGRBZ <gkhn.gurbuz@hotmail.com>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: ZijiYu <ziji.yu@stonybrook.edu>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/tr/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_CN/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_Hans/
Translation: Servarr/Prowlarr
2025-05-11 00:07:11 +03:00
Bogdan a7d99f351c Fixed: Parsing user agents without a version
Fixes #2392
2025-05-11 00:05:29 +03:00
Bogdan b0212dd780 Add hourly limits as defaults for PTP 2025-05-10 11:55:11 +03:00
Bogdan c8f5099423 Use the thrown exception in http timeout handling 2025-05-09 15:58:02 +03:00
Bogdan 5cc4c3f302 Bump version to 1.36.1 2025-05-04 21:06:28 +03:00
Bogdan c0d2cb42e9 Fixed: (PTP) Sorting releases by time added 2025-05-01 17:06:17 +03:00
Bogdan 8081f13052 Clean logging messages in AppriseProxy 2025-05-01 12:12:47 +03:00
Bogdan 84b672e617 Fixed: Sync indexers to apps only if search is available 2025-05-01 01:34:09 +03:00
Bogdan ed586c2d72 Update fixture file for PTP 2025-05-01 00:30:55 +03:00
Bogdan 233176e321 Improve error message when BHD's API responds with HTML 2025-04-30 22:12:30 +03:00
Bogdan d1e3390bae Fixed: (PTP) Category mapping for search results 2025-04-30 22:12:30 +03:00
Bogdan 1cd60c7a40 Bump version to 1.36.0 2025-04-30 14:03:05 +03:00
Bogdan c61cfcd312 Avoid logging the whole response in the exception when not finding JSON selectors in Cardigann 2025-04-30 12:36:34 +03:00
Weblate 5eb4d112ca Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Weblate <noreply-mt-weblate@weblate.org>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/nb_NO/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/uk/
Translation: Servarr/Prowlarr
2025-04-29 11:05:21 +03:00
Mark McDowall 70f2361d69 Improve messaging when NZB contains invalid XML
(cherry picked from commit 728df146ada115a367bf1ce808482a4625e6098d)
2025-04-29 10:58:31 +03:00
Bogdan 1d6babaa15 Bump caniuse db 2025-04-29 10:23:51 +03:00
Bogdan 0427add8d0 Bump core-js to 3.41 2025-04-29 10:23:15 +03:00
Bogdan 010c2b836d Clean up formatted strings in log messages 2025-04-29 10:16:59 +03:00
Bogdan 22c4c1fc9a Pass messages with arguments to NLog in LoggerExtensions
(cherry picked from commit 9683b0af35220bb0af801779a06d73feaeba809a)
2025-04-29 10:14:32 +03:00
Bogdan d5f6cc94b8 Fixed: (PTP) TV search capabilities removed 2025-04-29 10:04:40 +03:00
Bogdan 411e96ef2a New: Redirect enabled by default when adding new usenet indexers 2025-04-28 21:52:09 +03:00
Bogdan 2b0e52ebca Update default log level message 2025-04-27 21:22:37 +03:00
Bogdan c6fa26ca7b Bump version to 1.35.1 2025-04-27 11:48:50 +03:00
blu3 c85f170d41 Bump license year 2025-04-23 11:34:19 +03:00
Bogdan 48a658571b Improve error messaging for not finding JSON selectors in Cardigann 2025-04-21 14:39:22 +03:00
Weblate 0b3a5c9bc4 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Hugoren Martinako <aumpfbahn@gmail.com>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fi/
Translation: Servarr/Prowlarr
2025-04-20 22:30:45 +03:00
Bogdan 356d07ef34 Bump version to 1.35.0 2025-04-20 22:30:15 +03:00
Bogdan 0322d70d63 Fixed: Handle 307 and 308 redirects for indexer download requests 2025-04-20 11:09:08 +03:00
Bogdan 362f3fe223 Bump version to 1.34.1 2025-04-13 09:48:04 +03:00
Bogdan 075fd24f96 Downgrade Microsoft.AspNetCore.WebUtilities 2025-04-12 17:23:45 +03:00
Bogdan 4ba72ea7f3 Bump Swashbuckle to 7.3.2 2025-04-12 14:54:56 +03:00
Bogdan 46f73c51bb Bump IPAddressRange, Npgsql, System.Text.Json 2025-04-12 14:54:01 +03:00
Bogdan 3287d45661 Update timezone offset for AvistaZ trackers 2025-04-12 14:42:25 +03:00
Bogdan 71937fa44c Update timezone offset for FL 2025-04-12 14:33:30 +03:00
Bogdan 6aefd46cd4 Fixed: (SecretCinema) Edition not being decoded 2025-04-12 14:31:29 +03:00
Bogdan c8370c9e00 Bump version to 1.34.0 2025-04-09 20:59:15 +03:00
Servarr 6be4203b41 Automated API Docs update 2025-04-09 10:29:44 +03:00
Bogdan 1339373e43 Bump Selenium.WebDriver.ChromeDriver 2025-04-08 13:30:56 +03:00
Bogdan fc9dfb0cf7 Fixed: Disallow tags creation with empty label 2025-04-08 13:30:03 +03:00
Mark McDowall 48301055ea Fixed: Set output encoding to UTF-8 when running external processes
(cherry picked from commit f8e57b09856278a6d0c65f18704e96a33459687d)
2025-04-08 13:29:32 +03:00
Mark McDowall 8a9518c9c1 Update WikiUrl type in API docs
(cherry picked from commit 9bd619ccfe074abe396bbf043a36a5be18a7ba4b)
2025-04-08 13:29:09 +03:00
Bogdan de099c6770 Log delete statements only once 2025-04-08 13:28:52 +03:00
Bogdan 07711da4e0 Bump version to 1.33.3 2025-04-06 15:44:25 +03:00
MrE12345 7cb70716d0 Fixed: (NorBits) Change encoding to UTF8 (#2367) 2025-04-06 12:43:24 +03:00
Weblate 548dedad5c Multiple Translations updated by Weblate
ignore-downstream

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/prowlarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/cs/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ru/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/uk/
Translation: Servarr/Prowlarr
2025-04-06 12:23:27 +03:00
Bogdan 7008626358 Fixed: (PassThePopcorn) Parse volume factors for neutral leech releases 2025-04-04 21:34:10 +03:00
Bogdan f6f2a3b00d Bump linux agent to ubuntu-22.04 2025-04-02 00:10:40 +03:00
Weblate 2b16d93095 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Alex Mills <alex@alexmills.uk>
Co-authored-by: Lizandra Candido da Silva <lizandra.c.s@gmail.com>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Weblate <noreply-mt-weblate@weblate.org>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/bg/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/cs/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fa/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ko/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/nb_NO/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/tr/
Translation: Servarr/Prowlarr
2025-03-30 10:30:41 +03:00
Bogdan e63ee13d23 Bump version to 1.33.2 2025-03-30 10:30:03 +03:00
Bogdan 5c5a163151 Fixed: (AnimeBytes) Allow season searching for ONA 2025-03-28 13:39:19 +02:00
Bogdan 023eec0ec0 Update timezone offset for PrivateHD and CinemaZ 2025-03-25 13:04:07 +02:00
Bogdan 5bc5f0e6b8 New: Categories, genres, indexer flags and publish dates for webhook releases 2025-03-25 13:00:53 +02:00
Bogdan 5cbacc01eb Fixed: Publish dates timezone in history details for grabbed releases 2025-03-25 13:00:53 +02:00
Bogdan f4f1b38324 New: On Grab notifications for CustomScript 2025-03-25 13:00:53 +02:00
Bogdan 758dddd4ad Bump version to 1.33.1 2025-03-23 09:45:33 +02:00
Bogdan 73ee695633 New: (BeyondHD) Parsing audio and subtitles languages 2025-03-22 21:01:22 +02:00
Bogdan 27fbd7ef7e Fixed: (RuTracker.org) Improve subtitles removal 2025-03-22 12:45:10 +02:00
Bogdan 5125f256fb Fixed: Priority validation for indexers and download clients 2025-03-20 20:38:13 +02:00
Mark McDowall b99e8d0d65 Improve logging when login fails due to CryptographicException
(cherry picked from commit 1449941471cbb8885e9298317b9a30f2576d7941)
2025-03-16 13:10:09 +02:00
Bogdan d20b2cc9c0 Bump NLog and Polly 2025-03-16 12:06:32 +02:00
Bogdan 8a1787bdb6 Bump version to 1.33.0 2025-03-16 11:42:07 +02:00
Mark McDowall a19b8ea997 New: Truncate button text
Fixes #2352

(cherry picked from commit 093ee5b88db0470426f6132e66a5893e5cf89bab)
2025-03-10 20:07:15 +02:00
Mark McDowall 10ea6cd753 Improve wrapping of text in sidebar
(cherry picked from commit f58dfc5605738ebccdd6adc6f1ca2a7843c086b2)
2025-03-10 20:07:15 +02:00
Bogdan 2c1b464715 New: Recommend against using uTorrent
(cherry picked from commit 6d8c3f15b343a24fc31a212463af8ed2b5792508)
2025-03-10 20:07:15 +02:00
Bogdan 3263454041 Bump version to 1.32.2 2025-03-09 11:50:31 +02:00
269 changed files with 2562 additions and 1767 deletions
+2 -2
View File
@@ -2,11 +2,11 @@
// README at: https://github.com/devcontainers/templates/tree/main/src/dotnet // README at: https://github.com/devcontainers/templates/tree/main/src/dotnet
{ {
"name": "Prowlarr", "name": "Prowlarr",
"image": "mcr.microsoft.com/devcontainers/dotnet:1-6.0", "image": "mcr.microsoft.com/devcontainers/dotnet:1-8.0",
"features": { "features": {
"ghcr.io/devcontainers/features/node:1": { "ghcr.io/devcontainers/features/node:1": {
"nodeGypDependencies": true, "nodeGypDependencies": true,
"version": "16", "version": "20",
"nvmVersion": "latest" "nvmVersion": "latest"
} }
}, },
+1 -1
View File
@@ -10,7 +10,7 @@
"request": "launch", "request": "launch",
"preLaunchTask": "build dotnet", "preLaunchTask": "build dotnet",
// If you have changed target frameworks, make sure to update the program path. // If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceFolder}/_output/net6.0/Prowlarr", "program": "${workspaceFolder}/_output/net8.0/Prowlarr",
"args": [], "args": [],
"cwd": "${workspaceFolder}", "cwd": "${workspaceFolder}",
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
+1 -1
View File
@@ -78,6 +78,6 @@ Thank you to [<img src="https://resources.jetbrains.com/storage/products/company
### License ### License
- [GNU GPL v3](http://www.gnu.org/licenses/gpl.html) - [GNU GPL v3](http://www.gnu.org/licenses/gpl.html)
- Copyright 2010-2024 - Copyright 2010-2025
Icon Credit - [Box vector created by freepik - www.freepik.com](https://www.freepik.com/vectors/box) Icon Credit - [Box vector created by freepik - www.freepik.com](https://www.freepik.com/vectors/box)
+53 -77
View File
@@ -9,17 +9,17 @@ variables:
testsFolder: './_tests' testsFolder: './_tests'
yarnCacheFolder: $(Pipeline.Workspace)/.yarn yarnCacheFolder: $(Pipeline.Workspace)/.yarn
nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages
majorVersion: '1.32.1' majorVersion: '2.0.0'
minorVersion: $[counter('minorVersion', 1)] minorVersion: $[counter('minorVersion', 1)]
prowlarrVersion: '$(majorVersion).$(minorVersion)' prowlarrVersion: '$(majorVersion).$(minorVersion)'
buildName: '$(Build.SourceBranchName).$(prowlarrVersion)' buildName: '$(Build.SourceBranchName).$(prowlarrVersion)'
sentryOrg: 'servarr' sentryOrg: 'servarr'
sentryUrl: 'https://sentry.servarr.com' sentryUrl: 'https://sentry.servarr.com'
dotnetVersion: '6.0.427' dotnetVersion: '8.0.405'
nodeVersion: '20.X' nodeVersion: '20.X'
innoVersion: '6.2.2' innoVersion: '6.2.2'
windowsImage: 'windows-2022' windowsImage: 'windows-2022'
linuxImage: 'ubuntu-20.04' linuxImage: 'ubuntu-22.04'
macImage: 'macOS-13' macImage: 'macOS-13'
trigger: trigger:
@@ -106,7 +106,7 @@ stages:
echo "Extra platforms already enabled" echo "Extra platforms already enabled"
else else
echo "Enabling extra platform support" echo "Enabling extra platform support"
sed -i.ORI 's/osx-x64/osx-x64;freebsd-x64;linux-x86/' $BUNDLEDVERSIONS sed -i.ORI 's/osx-x64/osx-x64;freebsd-x64/' "$BUNDLEDVERSIONS"
fi fi
displayName: Enable Extra Platform Support displayName: Enable Extra Platform Support
- bash: ./build.sh --backend --enable-extra-platforms - bash: ./build.sh --backend --enable-extra-platforms
@@ -122,27 +122,23 @@ stages:
artifact: '$(osName)Backend' artifact: '$(osName)Backend'
displayName: Publish Backend displayName: Publish Backend
condition: and(succeeded(), eq(variables['osName'], 'Windows')) condition: and(succeeded(), eq(variables['osName'], 'Windows'))
- publish: '$(testsFolder)/net6.0/win-x64/publish' - publish: '$(testsFolder)/net8.0/win-x64/publish'
artifact: win-x64-tests artifact: win-x64-tests
displayName: Publish win-x64 Test Package displayName: Publish win-x64 Test Package
condition: and(succeeded(), eq(variables['osName'], 'Windows')) condition: and(succeeded(), eq(variables['osName'], 'Windows'))
- publish: '$(testsFolder)/net6.0/linux-x64/publish' - publish: '$(testsFolder)/net8.0/linux-x64/publish'
artifact: linux-x64-tests artifact: linux-x64-tests
displayName: Publish linux-x64 Test Package displayName: Publish linux-x64 Test Package
condition: and(succeeded(), eq(variables['osName'], 'Windows')) condition: and(succeeded(), eq(variables['osName'], 'Windows'))
- publish: '$(testsFolder)/net6.0/linux-x86/publish' - publish: '$(testsFolder)/net8.0/linux-musl-x64/publish'
artifact: linux-x86-tests
displayName: Publish linux-x86 Test Package
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
- publish: '$(testsFolder)/net6.0/linux-musl-x64/publish'
artifact: linux-musl-x64-tests artifact: linux-musl-x64-tests
displayName: Publish linux-musl-x64 Test Package displayName: Publish linux-musl-x64 Test Package
condition: and(succeeded(), eq(variables['osName'], 'Windows')) condition: and(succeeded(), eq(variables['osName'], 'Windows'))
- publish: '$(testsFolder)/net6.0/freebsd-x64/publish' - publish: '$(testsFolder)/net8.0/freebsd-x64/publish'
artifact: freebsd-x64-tests artifact: freebsd-x64-tests
displayName: Publish freebsd-x64 Test Package displayName: Publish freebsd-x64 Test Package
condition: and(succeeded(), eq(variables['osName'], 'Windows')) condition: and(succeeded(), eq(variables['osName'], 'Windows'))
- publish: '$(testsFolder)/net6.0/osx-x64/publish' - publish: '$(testsFolder)/net8.0/osx-x64/publish'
artifact: osx-x64-tests artifact: osx-x64-tests
displayName: Publish osx-x64 Test Package displayName: Publish osx-x64 Test Package
condition: and(succeeded(), eq(variables['osName'], 'Windows')) condition: and(succeeded(), eq(variables['osName'], 'Windows'))
@@ -189,7 +185,7 @@ stages:
artifact: '$(osName)Frontend' artifact: '$(osName)Frontend'
displayName: Publish Frontend displayName: Publish Frontend
condition: and(succeeded(), eq(variables['osName'], 'Windows')) condition: and(succeeded(), eq(variables['osName'], 'Windows'))
- stage: Installer - stage: Installer
dependsOn: dependsOn:
- Build_Backend - Build_Backend
@@ -259,21 +255,21 @@ stages:
archiveFile: '$(Build.ArtifactStagingDirectory)/Prowlarr.$(buildName).windows-core-x64.zip' archiveFile: '$(Build.ArtifactStagingDirectory)/Prowlarr.$(buildName).windows-core-x64.zip'
archiveType: 'zip' archiveType: 'zip'
includeRootFolder: false includeRootFolder: false
rootFolderOrFile: $(artifactsFolder)/win-x64/net6.0 rootFolderOrFile: $(artifactsFolder)/win-x64/net8.0
- task: ArchiveFiles@2 - task: ArchiveFiles@2
displayName: Create win-x86 zip displayName: Create win-x86 zip
inputs: inputs:
archiveFile: '$(Build.ArtifactStagingDirectory)/Prowlarr.$(buildName).windows-core-x86.zip' archiveFile: '$(Build.ArtifactStagingDirectory)/Prowlarr.$(buildName).windows-core-x86.zip'
archiveType: 'zip' archiveType: 'zip'
includeRootFolder: false includeRootFolder: false
rootFolderOrFile: $(artifactsFolder)/win-x86/net6.0 rootFolderOrFile: $(artifactsFolder)/win-x86/net8.0
- task: ArchiveFiles@2 - task: ArchiveFiles@2
displayName: Create osx-x64 app displayName: Create osx-x64 app
inputs: inputs:
archiveFile: '$(Build.ArtifactStagingDirectory)/Prowlarr.$(buildName).osx-app-core-x64.zip' archiveFile: '$(Build.ArtifactStagingDirectory)/Prowlarr.$(buildName).osx-app-core-x64.zip'
archiveType: 'zip' archiveType: 'zip'
includeRootFolder: false includeRootFolder: false
rootFolderOrFile: $(artifactsFolder)/osx-x64-app/net6.0 rootFolderOrFile: $(artifactsFolder)/osx-x64-app/net8.0
- task: ArchiveFiles@2 - task: ArchiveFiles@2
displayName: Create osx-x64 tar displayName: Create osx-x64 tar
inputs: inputs:
@@ -281,14 +277,14 @@ stages:
archiveType: 'tar' archiveType: 'tar'
tarCompression: 'gz' tarCompression: 'gz'
includeRootFolder: false includeRootFolder: false
rootFolderOrFile: $(artifactsFolder)/osx-x64/net6.0 rootFolderOrFile: $(artifactsFolder)/osx-x64/net8.0
- task: ArchiveFiles@2 - task: ArchiveFiles@2
displayName: Create osx-arm64 app displayName: Create osx-arm64 app
inputs: inputs:
archiveFile: '$(Build.ArtifactStagingDirectory)/Prowlarr.$(buildName).osx-app-core-arm64.zip' archiveFile: '$(Build.ArtifactStagingDirectory)/Prowlarr.$(buildName).osx-app-core-arm64.zip'
archiveType: 'zip' archiveType: 'zip'
includeRootFolder: false includeRootFolder: false
rootFolderOrFile: $(artifactsFolder)/osx-arm64-app/net6.0 rootFolderOrFile: $(artifactsFolder)/osx-arm64-app/net8.0
- task: ArchiveFiles@2 - task: ArchiveFiles@2
displayName: Create osx-arm64 tar displayName: Create osx-arm64 tar
inputs: inputs:
@@ -296,7 +292,7 @@ stages:
archiveType: 'tar' archiveType: 'tar'
tarCompression: 'gz' tarCompression: 'gz'
includeRootFolder: false includeRootFolder: false
rootFolderOrFile: $(artifactsFolder)/osx-arm64/net6.0 rootFolderOrFile: $(artifactsFolder)/osx-arm64/net8.0
- task: ArchiveFiles@2 - task: ArchiveFiles@2
displayName: Create linux-x64 tar displayName: Create linux-x64 tar
inputs: inputs:
@@ -304,7 +300,7 @@ stages:
archiveType: 'tar' archiveType: 'tar'
tarCompression: 'gz' tarCompression: 'gz'
includeRootFolder: false includeRootFolder: false
rootFolderOrFile: $(artifactsFolder)/linux-x64/net6.0 rootFolderOrFile: $(artifactsFolder)/linux-x64/net8.0
- task: ArchiveFiles@2 - task: ArchiveFiles@2
displayName: Create linux-musl-x64 tar displayName: Create linux-musl-x64 tar
inputs: inputs:
@@ -312,15 +308,7 @@ stages:
archiveType: 'tar' archiveType: 'tar'
tarCompression: 'gz' tarCompression: 'gz'
includeRootFolder: false includeRootFolder: false
rootFolderOrFile: $(artifactsFolder)/linux-musl-x64/net6.0 rootFolderOrFile: $(artifactsFolder)/linux-musl-x64/net8.0
- task: ArchiveFiles@2
displayName: Create linux-x86 tar
inputs:
archiveFile: '$(Build.ArtifactStagingDirectory)/Prowlarr.$(buildName).linux-core-x86.tar.gz'
archiveType: 'tar'
tarCompression: 'gz'
includeRootFolder: false
rootFolderOrFile: $(artifactsFolder)/linux-x86/net6.0
- task: ArchiveFiles@2 - task: ArchiveFiles@2
displayName: Create linux-arm tar displayName: Create linux-arm tar
inputs: inputs:
@@ -328,7 +316,7 @@ stages:
archiveType: 'tar' archiveType: 'tar'
tarCompression: 'gz' tarCompression: 'gz'
includeRootFolder: false includeRootFolder: false
rootFolderOrFile: $(artifactsFolder)/linux-arm/net6.0 rootFolderOrFile: $(artifactsFolder)/linux-arm/net8.0
- task: ArchiveFiles@2 - task: ArchiveFiles@2
displayName: Create linux-musl-arm tar displayName: Create linux-musl-arm tar
inputs: inputs:
@@ -336,7 +324,7 @@ stages:
archiveType: 'tar' archiveType: 'tar'
tarCompression: 'gz' tarCompression: 'gz'
includeRootFolder: false includeRootFolder: false
rootFolderOrFile: $(artifactsFolder)/linux-musl-arm/net6.0 rootFolderOrFile: $(artifactsFolder)/linux-musl-arm/net8.0
- task: ArchiveFiles@2 - task: ArchiveFiles@2
displayName: Create linux-arm64 tar displayName: Create linux-arm64 tar
inputs: inputs:
@@ -344,7 +332,7 @@ stages:
archiveType: 'tar' archiveType: 'tar'
tarCompression: 'gz' tarCompression: 'gz'
includeRootFolder: false includeRootFolder: false
rootFolderOrFile: $(artifactsFolder)/linux-arm64/net6.0 rootFolderOrFile: $(artifactsFolder)/linux-arm64/net8.0
- task: ArchiveFiles@2 - task: ArchiveFiles@2
displayName: Create linux-musl-arm64 tar displayName: Create linux-musl-arm64 tar
inputs: inputs:
@@ -352,7 +340,7 @@ stages:
archiveType: 'tar' archiveType: 'tar'
tarCompression: 'gz' tarCompression: 'gz'
includeRootFolder: false includeRootFolder: false
rootFolderOrFile: $(artifactsFolder)/linux-musl-arm64/net6.0 rootFolderOrFile: $(artifactsFolder)/linux-musl-arm64/net8.0
- task: ArchiveFiles@2 - task: ArchiveFiles@2
displayName: Create freebsd-x64 tar displayName: Create freebsd-x64 tar
inputs: inputs:
@@ -360,7 +348,7 @@ stages:
archiveType: 'tar' archiveType: 'tar'
tarCompression: 'gz' tarCompression: 'gz'
includeRootFolder: false includeRootFolder: false
rootFolderOrFile: $(artifactsFolder)/freebsd-x64/net6.0 rootFolderOrFile: $(artifactsFolder)/freebsd-x64/net8.0
- publish: $(Build.ArtifactStagingDirectory) - publish: $(Build.ArtifactStagingDirectory)
artifact: 'Packages' artifact: 'Packages'
displayName: Publish Packages displayName: Publish Packages
@@ -391,7 +379,7 @@ stages:
SENTRY_AUTH_TOKEN: $(sentryAuthTokenServarr) SENTRY_AUTH_TOKEN: $(sentryAuthTokenServarr)
SENTRY_ORG: $(sentryOrg) SENTRY_ORG: $(sentryOrg)
SENTRY_URL: $(sentryUrl) SENTRY_URL: $(sentryUrl)
- stage: Unit_Test - stage: Unit_Test
displayName: Unit Tests displayName: Unit Tests
dependsOn: Build_Backend dependsOn: Build_Backend
@@ -476,6 +464,7 @@ stages:
testResultsFiles: '**/TestResult.xml' testResultsFiles: '**/TestResult.xml'
testRunTitle: '$(testName) Unit Tests' testRunTitle: '$(testName) Unit Tests'
failTaskOnFailedTests: true failTaskOnFailedTests: true
failTaskOnMissingResultsFile: ne(variables['testName'], 'freebsd-x64')
- job: Unit_Docker - job: Unit_Docker
displayName: Unit Docker displayName: Unit Docker
@@ -487,29 +476,19 @@ stages:
testName: 'Musl Net Core' testName: 'Musl Net Core'
artifactName: linux-musl-x64-tests artifactName: linux-musl-x64-tests
containerImage: ghcr.io/servarr/testimages:alpine containerImage: ghcr.io/servarr/testimages:alpine
linux-x86:
testName: 'linux-x86'
artifactName: linux-x86-tests
containerImage: ghcr.io/servarr/testimages:linux-x86
pool: pool:
vmImage: ${{ variables.linuxImage }} vmImage: ${{ variables.linuxImage }}
container: $[ variables['containerImage'] ] container: $[ variables['containerImage'] ]
timeoutInMinutes: 10 timeoutInMinutes: 10
steps: steps:
- task: UseDotNet@2 - task: UseDotNet@2
displayName: 'Install .NET' displayName: 'Install .NET'
inputs: inputs:
version: $(dotnetVersion) version: $(dotnetVersion)
condition: and(succeeded(), ne(variables['testName'], 'linux-x86'))
- bash: |
SDKURL=$(curl -s https://api.github.com/repos/Servarr/dotnet-linux-x86/releases | jq -rc '.[].assets[].browser_download_url' | grep sdk-${DOTNETVERSION}.*gz$)
curl -fsSL $SDKURL | tar xzf - -C /opt/dotnet
displayName: 'Install .NET'
condition: and(succeeded(), eq(variables['testName'], 'linux-x86'))
- checkout: none - checkout: none
- task: DownloadPipelineArtifact@2 - task: DownloadPipelineArtifact@2
displayName: Download Test Artifact displayName: Download Test Artifact
@@ -532,7 +511,8 @@ stages:
testResultsFiles: '**/TestResult.xml' testResultsFiles: '**/TestResult.xml'
testRunTitle: '$(testName) Unit Tests' testRunTitle: '$(testName) Unit Tests'
failTaskOnFailedTests: true failTaskOnFailedTests: true
failTaskOnMissingResultsFile: true
- job: Unit_LinuxCore_Postgres14 - job: Unit_LinuxCore_Postgres14
displayName: Unit Native LinuxCore with Postgres14 Database displayName: Unit Native LinuxCore with Postgres14 Database
dependsOn: Prepare dependsOn: Prepare
@@ -549,7 +529,7 @@ stages:
vmImage: ${{ variables.linuxImage }} vmImage: ${{ variables.linuxImage }}
timeoutInMinutes: 10 timeoutInMinutes: 10
steps: steps:
- task: UseDotNet@2 - task: UseDotNet@2
displayName: 'Install .net core' displayName: 'Install .net core'
@@ -585,6 +565,7 @@ stages:
testResultsFiles: '**/TestResult.xml' testResultsFiles: '**/TestResult.xml'
testRunTitle: 'LinuxCore Postgres14 Unit Tests' testRunTitle: 'LinuxCore Postgres14 Unit Tests'
failTaskOnFailedTests: true failTaskOnFailedTests: true
failTaskOnMissingResultsFile: true
- job: Unit_LinuxCore_Postgres15 - job: Unit_LinuxCore_Postgres15
displayName: Unit Native LinuxCore with Postgres15 Database displayName: Unit Native LinuxCore with Postgres15 Database
@@ -597,12 +578,12 @@ stages:
Prowlarr__Postgres__Port: '5432' Prowlarr__Postgres__Port: '5432'
Prowlarr__Postgres__User: 'prowlarr' Prowlarr__Postgres__User: 'prowlarr'
Prowlarr__Postgres__Password: 'prowlarr' Prowlarr__Postgres__Password: 'prowlarr'
pool: pool:
vmImage: ${{ variables.linuxImage }} vmImage: ${{ variables.linuxImage }}
timeoutInMinutes: 10 timeoutInMinutes: 10
steps: steps:
- task: UseDotNet@2 - task: UseDotNet@2
displayName: 'Install .net core' displayName: 'Install .net core'
@@ -638,6 +619,7 @@ stages:
testResultsFiles: '**/TestResult.xml' testResultsFiles: '**/TestResult.xml'
testRunTitle: 'LinuxCore Postgres15 Unit Tests' testRunTitle: 'LinuxCore Postgres15 Unit Tests'
failTaskOnFailedTests: true failTaskOnFailedTests: true
failTaskOnMissingResultsFile: true
- stage: Integration - stage: Integration
displayName: Integration displayName: Integration
@@ -681,7 +663,7 @@ stages:
pool: pool:
vmImage: $(imageName) vmImage: $(imageName)
steps: steps:
- task: UseDotNet@2 - task: UseDotNet@2
displayName: 'Install .net core' displayName: 'Install .net core'
@@ -703,7 +685,7 @@ stages:
targetPath: $(Build.ArtifactStagingDirectory) targetPath: $(Build.ArtifactStagingDirectory)
- task: ExtractFiles@1 - task: ExtractFiles@1
inputs: inputs:
archiveFilePatterns: '$(Build.ArtifactStagingDirectory)/**/$(pattern)' archiveFilePatterns: '$(Build.ArtifactStagingDirectory)/**/$(pattern)'
destinationFolder: '$(Build.ArtifactStagingDirectory)/bin' destinationFolder: '$(Build.ArtifactStagingDirectory)/bin'
displayName: Extract Package displayName: Extract Package
- bash: | - bash: |
@@ -720,6 +702,7 @@ stages:
testResultsFiles: '**/TestResult.xml' testResultsFiles: '**/TestResult.xml'
testRunTitle: '$(testName) Integration Tests' testRunTitle: '$(testName) Integration Tests'
failTaskOnFailedTests: true failTaskOnFailedTests: true
failTaskOnMissingResultsFile: true
displayName: Publish Test Results displayName: Publish Test Results
- job: Integration_LinuxCore_Postgres14 - job: Integration_LinuxCore_Postgres14
@@ -757,7 +740,7 @@ stages:
targetPath: $(Build.ArtifactStagingDirectory) targetPath: $(Build.ArtifactStagingDirectory)
- task: ExtractFiles@1 - task: ExtractFiles@1
inputs: inputs:
archiveFilePatterns: '$(Build.ArtifactStagingDirectory)/**/$(pattern)' archiveFilePatterns: '$(Build.ArtifactStagingDirectory)/**/$(pattern)'
destinationFolder: '$(Build.ArtifactStagingDirectory)/bin' destinationFolder: '$(Build.ArtifactStagingDirectory)/bin'
displayName: Extract Package displayName: Extract Package
- bash: | - bash: |
@@ -782,6 +765,7 @@ stages:
testResultsFiles: '**/TestResult.xml' testResultsFiles: '**/TestResult.xml'
testRunTitle: 'Integration LinuxCore Postgres14 Database Integration Tests' testRunTitle: 'Integration LinuxCore Postgres14 Database Integration Tests'
failTaskOnFailedTests: true failTaskOnFailedTests: true
failTaskOnMissingResultsFile: true
displayName: Publish Test Results displayName: Publish Test Results
@@ -820,7 +804,7 @@ stages:
targetPath: $(Build.ArtifactStagingDirectory) targetPath: $(Build.ArtifactStagingDirectory)
- task: ExtractFiles@1 - task: ExtractFiles@1
inputs: inputs:
archiveFilePatterns: '$(Build.ArtifactStagingDirectory)/**/$(pattern)' archiveFilePatterns: '$(Build.ArtifactStagingDirectory)/**/$(pattern)'
destinationFolder: '$(Build.ArtifactStagingDirectory)/bin' destinationFolder: '$(Build.ArtifactStagingDirectory)/bin'
displayName: Extract Package displayName: Extract Package
- bash: | - bash: |
@@ -845,6 +829,7 @@ stages:
testResultsFiles: '**/TestResult.xml' testResultsFiles: '**/TestResult.xml'
testRunTitle: 'Integration LinuxCore Postgres15 Database Integration Tests' testRunTitle: 'Integration LinuxCore Postgres15 Database Integration Tests'
failTaskOnFailedTests: true failTaskOnFailedTests: true
failTaskOnMissingResultsFile: true
displayName: Publish Test Results displayName: Publish Test Results
- job: Integration_FreeBSD - job: Integration_FreeBSD
@@ -891,6 +876,7 @@ stages:
testResultsFiles: '**/TestResult.xml' testResultsFiles: '**/TestResult.xml'
testRunTitle: 'FreeBSD Integration Tests' testRunTitle: 'FreeBSD Integration Tests'
failTaskOnFailedTests: true failTaskOnFailedTests: true
failTaskOnMissingResultsFile: false
displayName: Publish Test Results displayName: Publish Test Results
- job: Integration_Docker - job: Integration_Docker
@@ -904,29 +890,18 @@ stages:
artifactName: linux-musl-x64-tests artifactName: linux-musl-x64-tests
containerImage: ghcr.io/servarr/testimages:alpine containerImage: ghcr.io/servarr/testimages:alpine
pattern: 'Prowlarr.*.linux-musl-core-x64.tar.gz' pattern: 'Prowlarr.*.linux-musl-core-x64.tar.gz'
linux-x86:
testName: 'linux-x86'
artifactName: linux-x86-tests
containerImage: ghcr.io/servarr/testimages:linux-x86
pattern: 'Prowlarr.*.linux-core-x86.tar.gz'
pool: pool:
vmImage: ${{ variables.linuxImage }} vmImage: ${{ variables.linuxImage }}
container: $[ variables['containerImage'] ] container: $[ variables['containerImage'] ]
timeoutInMinutes: 15 timeoutInMinutes: 15
steps: steps:
- task: UseDotNet@2 - task: UseDotNet@2
displayName: 'Install .NET' displayName: 'Install .NET'
inputs: inputs:
version: $(dotnetVersion) version: $(dotnetVersion)
condition: and(succeeded(), ne(variables['testName'], 'linux-x86'))
- bash: |
SDKURL=$(curl -s https://api.github.com/repos/Servarr/dotnet-linux-x86/releases | jq -rc '.[].assets[].browser_download_url' | grep sdk-${DOTNETVERSION}.*gz$)
curl -fsSL $SDKURL | tar xzf - -C /opt/dotnet
displayName: 'Install .NET'
condition: and(succeeded(), eq(variables['testName'], 'linux-x86'))
- checkout: none - checkout: none
- task: DownloadPipelineArtifact@2 - task: DownloadPipelineArtifact@2
displayName: Download Test Artifact displayName: Download Test Artifact
@@ -943,7 +918,7 @@ stages:
targetPath: $(Build.ArtifactStagingDirectory) targetPath: $(Build.ArtifactStagingDirectory)
- task: ExtractFiles@1 - task: ExtractFiles@1
inputs: inputs:
archiveFilePatterns: '$(Build.ArtifactStagingDirectory)/**/$(pattern)' archiveFilePatterns: '$(Build.ArtifactStagingDirectory)/**/$(pattern)'
destinationFolder: '$(Build.ArtifactStagingDirectory)/bin' destinationFolder: '$(Build.ArtifactStagingDirectory)/bin'
displayName: Extract Package displayName: Extract Package
- bash: | - bash: |
@@ -960,12 +935,13 @@ stages:
testResultsFiles: '**/TestResult.xml' testResultsFiles: '**/TestResult.xml'
testRunTitle: '$(testName) Integration Tests' testRunTitle: '$(testName) Integration Tests'
failTaskOnFailedTests: true failTaskOnFailedTests: true
failTaskOnMissingResultsFile: true
displayName: Publish Test Results displayName: Publish Test Results
- stage: Automation - stage: Automation
displayName: Automation displayName: Automation
dependsOn: Packages dependsOn: Packages
jobs: jobs:
- job: Automation - job: Automation
strategy: strategy:
@@ -991,7 +967,7 @@ stages:
pool: pool:
vmImage: $(imageName) vmImage: $(imageName)
steps: steps:
- task: UseDotNet@2 - task: UseDotNet@2
displayName: 'Install .net core' displayName: 'Install .net core'
@@ -1013,7 +989,7 @@ stages:
targetPath: $(Build.ArtifactStagingDirectory) targetPath: $(Build.ArtifactStagingDirectory)
- task: ExtractFiles@1 - task: ExtractFiles@1
inputs: inputs:
archiveFilePatterns: '$(Build.ArtifactStagingDirectory)/**/$(pattern)' archiveFilePatterns: '$(Build.ArtifactStagingDirectory)/**/$(pattern)'
destinationFolder: '$(Build.ArtifactStagingDirectory)/bin' destinationFolder: '$(Build.ArtifactStagingDirectory)/bin'
displayName: Extract Package displayName: Extract Package
- bash: | - bash: |
@@ -1041,6 +1017,7 @@ stages:
testResultsFiles: '**/TestResult.xml' testResultsFiles: '**/TestResult.xml'
testRunTitle: '$(osName) Automation Tests' testRunTitle: '$(osName) Automation Tests'
failTaskOnFailedTests: $(failBuild) failTaskOnFailedTests: $(failBuild)
failTaskOnMissingResultsFile: $(failBuild)
displayName: Publish Test Results displayName: Publish Test Results
- stage: Analyze - stage: Analyze
@@ -1116,7 +1093,7 @@ stages:
- checkout: self - checkout: self
submodules: true submodules: true
persistCredentials: true persistCredentials: true
fetchDepth: 1 fetchDepth: 1
- bash: ./docs.sh Windows - bash: ./docs.sh Windows
displayName: Create openapi.json displayName: Create openapi.json
- bash: | - bash: |
@@ -1184,13 +1161,13 @@ stages:
sonar.cs.opencover.reportsPaths=$(Build.SourcesDirectory)/CoverageResults/**/coverage.opencover.xml sonar.cs.opencover.reportsPaths=$(Build.SourcesDirectory)/CoverageResults/**/coverage.opencover.xml
sonar.cs.nunit.reportsPaths=$(Build.SourcesDirectory)/TestResult.xml sonar.cs.nunit.reportsPaths=$(Build.SourcesDirectory)/TestResult.xml
- bash: | - bash: |
./build.sh --backend -f net6.0 -r win-x64 ./build.sh --backend -f net8.0 -r win-x64
TEST_DIR=_tests/net6.0/win-x64/publish/ ./test.sh Windows Unit Coverage TEST_DIR=_tests/net8.0/win-x64/publish/ ./test.sh Windows Unit Coverage
displayName: Coverage Unit Tests displayName: Coverage Unit Tests
- task: SonarCloudAnalyze@3 - task: SonarCloudAnalyze@3
condition: eq(variables['System.PullRequest.IsFork'], 'False') condition: eq(variables['System.PullRequest.IsFork'], 'False')
displayName: Publish SonarCloud Results displayName: Publish SonarCloud Results
- task: reportgenerator@5.3.11 - task: reportgenerator@5
displayName: Generate Coverage Report displayName: Generate Coverage Report
inputs: inputs:
reports: '$(Build.SourcesDirectory)/CoverageResults/**/coverage.opencover.xml' reports: '$(Build.SourcesDirectory)/CoverageResults/**/coverage.opencover.xml'
@@ -1228,4 +1205,3 @@ stages:
DISCORDCHANNELID: $(discordChannelId) DISCORDCHANNELID: $(discordChannelId)
DISCORDWEBHOOKKEY: $(discordWebhookKey) DISCORDWEBHOOKKEY: $(discordWebhookKey)
DISCORDTHREADID: $(discordThreadId) DISCORDTHREADID: $(discordThreadId)
+25 -27
View File
@@ -33,14 +33,14 @@ EnableExtraPlatformsInSDK()
echo "Extra platforms already enabled" echo "Extra platforms already enabled"
else else
echo "Enabling extra platform support" echo "Enabling extra platform support"
sed -i.ORI 's/osx-x64/osx-x64;freebsd-x64;linux-x86/' $BUNDLEDVERSIONS sed -i.ORI 's/osx-x64/osx-x64;freebsd-x64/' "$BUNDLEDVERSIONS"
fi fi
} }
EnableExtraPlatforms() EnableExtraPlatforms()
{ {
if grep -qv freebsd-x64 src/Directory.Build.props; then if grep -qv freebsd-x64 src/Directory.Build.props; then
sed -i'' -e "s^<RuntimeIdentifiers>\(.*\)</RuntimeIdentifiers>^<RuntimeIdentifiers>\1;freebsd-x64;linux-x86</RuntimeIdentifiers>^g" src/Directory.Build.props sed -i'' -e "s^<RuntimeIdentifiers>\(.*\)</RuntimeIdentifiers>^<RuntimeIdentifiers>\1;freebsd-x64</RuntimeIdentifiers>^g" src/Directory.Build.props
fi fi
} }
@@ -79,9 +79,9 @@ Build()
if [[ -z "$RID" || -z "$FRAMEWORK" ]]; if [[ -z "$RID" || -z "$FRAMEWORK" ]];
then then
dotnet msbuild -restore $slnFile -p:Configuration=Release -p:Platform=$platform -t:PublishAllRids dotnet msbuild -restore $slnFile -p:SelfContained=True -p:Configuration=Release -p:Platform=$platform -t:PublishAllRids
else else
dotnet msbuild -restore $slnFile -p:Configuration=Release -p:Platform=$platform -p:RuntimeIdentifiers=$RID -t:PublishAllRids dotnet msbuild -restore $slnFile -p:SelfContained=True -p:Configuration=Release -p:Platform=$platform -p:RuntimeIdentifiers=$RID -t:PublishAllRids
fi fi
ProgressEnd 'Build' ProgressEnd 'Build'
@@ -137,7 +137,7 @@ PackageLinux()
echo "Adding Prowlarr.Mono to UpdatePackage" echo "Adding Prowlarr.Mono to UpdatePackage"
cp $folder/Prowlarr.Mono.* $folder/Prowlarr.Update cp $folder/Prowlarr.Mono.* $folder/Prowlarr.Update
if [ "$framework" = "net6.0" ]; then if [ "$framework" = "net8.0" ]; then
cp $folder/Mono.Posix.NETStandard.* $folder/Prowlarr.Update cp $folder/Mono.Posix.NETStandard.* $folder/Prowlarr.Update
cp $folder/libMonoPosixHelper.* $folder/Prowlarr.Update cp $folder/libMonoPosixHelper.* $folder/Prowlarr.Update
fi fi
@@ -165,7 +165,7 @@ PackageMacOS()
echo "Adding Prowlarr.Mono to UpdatePackage" echo "Adding Prowlarr.Mono to UpdatePackage"
cp $folder/Prowlarr.Mono.* $folder/Prowlarr.Update cp $folder/Prowlarr.Mono.* $folder/Prowlarr.Update
if [ "$framework" = "net6.0" ]; then if [ "$framework" = "net8.0" ]; then
cp $folder/Mono.Posix.NETStandard.* $folder/Prowlarr.Update cp $folder/Mono.Posix.NETStandard.* $folder/Prowlarr.Update
cp $folder/libMonoPosixHelper.* $folder/Prowlarr.Update cp $folder/libMonoPosixHelper.* $folder/Prowlarr.Update
fi fi
@@ -377,15 +377,14 @@ then
Build Build
if [[ -z "$RID" || -z "$FRAMEWORK" ]]; if [[ -z "$RID" || -z "$FRAMEWORK" ]];
then then
PackageTests "net6.0" "win-x64" PackageTests "net8.0" "win-x64"
PackageTests "net6.0" "win-x86" PackageTests "net8.0" "win-x86"
PackageTests "net6.0" "linux-x64" PackageTests "net8.0" "linux-x64"
PackageTests "net6.0" "linux-musl-x64" PackageTests "net8.0" "linux-musl-x64"
PackageTests "net6.0" "osx-x64" PackageTests "net8.0" "osx-x64"
if [ "$ENABLE_EXTRA_PLATFORMS" = "YES" ]; if [ "$ENABLE_EXTRA_PLATFORMS" = "YES" ];
then then
PackageTests "net6.0" "freebsd-x64" PackageTests "net8.0" "freebsd-x64"
PackageTests "net6.0" "linux-x86"
fi fi
else else
PackageTests "$FRAMEWORK" "$RID" PackageTests "$FRAMEWORK" "$RID"
@@ -413,20 +412,19 @@ then
if [[ -z "$RID" || -z "$FRAMEWORK" ]]; if [[ -z "$RID" || -z "$FRAMEWORK" ]];
then then
Package "net6.0" "win-x64" Package "net8.0" "win-x64"
Package "net6.0" "win-x86" Package "net8.0" "win-x86"
Package "net6.0" "linux-x64" Package "net8.0" "linux-x64"
Package "net6.0" "linux-musl-x64" Package "net8.0" "linux-musl-x64"
Package "net6.0" "linux-arm64" Package "net8.0" "linux-arm64"
Package "net6.0" "linux-musl-arm64" Package "net8.0" "linux-musl-arm64"
Package "net6.0" "linux-arm" Package "net8.0" "linux-arm"
Package "net6.0" "linux-musl-arm" Package "net8.0" "linux-musl-arm"
Package "net6.0" "osx-x64" Package "net8.0" "osx-x64"
Package "net6.0" "osx-arm64" Package "net8.0" "osx-arm64"
if [ "$ENABLE_EXTRA_PLATFORMS" = "YES" ]; if [ "$ENABLE_EXTRA_PLATFORMS" = "YES" ];
then then
Package "net6.0" "freebsd-x64" Package "net8.0" "freebsd-x64"
Package "net6.0" "linux-x86"
fi fi
else else
Package "$FRAMEWORK" "$RID" Package "$FRAMEWORK" "$RID"
@@ -436,7 +434,7 @@ fi
if [ "$INSTALLER" = "YES" ]; if [ "$INSTALLER" = "YES" ];
then then
InstallInno InstallInno
BuildInstaller "net6.0" "win-x64" BuildInstaller "net8.0" "win-x64"
BuildInstaller "net6.0" "win-x86" BuildInstaller "net8.0" "win-x86"
RemoveInno RemoveInno
fi fi
+2 -2
View File
@@ -1,7 +1,7 @@
#!/bin/bash #!/bin/bash
set -e set -e
FRAMEWORK="net6.0" FRAMEWORK="net8.0"
PLATFORM=$1 PLATFORM=$1
ARCHITECTURE="${2:-x64}" ARCHITECTURE="${2:-x64}"
@@ -38,7 +38,7 @@ dotnet clean $slnFile -c Release
dotnet msbuild -restore $slnFile -p:Configuration=Debug -p:Platform=$platform -p:RuntimeIdentifiers=$RUNTIME -t:PublishAllRids dotnet msbuild -restore $slnFile -p:Configuration=Debug -p:Platform=$platform -p:RuntimeIdentifiers=$RUNTIME -t:PublishAllRids
dotnet new tool-manifest dotnet new tool-manifest
dotnet tool install --version 6.6.2 Swashbuckle.AspNetCore.Cli dotnet tool install --version 8.1.4 Swashbuckle.AspNetCore.Cli
dotnet tool run swagger tofile --output ./src/Prowlarr.Api.V1/openapi.json "$outputFolder/$FRAMEWORK/$RUNTIME/$application" v1 & dotnet tool run swagger tofile --output ./src/Prowlarr.Api.V1/openapi.json "$outputFolder/$FRAMEWORK/$RUNTIME/$application" v1 &
+1 -1
View File
@@ -170,7 +170,7 @@ module.exports = (env) => {
loose: true, loose: true,
debug: false, debug: false,
useBuiltIns: 'entry', useBuiltIns: 'entry',
corejs: '3.39' corejs: '3.42'
} }
] ]
] ]
@@ -24,6 +24,7 @@
composes: link; composes: link;
padding: 10px 24px; padding: 10px 24px;
padding-left: 35px;
} }
.isActiveLink { .isActiveLink {
@@ -41,10 +42,6 @@
text-align: center; text-align: center;
} }
.noIcon {
margin-left: 25px;
}
.status { .status {
float: right; float: right;
} }
@@ -8,7 +8,6 @@ interface CssExports {
'isActiveParentLink': string; 'isActiveParentLink': string;
'item': string; 'item': string;
'link': string; 'link': string;
'noIcon': string;
'status': string; 'status': string;
} }
export const cssExports: CssExports; export const cssExports: CssExports;
@@ -63,9 +63,7 @@ class PageSidebarItem extends Component {
</span> </span>
} }
<span className={isChildItem ? styles.noIcon : null}> {typeof title === 'function' ? title() : title}
{typeof title === 'function' ? title() : title}
</span>
{ {
!!StatusComponent && !!StatusComponent &&
@@ -22,11 +22,14 @@
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
overflow: hidden;
height: 24px; height: 24px;
} }
.label { .label {
padding: 0 3px; padding: 0 3px;
max-width: 100%;
max-height: 100%;
color: var(--toolbarLabelColor); color: var(--toolbarLabelColor);
font-size: $extraSmallFontSize; font-size: $extraSmallFontSize;
line-height: calc($extraSmallFontSize + 1px); line-height: calc($extraSmallFontSize + 1px);
@@ -23,6 +23,7 @@ function PageToolbarButton(props) {
isDisabled && styles.isDisabled isDisabled && styles.isDisabled
)} )}
isDisabled={isDisabled || isSpinning} isDisabled={isDisabled || isSpinning}
title={label}
{...otherProps} {...otherProps}
> >
<Icon <Icon
+15 -2
View File
@@ -65,17 +65,30 @@ class VirtualTable extends Component {
if (this._grid && scrollTop !== undefined && scrollTop !== 0 && !scrollRestored) { if (this._grid && scrollTop !== undefined && scrollTop !== 0 && !scrollRestored) {
this.setState({ scrollRestored: true }); this.setState({ scrollRestored: true });
this._grid.scrollToPosition({ scrollTop }); this._gridScrollToPosition({ scrollTop });
} }
if (scrollIndex != null && scrollIndex !== prevProps.scrollIndex) { if (scrollIndex != null && scrollIndex !== prevProps.scrollIndex) {
this._grid.scrollToCell({ this._gridScrollToCell({
rowIndex: scrollIndex, rowIndex: scrollIndex,
columnIndex: 0 columnIndex: 0
}); });
} }
} }
_gridScrollToCell = ({ rowIndex = 0, columnIndex = 0 }) => {
const scrollOffset = this._grid.getOffsetForCell({
rowIndex,
columnIndex
});
this._gridScrollToPosition(scrollOffset);
};
_gridScrollToPosition = ({ scrollTop = 0, scrollLeft = 0 }) => {
this.props.scroller?.scrollTo({ top: scrollTop, left: scrollLeft });
};
// //
// Control // Control
@@ -21,7 +21,7 @@ function createMapStateToProps() {
) => { ) => {
// If a release is deleted this selector may fire before the parent // If a release is deleted this selector may fire before the parent
// selecors, which will result in an undefined release, if that happens // selectors, which will result in an undefined release, if that happens
// we want to return early here and again in the render function to avoid // we want to return early here and again in the render function to avoid
// trying to show a release that has no information available. // trying to show a release that has no information available.
@@ -30,7 +30,9 @@ export const authenticationMethodOptions = [
key: 'basic', key: 'basic',
get value() { get value() {
return translate('AuthBasic'); return translate('AuthBasic');
} },
isDisabled: true,
isHidden: true
}, },
{ {
key: 'forms', key: 'forms',
+1 -1
View File
@@ -419,7 +419,7 @@ export const reducers = createHandleActions({
const items = newState.items; const items = newState.items;
const index = items.findIndex((item) => item.guid === guid); const index = items.findIndex((item) => item.guid === guid);
// Don't try to update if there isnt a matching item (the user closed the modal) // Don't try to update if there isn't a matching item (the user closed the modal)
if (index >= 0) { if (index >= 0) {
const item = Object.assign({}, items[index], payload); const item = Object.assign({}, items[index], payload);
@@ -2,8 +2,8 @@ import { createSelector } from 'reselect';
import { isCommandExecuting } from 'Utilities/Command'; import { isCommandExecuting } from 'Utilities/Command';
import createCommandSelector from './createCommandSelector'; import createCommandSelector from './createCommandSelector';
function createCommandExecutingSelector(name: string, contraints = {}) { function createCommandExecutingSelector(name: string, constraints = {}) {
return createSelector(createCommandSelector(name, contraints), (command) => { return createSelector(createCommandSelector(name, constraints), (command) => {
return isCommandExecuting(command); return isCommandExecuting(command);
}); });
} }
@@ -2,9 +2,9 @@ import { createSelector } from 'reselect';
import { findCommand } from 'Utilities/Command'; import { findCommand } from 'Utilities/Command';
import createCommandsSelector from './createCommandsSelector'; import createCommandsSelector from './createCommandsSelector';
function createCommandSelector(name: string, contraints = {}) { function createCommandSelector(name: string, constraints = {}) {
return createSelector(createCommandsSelector(), (commands) => { return createSelector(createCommandsSelector(), (commands) => {
return findCommand(commands, { name, ...contraints }); return findCommand(commands, { name, ...constraints });
}); });
} }
+5
View File
@@ -0,0 +1,5 @@
{
"sdk": {
"version": "8.0.405"
}
}
+16 -16
View File
@@ -23,17 +23,17 @@
"defaults" "defaults"
], ],
"dependencies": { "dependencies": {
"@fortawesome/fontawesome-free": "6.7.1", "@fortawesome/fontawesome-free": "6.7.2",
"@fortawesome/fontawesome-svg-core": "6.7.1", "@fortawesome/fontawesome-svg-core": "6.7.2",
"@fortawesome/free-regular-svg-icons": "6.7.1", "@fortawesome/free-regular-svg-icons": "6.7.2",
"@fortawesome/free-solid-svg-icons": "6.7.1", "@fortawesome/free-solid-svg-icons": "6.7.2",
"@fortawesome/react-fontawesome": "0.2.2", "@fortawesome/react-fontawesome": "0.2.2",
"@juggle/resize-observer": "3.4.0", "@juggle/resize-observer": "3.4.0",
"@microsoft/signalr": "6.0.25", "@microsoft/signalr": "8.0.7",
"@sentry/browser": "7.119.1", "@sentry/browser": "7.119.1",
"@sentry/integrations": "7.119.1", "@sentry/integrations": "7.119.1",
"@types/node": "20.16.11", "@types/node": "20.16.11",
"@types/react": "18.2.79", "@types/react": "18.3.21",
"@types/react-dom": "18.2.25", "@types/react-dom": "18.2.25",
"chart.js": "4.4.4", "chart.js": "4.4.4",
"classnames": "2.5.1", "classnames": "2.5.1",
@@ -71,9 +71,9 @@
"react-router-dom": "5.2.0", "react-router-dom": "5.2.0",
"react-tabs": "4.3.0", "react-tabs": "4.3.0",
"react-text-truncate": "0.19.0", "react-text-truncate": "0.19.0",
"react-use-measure": "2.1.1", "react-use-measure": "2.1.7",
"react-virtualized": "9.21.1", "react-virtualized": "9.22.6",
"react-window": "1.8.10", "react-window": "1.8.11",
"redux": "4.2.1", "redux": "4.2.1",
"redux-actions": "2.6.5", "redux-actions": "2.6.5",
"redux-batched-actions": "0.5.0", "redux-batched-actions": "0.5.0",
@@ -84,13 +84,13 @@
"typescript": "5.7.2" "typescript": "5.7.2"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "7.26.0", "@babel/core": "7.27.1",
"@babel/eslint-parser": "7.25.9", "@babel/eslint-parser": "7.27.1",
"@babel/plugin-proposal-export-default-from": "7.25.9", "@babel/plugin-proposal-export-default-from": "7.27.1",
"@babel/plugin-syntax-dynamic-import": "7.8.3", "@babel/plugin-syntax-dynamic-import": "7.8.3",
"@babel/preset-env": "7.26.0", "@babel/preset-env": "7.27.2",
"@babel/preset-react": "7.26.3", "@babel/preset-react": "7.27.1",
"@babel/preset-typescript": "7.26.0", "@babel/preset-typescript": "7.27.1",
"@types/lodash": "4.14.195", "@types/lodash": "4.14.195",
"@types/react-document-title": "2.0.10", "@types/react-document-title": "2.0.10",
"@types/react-router-dom": "5.3.3", "@types/react-router-dom": "5.3.3",
@@ -104,7 +104,7 @@
"babel-loader": "9.2.1", "babel-loader": "9.2.1",
"babel-plugin-inline-classnames": "2.0.1", "babel-plugin-inline-classnames": "2.0.1",
"babel-plugin-transform-react-remove-prop-types": "0.4.24", "babel-plugin-transform-react-remove-prop-types": "0.4.24",
"core-js": "3.39.0", "core-js": "3.42.0",
"css-loader": "6.7.3", "css-loader": "6.7.3",
"css-modules-typescript-loader": "4.0.1", "css-modules-typescript-loader": "4.0.1",
"eslint": "8.57.1", "eslint": "8.57.1",
+3 -10
View File
@@ -99,13 +99,6 @@
<RootNamespace Condition="'$(ProwlarrProject)'=='true'">$(MSBuildProjectName.Replace('Prowlarr','NzbDrone'))</RootNamespace> <RootNamespace Condition="'$(ProwlarrProject)'=='true'">$(MSBuildProjectName.Replace('Prowlarr','NzbDrone'))</RootNamespace>
</PropertyGroup> </PropertyGroup>
<ItemGroup Condition="'$(TestProject)'!='true'">
<!-- Annotates .NET assemblies with repository information including SHA -->
<!-- Sentry uses this to link directly to GitHub at the exact version/file/line -->
<!-- This is built-in on .NET 8 and can be removed once the project is updated -->
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
</ItemGroup>
<!-- Sentry specific configuration: Only in Release mode --> <!-- Sentry specific configuration: Only in Release mode -->
<PropertyGroup Condition="'$(Configuration)' == 'Release'"> <PropertyGroup Condition="'$(Configuration)' == 'Release'">
<!-- https://docs.sentry.io/platforms/dotnet/configuration/msbuild/ --> <!-- https://docs.sentry.io/platforms/dotnet/configuration/msbuild/ -->
@@ -136,7 +129,7 @@
<PackageReference Include="NunitXml.TestLogger" Version="3.0.131" /> <PackageReference Include="NunitXml.TestLogger" Version="3.0.131" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(TestProject)'=='true' and '$(TargetFramework)'=='net6.0'"> <ItemGroup Condition="'$(TestProject)'=='true' and '$(TargetFramework)'=='net8.0'">
<PackageReference Include="coverlet.collector" Version="3.0.4-preview.27.ge7cb7c3b40" /> <PackageReference Include="coverlet.collector" Version="3.0.4-preview.27.ge7cb7c3b40" />
</ItemGroup> </ItemGroup>
@@ -148,9 +141,9 @@
<!-- Set up stylecop --> <!-- Set up stylecop -->
<ItemGroup Condition="'$(ProwlarrProject)'=='true' and '$(EnableAnalyzers)'!='false'"> <ItemGroup Condition="'$(ProwlarrProject)'=='true' and '$(EnableAnalyzers)'!='false'">
<!-- StyleCop analysis --> <!-- StyleCop analysis -->
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118"> <PackageReference Include="StyleCop.Analyzers.Unstable" Version="1.2.0.556">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<AdditionalFiles Include="$(SolutionDir)stylecop.json" /> <AdditionalFiles Include="$(SolutionDir)stylecop.json" />
</ItemGroup> </ItemGroup>
@@ -39,15 +39,16 @@ namespace NzbDrone.Automation.Test
var service = ChromeDriverService.CreateDefaultService(); var service = ChromeDriverService.CreateDefaultService();
// Timeout as windows automation tests seem to take alot longer to get going // Timeout as windows automation tests seem to take alot longer to get going
driver = new ChromeDriver(service, options, new TimeSpan(0, 3, 0)); driver = new ChromeDriver(service, options, TimeSpan.FromMinutes(3));
driver.Manage().Window.Size = new System.Drawing.Size(1920, 1080); driver.Manage().Window.Size = new System.Drawing.Size(1920, 1080);
driver.Manage().Window.FullScreen();
_runner = new NzbDroneRunner(LogManager.GetCurrentClassLogger(), null); _runner = new NzbDroneRunner(LogManager.GetCurrentClassLogger(), null);
_runner.KillAll(); _runner.KillAll();
_runner.Start(true); _runner.Start(true);
driver.Url = "http://localhost:9696"; driver.Navigate().GoToUrl("http://localhost:9696");
var page = new PageBase(driver); var page = new PageBase(driver);
page.WaitForNoSpinner(); page.WaitForNoSpinner();
@@ -67,7 +68,7 @@ namespace NzbDrone.Automation.Test
{ {
try try
{ {
var image = ((ITakesScreenshot)driver).GetScreenshot(); var image = (driver as ITakesScreenshot).GetScreenshot();
image.SaveAsFile($"./{name}_test_screenshot.png", ScreenshotImageFormat.Png); image.SaveAsFile($"./{name}_test_screenshot.png", ScreenshotImageFormat.Png);
} }
catch (Exception ex) catch (Exception ex)
@@ -7,12 +7,11 @@ namespace NzbDrone.Automation.Test.PageModel
{ {
public class PageBase public class PageBase
{ {
private readonly WebDriver _driver; private readonly IWebDriver _driver;
public PageBase(WebDriver driver) public PageBase(IWebDriver driver)
{ {
_driver = driver; _driver = driver;
driver.Manage().Window.Maximize();
} }
public IWebElement FindByClass(string className, int timeout = 5) public IWebElement FindByClass(string className, int timeout = 5)
@@ -1,10 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net6.0</TargetFrameworks> <TargetFrameworks>net8.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Selenium.Support" Version="4.1.0" /> <PackageReference Include="Selenium.Support" Version="4.1.0" />
<PackageReference Include="Selenium.WebDriver.ChromeDriver" Version="99.0.4844.5100" /> <PackageReference Include="Selenium.WebDriver.ChromeDriver" Version="134.0.6998.16500" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\NzbDrone.Test.Common\Prowlarr.Test.Common.csproj" /> <ProjectReference Include="..\NzbDrone.Test.Common\Prowlarr.Test.Common.csproj" />
@@ -10,13 +10,13 @@ namespace NzbDrone.Common.Test.EnvironmentInfo
[Test] [Test]
public void should_return_version() public void should_return_version()
{ {
BuildInfo.Version.Major.Should().BeOneOf(0, 1, 10); BuildInfo.Version.Major.Should().BeOneOf(0, 2, 10);
} }
[Test] [Test]
public void should_get_branch() public void should_get_branch()
{ {
BuildInfo.Branch.Should().NotBe("unknow"); BuildInfo.Branch.Should().NotBe("unknown");
BuildInfo.Branch.Should().NotBeNullOrWhiteSpace(); BuildInfo.Branch.Should().NotBeNullOrWhiteSpace();
} }
} }
@@ -35,7 +35,7 @@ namespace NzbDrone.Common.Test.Http
private string _httpBinHost; private string _httpBinHost;
private string _httpBinHost2; private string _httpBinHost2;
private System.Net.Http.HttpClient _httpClient = new (); private System.Net.Http.HttpClient _httpClient = new();
[OneTimeSetUp] [OneTimeSetUp]
public void FixtureSetUp() public void FixtureSetUp()
@@ -16,6 +16,8 @@ namespace NzbDrone.Common.Test.Http
[TestCase("Readarr/1.0.0.2300 (ubuntu 20.04)", "Readarr")] [TestCase("Readarr/1.0.0.2300 (ubuntu 20.04)", "Readarr")]
[TestCase("Sonarr/3.0.6.9999 (ubuntu 20.04)", "Sonarr")] [TestCase("Sonarr/3.0.6.9999 (ubuntu 20.04)", "Sonarr")]
[TestCase("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36", "Other")] [TestCase("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36", "Other")]
[TestCase("appbrr", "appbrr")]
[TestCase(" appbrr ", "appbrr")]
public void should_parse_user_agent(string userAgent, string parsedAgent) public void should_parse_user_agent(string userAgent, string parsedAgent)
{ {
UserAgentParser.ParseSource(userAgent).Should().Be(parsedAgent); UserAgentParser.ParseSource(userAgent).Should().Be(parsedAgent);
@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net6.0</TargetFrameworks> <TargetFrameworks>net8.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\NzbDrone.Host\Prowlarr.Host.csproj" /> <ProjectReference Include="..\NzbDrone.Host\Prowlarr.Host.csproj" />
@@ -1,6 +1,5 @@
using System; using System;
using System.IO; using System.IO;
using System.Runtime.Serialization;
namespace NzbDrone.Common.Disk namespace NzbDrone.Common.Disk
{ {
@@ -24,10 +23,5 @@ namespace NzbDrone.Common.Disk
: base(message, innerException) : base(message, innerException)
{ {
} }
protected DestinationAlreadyExistsException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
} }
} }
+1 -1
View File
@@ -295,7 +295,7 @@ namespace NzbDrone.Common.Disk
return _path.Split(new char[] { '\\', '/' }, StringSplitOptions.RemoveEmptyEntries); return _path.Split(new char[] { '\\', '/' }, StringSplitOptions.RemoveEmptyEntries);
} }
public static OsPath Null => new (null); public static OsPath Null => new(null);
public override string ToString() public override string ToString()
{ {
@@ -75,6 +75,17 @@ namespace NzbDrone.Common.EnvironmentInfo
{ {
try try
{ {
if (OsInfo.IsOsx)
{
var userAppDataFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile, Environment.SpecialFolderOption.DoNotVerify), ".config", "Prowlarr");
if (_diskProvider.FolderExists(userAppDataFolder) && !_diskProvider.FileExists(_appFolderInfo.GetConfigPath()))
{
_diskTransferService.MirrorFolder(userAppDataFolder, _appFolderInfo.AppDataFolder);
_diskProvider.DeleteFolder(userAppDataFolder, true);
}
}
var oldDbFile = Path.Combine(_appFolderInfo.AppDataFolder, "nzbdrone.db"); var oldDbFile = Path.Combine(_appFolderInfo.AppDataFolder, "nzbdrone.db");
if (_startupContext.Args.ContainsKey(StartupContext.APPDATA)) if (_startupContext.Args.ContainsKey(StartupContext.APPDATA))
@@ -115,7 +126,7 @@ namespace NzbDrone.Common.EnvironmentInfo
catch (Exception ex) catch (Exception ex)
{ {
_logger.Debug(ex, ex.Message); _logger.Debug(ex, ex.Message);
throw new ProwlarrStartupException("Unable to migrate DB from nzbdrone.db to {0}. Migrate manually", _appFolderInfo.GetDatabase()); throw new ProwlarrStartupException(ex, "Unable to migrate DB from nzbdrone.db to {0}. Migrate manually", _appFolderInfo.GetDatabase());
} }
} }
@@ -15,7 +15,7 @@ namespace NzbDrone.Common.EnvironmentInfo
var attributes = assembly.GetCustomAttributes(true); var attributes = assembly.GetCustomAttributes(true);
Branch = "unknow"; Branch = "unknown";
var config = attributes.OfType<AssemblyConfigurationAttribute>().FirstOrDefault(); var config = attributes.OfType<AssemblyConfigurationAttribute>().FirstOrDefault();
if (config != null) if (config != null)
@@ -31,7 +31,7 @@ namespace NzbDrone.Common.Extensions
} }
public static IDictionary<TNewKey, TNewValue> SelectDictionary<TKey, TValue, TNewKey, TNewValue>(this IDictionary<TKey, TValue> dictionary, public static IDictionary<TNewKey, TNewValue> SelectDictionary<TKey, TValue, TNewKey, TNewValue>(this IDictionary<TKey, TValue> dictionary,
Func<KeyValuePair<TKey, TValue>, ValueTuple<TNewKey, TNewValue>> selection) Func<KeyValuePair<TKey, TValue>, (TNewKey Item1, TNewValue Item2)> selection)
{ {
return dictionary.Select(selection).ToDictionary(t => t.Item1, t => t.Item2); return dictionary.Select(selection).ToDictionary(t => t.Item1, t => t.Item2);
} }
+1 -1
View File
@@ -9,7 +9,7 @@ namespace NzbDrone.Common.Http
{ {
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie
// NOTE: we are not checking non-ascii characters and we should // NOTE: we are not checking non-ascii characters and we should
private static readonly Regex CookieRegex = new (@"([^\(\)<>@,;:\\""/\[\]\?=\{\}\s]+)=([^,;\\""\s]+)"); private static readonly Regex CookieRegex = new(@"([^\(\)<>@,;:\\""/\[\]\?=\{\}\s]+)=([^,;\\""\s]+)");
private static readonly string[] FilterProps = { "COMMENT", "COMMENTURL", "DISCORD", "DOMAIN", "EXPIRES", "MAX-AGE", "PATH", "PORT", "SECURE", "VERSION", "HTTPONLY", "SAMESITE" }; private static readonly string[] FilterProps = { "COMMENT", "COMMENTURL", "DISCORD", "DOMAIN", "EXPIRES", "MAX-AGE", "PATH", "PORT", "SECURE", "VERSION", "HTTPONLY", "SAMESITE" };
private static readonly char[] InvalidKeyChars = { '(', ')', '<', '>', '@', ',', ';', ':', '\\', '"', '/', '[', ']', '?', '=', '{', '}', ' ', '\t', '\n' }; private static readonly char[] InvalidKeyChars = { '(', ')', '<', '>', '@', ',', ';', ':', '\\', '"', '/', '[', ']', '?', '=', '{', '}', ' ', '\t', '\n' };
private static readonly char[] InvalidValueChars = { '"', ',', ';', '\\', ' ', '\t', '\n' }; private static readonly char[] InvalidValueChars = { '"', ',', ';', '\\', ' ', '\t', '\n' };
@@ -167,7 +167,7 @@ namespace NzbDrone.Common.Http.Dispatchers
} }
catch (OperationCanceledException ex) when (cts.IsCancellationRequested) catch (OperationCanceledException ex) when (cts.IsCancellationRequested)
{ {
throw new WebException("Http request timed out", ex.InnerException, WebExceptionStatus.Timeout, null); throw new WebException("Http request timed out", ex, WebExceptionStatus.Timeout, null);
} }
} }
+1 -1
View File
@@ -97,7 +97,7 @@ namespace NzbDrone.Common.Http
// Save to add to final response // Save to add to final response
var responseCookies = response.Cookies; var responseCookies = response.Cookies;
// Update cookiecontainer for next request with any cookies recieved on last request // Update cookie container for next request with any cookies received on last request
var responseContainer = HandleRedirectCookies(request, response); var responseContainer = HandleRedirectCookies(request, response);
response = await ExecuteRequestAsync(request, responseContainer); response = await ExecuteRequestAsync(request, responseContainer);
+1 -1
View File
@@ -9,7 +9,7 @@ namespace NzbDrone.Common.Http
{ {
public class HttpResponse public class HttpResponse
{ {
private static readonly Regex RegexRefresh = new ("^(.*?url)=(.*?)(?:;|$)", RegexOptions.Compiled); private static readonly Regex RegexRefresh = new("^(.*?url)=(.*?)(?:;|$)", RegexOptions.Compiled);
public HttpResponse(HttpRequest request, HttpHeader headers, CookieCollection cookies, byte[] binaryData, long elapsedTime = 0, HttpStatusCode statusCode = HttpStatusCode.OK, Version version = null) public HttpResponse(HttpRequest request, HttpHeader headers, CookieCollection cookies, byte[] binaryData, long elapsedTime = 0, HttpStatusCode statusCode = HttpStatusCode.OK, Version version = null)
{ {
+5 -9
View File
@@ -1,15 +1,16 @@
using System;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
namespace NzbDrone.Common.Http namespace NzbDrone.Common.Http
{ {
public static class UserAgentParser public static class UserAgentParser
{ {
private static readonly Regex AppSourceRegex = new Regex(@"(?<agent>[a-z0-9]*)\/.*(?:\(.*\))?", private static readonly Regex AppSourceRegex = new(@"^(?<agent>[a-z0-9]+)(?:\/.+(?:\(.*\))?|$)",
RegexOptions.IgnoreCase | RegexOptions.Compiled); RegexOptions.IgnoreCase | RegexOptions.Compiled);
public static string SimplifyUserAgent(string userAgent) public static string SimplifyUserAgent(string userAgent)
{ {
if (userAgent == null || userAgent.StartsWith("Mozilla/5.0")) if (userAgent == null || userAgent.StartsWith("Mozilla/5.0", StringComparison.Ordinal))
{ {
return null; return null;
} }
@@ -19,14 +20,9 @@ namespace NzbDrone.Common.Http
public static string ParseSource(string userAgent) public static string ParseSource(string userAgent)
{ {
var match = AppSourceRegex.Match(SimplifyUserAgent(userAgent) ?? string.Empty); var match = AppSourceRegex.Match(SimplifyUserAgent(userAgent?.Trim()) ?? string.Empty);
if (match.Groups["agent"].Success) return match.Groups["agent"].Success ? match.Groups["agent"].Value : "Other";
{
return match.Groups["agent"].Value;
}
return "Other";
} }
} }
} }
@@ -10,64 +10,64 @@ namespace NzbDrone.Common.Instrumentation
private static readonly Regex[] CleansingRules = private static readonly Regex[] CleansingRules =
{ {
// Url // Url
new (@"(?<=[?&: ;])(apikey|api_key|(?:(?:access|api)[-_]?)?token|pass(?:key|wd)?|auth|authkey|rsskey|user|u?id|api|[a-z_]*apikey|account|pid|pwd)=(?<secret>[^&=""]+?)(?=[ ""&=]|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new(@"(?<=[?&: ;])(apikey|api_key|(?:(?:access|api)[-_]?)?token|pass(?:key|wd)?|auth|authkey|rsskey|user|u?id|api|[a-z_]*apikey|account|pid|pwd)=(?<secret>[^&=""]+?)(?=[ ""&=]|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new (@"(?<=[?& ;])[^=]*?(_?(?<!use|get_)token|username|passwo?rd)=(?<secret>[^&=]+?)(?= |&|$|;)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new(@"(?<=[?& ;])[^=]*?(_?(?<!use|get_)token|username|passwo?rd)=(?<secret>[^&=]+?)(?= |&|$|;)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new (@"rss(24h)?\.torrentleech\.org/(?!rss)(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new(@"rss(24h)?\.torrentleech\.org/(?!rss)(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new (@"torrentleech\.org/rss/download/[0-9]+/(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new(@"torrentleech\.org/rss/download/[0-9]+/(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new (@"iptorrents\.com/[/a-z0-9?&;]*?(?:[?&;](u|tp)=(?<secret>[^&=;]+?))+(?= |;|&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new(@"iptorrents\.com/[/a-z0-9?&;]*?(?:[?&;](u|tp)=(?<secret>[^&=;]+?))+(?= |;|&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new (@"/fetch/[a-z0-9]{32}/(?<secret>[a-z0-9]{32})", RegexOptions.Compiled), new(@"/fetch/[a-z0-9]{32}/(?<secret>[a-z0-9]{32})", RegexOptions.Compiled),
new (@"getnzb.*?(?<=\?|&)(r)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new(@"getnzb.*?(?<=\?|&)(r)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new (@"\b(\w*)?(_?(?<!use|get_)token|username|passwo?rd)=(?<secret>[^&=]+?)(?= |&|$|;)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new(@"\b(\w*)?(_?(?<!use|get_)token|username|passwo?rd)=(?<secret>[^&=]+?)(?= |&|$|;)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new (@"(?<=authkey = "")(?<secret>[^&=]+?)(?="")", RegexOptions.Compiled | RegexOptions.IgnoreCase), new(@"(?<=authkey = "")(?<secret>[^&=]+?)(?="")", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new (@"(?<=beyond-hd\.[a-z]+/api/torrents/)(?<secret>[^&=][a-z0-9]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new(@"(?<=beyond-hd\.[a-z]+/api/torrents/)(?<secret>[^&=][a-z0-9]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new (@"(?<=beyond-hd\.[a-z]+/torrent/download/[\w\d-]+[.]\d+[.])(?<secret>[a-z0-9]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new(@"(?<=beyond-hd\.[a-z]+/torrent/download/[\w\d-]+[.]\d+[.])(?<secret>[a-z0-9]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new (@"(?:sharewood)\.[a-z]{2,3}/api/(?<secret>[a-z0-9]{16,})/", RegexOptions.Compiled | RegexOptions.IgnoreCase), new(@"(?:sharewood)\.[a-z]{2,3}/api/(?<secret>[a-z0-9]{16,})/", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// UNIT3D // UNIT3D
new (@"(?<=[a-z0-9-]+\.[a-z]+/torrent/download/\d+\.)(?<secret>[^&=][a-z0-9]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new(@"(?<=[a-z0-9-]+\.[a-z]+/torrent/download/\d+\.)(?<secret>[^&=][a-z0-9]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// Path // Path
new (@"""C:\\Users\\(?<secret>[^\""]+?)(\\|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new(@"""C:\\Users\\(?<secret>[^\""]+?)(\\|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new (@"""/(home|Users)/(?<secret>[^/""]+?)(/|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new(@"""/(home|Users)/(?<secret>[^/""]+?)(/|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// Trackers Announce Keys; Designed for Qbit Json; should work for all in theory // Trackers Announce Keys; Designed for Qbit Json; should work for all in theory
new (@"announce(\.php)?(/|%2f|%3fpasskey%3d)(?<secret>[a-z0-9]{16,})|(?<secret>[a-z0-9]{16,})(/|%2f)announce", RegexOptions.Compiled | RegexOptions.IgnoreCase), new(@"announce(\.php)?(/|%2f|%3fpasskey%3d)(?<secret>[a-z0-9]{16,})|(?<secret>[a-z0-9]{16,})(/|%2f)announce", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// NzbGet // NzbGet
new (@"""Name""\s*:\s*""[^""]*(username|password)""\s*,\s*""Value""\s*:\s*""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase), new(@"""Name""\s*:\s*""[^""]*(username|password)""\s*,\s*""Value""\s*:\s*""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// Sabnzbd // Sabnzbd
new (@"""[^""]*(username|password|api_?key|nzb_key)""\s*:\s*""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase), new(@"""[^""]*(username|password|api_?key|nzb_key)""\s*:\s*""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new (@"""email_(account|to|from|pwd)""\s*:\s*""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase), new(@"""email_(account|to|from|pwd)""\s*:\s*""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// uTorrent // uTorrent
new (@"\[""[a-z._]*(username|password)"",\d,""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase), new(@"\[""[a-z._]*(username|password)"",\d,""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new (@"\[""(boss_key|boss_key_salt|proxy\.proxy)"",\d,""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase), new(@"\[""(boss_key|boss_key_salt|proxy\.proxy)"",\d,""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// Deluge // Deluge
new (@"auth.login\(""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase), new(@"auth.login\(""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// BroadcastheNet (;torrent_pass|torrents_notify_ is for MTV) // BroadcastheNet (;torrent_pass|torrents_notify_ is for MTV)
new (@"""?method""?\s*:\s*""(getTorrents)"",\s*""?params""?\s*:\s*\[\s*""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase), new(@"""?method""?\s*:\s*""(getTorrents)"",\s*""?params""?\s*:\s*\[\s*""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new (@"getTorrents\(""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase), new(@"getTorrents\(""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new (@"(?<=\?|&|;|=)(authkey|torrent_pass|torrents_notify)[_=](?<secret>[^&=]+?)(?=""|&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new(@"(?<=\?|&|;|=)(authkey|torrent_pass|torrents_notify)[_=](?<secret>[^&=]+?)(?=""|&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// Plex // Plex
new (@"(?<=\?|&)(X-Plex-Client-Identifier|X-Plex-Token)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new(@"(?<=\?|&)(X-Plex-Client-Identifier|X-Plex-Token)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// Indexer Responses // Indexer Responses
new (@"(?:avistaz|exoticaz|cinemaz|privatehd)\.[a-z]{2,3}/rss/download/(?<secret>[^&=]+?)/(?<secret>[^&=]+?)\.torrent", RegexOptions.Compiled | RegexOptions.IgnoreCase), new(@"(?:avistaz|exoticaz|cinemaz|privatehd)\.[a-z]{2,3}/rss/download/(?<secret>[^&=]+?)/(?<secret>[^&=]+?)\.torrent", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new (@"(?:animebytes)\.[a-z]{2,3}/torrent/[0-9]+/download/(?<secret>[^&=]+?)[""]", RegexOptions.Compiled | RegexOptions.IgnoreCase), new(@"(?:animebytes)\.[a-z]{2,3}/torrent/[0-9]+/download/(?<secret>[^&=]+?)[""]", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new (@"""(info_hash|token|((pass|rss)[- _]?key))"":""(?<secret>[^&=]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase), new(@"""(info_hash|token|((pass|rss)[- _]?key))"":""(?<secret>[^&=]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// Applications // Applications
new (@"""name"":""apikey"",""value"":""(?<secret>[^&=]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase), new(@"""name"":""apikey"",""value"":""(?<secret>[^&=]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// Discord // Discord
new (@"discord.com/api/webhooks/((?<secret>[\w-]+)/)?(?<secret>[\w-]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase) new(@"discord.com/api/webhooks/((?<secret>[\w-]+)/)?(?<secret>[\w-]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase)
}; };
private static readonly Regex CleanseRemoteIPRegex = new (@"(?:Auth-\w+(?<!Failure|Unauthorized) ip|from) (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})", RegexOptions.Compiled); private static readonly Regex CleanseRemoteIPRegex = new(@"(?:Auth-\w+(?<!Failure|Unauthorized) ip|from) (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})", RegexOptions.Compiled);
public static string Cleanse(string message) public static string Cleanse(string message)
{ {
@@ -4,27 +4,27 @@ namespace NzbDrone.Common.Instrumentation.Extensions
{ {
public static class LoggerExtensions public static class LoggerExtensions
{ {
[MessageTemplateFormatMethod("message")]
public static void ProgressInfo(this Logger logger, string message, params object[] args) public static void ProgressInfo(this Logger logger, string message, params object[] args)
{ {
var formattedMessage = string.Format(message, args); LogProgressMessage(logger, LogLevel.Info, message, args);
LogProgressMessage(logger, LogLevel.Info, formattedMessage);
} }
[MessageTemplateFormatMethod("message")]
public static void ProgressDebug(this Logger logger, string message, params object[] args) public static void ProgressDebug(this Logger logger, string message, params object[] args)
{ {
var formattedMessage = string.Format(message, args); LogProgressMessage(logger, LogLevel.Debug, message, args);
LogProgressMessage(logger, LogLevel.Debug, formattedMessage);
} }
[MessageTemplateFormatMethod("message")]
public static void ProgressTrace(this Logger logger, string message, params object[] args) public static void ProgressTrace(this Logger logger, string message, params object[] args)
{ {
var formattedMessage = string.Format(message, args); LogProgressMessage(logger, LogLevel.Trace, message, args);
LogProgressMessage(logger, LogLevel.Trace, formattedMessage);
} }
private static void LogProgressMessage(Logger logger, LogLevel level, string message) private static void LogProgressMessage(Logger logger, LogLevel level, string message, object[] parameters)
{ {
var logEvent = new LogEventInfo(level, logger.Name, message); var logEvent = new LogEventInfo(level, logger.Name, null, message, parameters);
logEvent.Properties.Add("Status", ""); logEvent.Properties.Add("Status", "");
logger.Log(logEvent); logger.Log(logEvent);
@@ -15,8 +15,8 @@ namespace NzbDrone.Common.Instrumentation
private const string FileLogLayout = @"${date:format=yyyy-MM-dd HH\:mm\:ss.f}|${level}|${logger}|${message}${onexception:inner=${newline}${newline}[v${assembly-version}] ${exception:format=ToString}${newline}${exception:format=Data}${newline}}"; private const string FileLogLayout = @"${date:format=yyyy-MM-dd HH\:mm\:ss.f}|${level}|${logger}|${message}${onexception:inner=${newline}${newline}[v${assembly-version}] ${exception:format=ToString}${newline}${exception:format=Data}${newline}}";
private const string ConsoleFormat = "[${level}] ${logger}: ${message} ${onexception:inner=${newline}${newline}[v${assembly-version}] ${exception:format=ToString}${newline}${exception:format=Data}${newline}}"; private const string ConsoleFormat = "[${level}] ${logger}: ${message} ${onexception:inner=${newline}${newline}[v${assembly-version}] ${exception:format=ToString}${newline}${exception:format=Data}${newline}}";
private static readonly CleansingConsoleLogLayout CleansingConsoleLayout = new (ConsoleFormat); private static readonly CleansingConsoleLogLayout CleansingConsoleLayout = new(ConsoleFormat);
private static readonly CleansingClefLogLayout ClefLogLayout = new (); private static readonly CleansingClefLogLayout ClefLogLayout = new();
private static bool _isConfigured; private static bool _isConfigured;
@@ -6,6 +6,7 @@ using System.ComponentModel;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text;
using NLog; using NLog;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Model; using NzbDrone.Common.Model;
@@ -117,7 +118,9 @@ namespace NzbDrone.Common.Processes
UseShellExecute = false, UseShellExecute = false,
RedirectStandardError = true, RedirectStandardError = true,
RedirectStandardOutput = true, RedirectStandardOutput = true,
RedirectStandardInput = true RedirectStandardInput = true,
StandardOutputEncoding = Encoding.UTF8,
StandardErrorEncoding = Encoding.UTF8
}; };
if (environmentVariables != null) if (environmentVariables != null)
+12 -12
View File
@@ -1,28 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net6.0</TargetFrameworks> <TargetFrameworks>net8.0</TargetFrameworks>
<DefineConstants Condition="'$(RuntimeIdentifier)' == 'linux-musl-x64' or '$(RuntimeIdentifier)' == 'linux-musl-arm64'">ISMUSL</DefineConstants> <DefineConstants Condition="'$(RuntimeIdentifier)' == 'linux-musl-x64' or '$(RuntimeIdentifier)' == 'linux-musl-arm64'">ISMUSL</DefineConstants>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="DryIoc.dll" Version="5.4.3" /> <PackageReference Include="DryIoc.dll" Version="5.4.3" />
<PackageReference Include="IPAddressRange" Version="6.1.0" /> <PackageReference Include="IPAddressRange" Version="6.2.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.1" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.2" /> <PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="8.0.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="NLog" Version="5.3.4" /> <PackageReference Include="NLog" Version="5.4.0" />
<PackageReference Include="NLog.Layouts.ClefJsonLayout" Version="1.0.0" /> <PackageReference Include="NLog.Layouts.ClefJsonLayout" Version="1.0.3" />
<PackageReference Include="NLog.Extensions.Logging" Version="5.3.15" /> <PackageReference Include="NLog.Extensions.Logging" Version="5.4.0" />
<PackageReference Include="Npgsql" Version="7.0.9" /> <PackageReference Include="Npgsql" Version="9.0.3" />
<PackageReference Include="Sentry" Version="4.0.2" /> <PackageReference Include="Sentry" Version="4.0.2" />
<PackageReference Include="NLog.Targets.Syslog" Version="7.0.0" /> <PackageReference Include="NLog.Targets.Syslog" Version="7.0.0" />
<PackageReference Include="SharpZipLib" Version="1.4.2" /> <PackageReference Include="SharpZipLib" Version="1.4.2" />
<PackageReference Include="System.Text.Json" Version="6.0.10" /> <PackageReference Include="System.Text.Json" Version="8.0.5" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" /> <PackageReference Include="System.ValueTuple" Version="4.6.1" />
<PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.115.5-18" /> <PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.115.5-18" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="6.0.1" /> <PackageReference Include="System.Configuration.ConfigurationManager" Version="8.0.1" />
<PackageReference Include="System.IO.FileSystem.AccessControl" Version="5.0.0" /> <PackageReference Include="System.IO.FileSystem.AccessControl" Version="5.0.0" />
<PackageReference Include="System.Runtime.Loader" Version="4.3.0" /> <PackageReference Include="System.Runtime.Loader" Version="4.3.0" />
<PackageReference Include="System.ServiceProcess.ServiceController" Version="6.0.1" /> <PackageReference Include="System.ServiceProcess.ServiceController" Version="8.0.1" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Update="EnsureThat\Resources\ExceptionMessages.Designer.cs"> <Compile Update="EnsureThat\Resources\ExceptionMessages.Designer.cs">
@@ -94,7 +94,8 @@ namespace NzbDrone.Common.TPL
{ {
_currentThreadIsProcessingItems = false; _currentThreadIsProcessingItems = false;
} }
}, null); },
null);
} }
/// <summary>Attempts to execute the specified task on the current thread.</summary> /// <summary>Attempts to execute the specified task on the current thread.</summary>
+2 -1
View File
@@ -20,7 +20,8 @@ namespace NzbDrone.Common.TPL
Logger.Error(exception, "Task Error"); Logger.Error(exception, "Task Error");
} }
} }
}, TaskContinuationOptions.OnlyOnFaulted); },
TaskContinuationOptions.OnlyOnFaulted);
return task; return task;
} }
+1 -1
View File
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFrameworks>net6.0</TargetFrameworks> <TargetFrameworks>net8.0</TargetFrameworks>
<ApplicationIcon>..\NzbDrone.Host\Prowlarr.ico</ApplicationIcon> <ApplicationIcon>..\NzbDrone.Host\Prowlarr.ico</ApplicationIcon>
</PropertyGroup> </PropertyGroup>
File diff suppressed because one or more lines are too long
@@ -1,15 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<caps> <caps>
<server version="1.0" title="Anime Tosho" strapline="Anime NZB/DDL mirror" url="https://animetosho.org/"/> <server version="1.0" title="Anime Tosho" strapline="Anime NZB/DDL mirror" url="https://animetosho.org/" />
<limits max="200" default="75"/> <limits max="200" default="75" />
<retention days="9999"/> <retention days="9999" />
<registration available="no" open="yes" /> <registration available="no" open="yes" />
<searching> <searching>
<search available="yes" supportedParams="q" /> <search available="yes" supportedParams="q" />
<tv-search available="no" supportedParams="q" /> <tv-search available="no" supportedParams="q" />
<movie-search available="no" supportedParams="q" /> <movie-search available="no" supportedParams="q" />
</searching> </searching>
<categories> <categories>
<category id="5070" name="Anime" description="Anime"/> <category id="5070" name="Anime" description="Anime" />
</categories> <category id="2020" name="Movies/Other" description="Movies (Anime)" />
</caps> </categories>
</caps>
@@ -51,7 +51,7 @@ namespace NzbDrone.Core.Test.IndexerTests.AvistazTests
torrentInfo.InfoUrl.Should().Be("https://avistaz.to/torrent/187240-japan-sinks-people-of-hope-2021-s01e05-720p-nf-web-dl-ddp20-x264-seikel"); torrentInfo.InfoUrl.Should().Be("https://avistaz.to/torrent/187240-japan-sinks-people-of-hope-2021-s01e05-720p-nf-web-dl-ddp20-x264-seikel");
torrentInfo.CommentUrl.Should().BeNullOrEmpty(); torrentInfo.CommentUrl.Should().BeNullOrEmpty();
torrentInfo.Indexer.Should().Be(Subject.Definition.Name); torrentInfo.Indexer.Should().Be(Subject.Definition.Name);
torrentInfo.PublishDate.Should().Be(DateTime.Parse("2021-11-14 22:26:21")); torrentInfo.PublishDate.Should().Be(DateTime.Parse("2021-11-14 21:26:21"));
torrentInfo.Size.Should().Be(935127615); torrentInfo.Size.Should().Be(935127615);
torrentInfo.InfoHash.Should().Be("a879261d4e6e792402f92401141a21de70d51bf2"); torrentInfo.InfoHash.Should().Be("a879261d4e6e792402f92401141a21de70d51bf2");
torrentInfo.MagnetUrl.Should().Be(null); torrentInfo.MagnetUrl.Should().Be(null);
@@ -51,7 +51,7 @@ namespace NzbDrone.Core.Test.IndexerTests.AvistazTests
torrentInfo.InfoUrl.Should().Be("https://exoticaz.to/torrent/64040-ssis-419-my-first-experience-is-yua-mikami-from-the-day-i-lost-my-virginity-i-was-devoted-to-sex"); torrentInfo.InfoUrl.Should().Be("https://exoticaz.to/torrent/64040-ssis-419-my-first-experience-is-yua-mikami-from-the-day-i-lost-my-virginity-i-was-devoted-to-sex");
torrentInfo.CommentUrl.Should().BeNullOrEmpty(); torrentInfo.CommentUrl.Should().BeNullOrEmpty();
torrentInfo.Indexer.Should().Be(Subject.Definition.Name); torrentInfo.Indexer.Should().Be(Subject.Definition.Name);
torrentInfo.PublishDate.Should().Be(DateTime.Parse("2022-06-11 10:04:50")); torrentInfo.PublishDate.Should().Be(DateTime.Parse("2022-06-11 09:04:50"));
torrentInfo.Size.Should().Be(7085405541); torrentInfo.Size.Should().Be(7085405541);
torrentInfo.InfoHash.Should().Be("asdjfiasdf54asd7f4a2sdf544asdf"); torrentInfo.InfoHash.Should().Be("asdjfiasdf54asd7f4a2sdf544asdf");
torrentInfo.MagnetUrl.Should().Be(null); torrentInfo.MagnetUrl.Should().Be(null);
@@ -51,7 +51,7 @@ namespace NzbDrone.Core.Test.IndexerTests.AvistazTests
torrentInfo.InfoUrl.Should().Be("https://privatehd.to/torrent/78506-godzilla-2014-2160p-uhd-bluray-remux-hdr-hevc-atmos-triton"); torrentInfo.InfoUrl.Should().Be("https://privatehd.to/torrent/78506-godzilla-2014-2160p-uhd-bluray-remux-hdr-hevc-atmos-triton");
torrentInfo.CommentUrl.Should().BeNullOrEmpty(); torrentInfo.CommentUrl.Should().BeNullOrEmpty();
torrentInfo.Indexer.Should().Be(Subject.Definition.Name); torrentInfo.Indexer.Should().Be(Subject.Definition.Name);
torrentInfo.PublishDate.Should().Be(DateTime.Parse("2021-03-21 05:24:49")); torrentInfo.PublishDate.Should().Be(DateTime.Parse("2021-03-21 04:24:49"));
torrentInfo.Size.Should().Be(69914591044); torrentInfo.Size.Should().Be(69914591044);
torrentInfo.InfoHash.Should().Be("a879261d4e6e792402f92401141a21de70d51bf2"); torrentInfo.InfoHash.Should().Be("a879261d4e6e792402f92401141a21de70d51bf2");
torrentInfo.MagnetUrl.Should().Be(null); torrentInfo.MagnetUrl.Should().Be(null);
@@ -55,7 +55,7 @@ namespace NzbDrone.Core.Test.IndexerTests.FileListTests
torrentInfo.InfoUrl.Should().Be("https://filelist.io/details.php?id=665873"); torrentInfo.InfoUrl.Should().Be("https://filelist.io/details.php?id=665873");
torrentInfo.CommentUrl.Should().BeNullOrEmpty(); torrentInfo.CommentUrl.Should().BeNullOrEmpty();
torrentInfo.Indexer.Should().Be(Subject.Definition.Name); torrentInfo.Indexer.Should().Be(Subject.Definition.Name);
torrentInfo.PublishDate.Should().Be(DateTime.Parse("2020-01-25 20:20:19")); torrentInfo.PublishDate.Should().Be(DateTime.Parse("2020-01-25 19:20:19"));
torrentInfo.Size.Should().Be(8300512414); torrentInfo.Size.Should().Be(8300512414);
torrentInfo.InfoHash.Should().Be(null); torrentInfo.InfoHash.Should().Be(null);
torrentInfo.MagnetUrl.Should().Be(null); torrentInfo.MagnetUrl.Should().Be(null);
@@ -83,17 +83,18 @@ namespace NzbDrone.Core.Test.IndexerTests.NewznabTests
bookCats.Should().Contain("8000"); bookCats.Should().Contain("8000");
} }
[Test] [TestCase(5070)]
public void should_find_sub_categories_as_main_categories() [TestCase(2020)]
public void should_find_sub_categories_as_main_categories(int category)
{ {
GivenCapsResponse(ReadAllText("Files/Indexers/Torznab/torznab_animetosho_caps.xml")); GivenCapsResponse(ReadAllText("Files/Indexers/Torznab/torznab_animetosho_caps.xml"));
var caps = Subject.GetCapabilities(_settings, _definition); var caps = Subject.GetCapabilities(_settings, _definition);
var bookCats = caps.Categories.MapTrackerCatToNewznab("5070"); var indexerCategories = caps.Categories.MapTrackerCatToNewznab(category.ToString());
bookCats.Count.Should().Be(2); indexerCategories.Count.Should().Be(2);
bookCats.First().Id.Should().Be(5070); indexerCategories.First().Id.Should().Be(category);
} }
[Test] [Test]
@@ -50,7 +50,7 @@ namespace NzbDrone.Core.Test.IndexerTests.PTPTests
first.Guid.Should().Be("PassThePopcorn-452135"); first.Guid.Should().Be("PassThePopcorn-452135");
first.Title.Should().Be("The.Night.Of.S01.BluRay.AAC2.0.x264-DEPTH"); first.Title.Should().Be("The.Night.Of.S01.BluRay.AAC2.0.x264-DEPTH");
first.DownloadProtocol.Should().Be(DownloadProtocol.Torrent); first.DownloadProtocol.Should().Be(DownloadProtocol.Torrent);
first.DownloadUrl.Should().Be("https://passthepopcorn.me/torrents.php?action=download&id=452135&authkey=00000000000000000000000000000000&torrent_pass=00000000000000000000000000000000"); first.DownloadUrl.Should().Be("https://passthepopcorn.me/torrents.php?action=download&id=452135");
first.InfoUrl.Should().Be("https://passthepopcorn.me/torrents.php?id=148131&torrentid=452135"); first.InfoUrl.Should().Be("https://passthepopcorn.me/torrents.php?id=148131&torrentid=452135");
//first.PublishDate.Should().Be(DateTime.Parse("2017-04-17T12:13:42+0000").ToUniversalTime()); stupid timezones //first.PublishDate.Should().Be(DateTime.Parse("2017-04-17T12:13:42+0000").ToUniversalTime()); stupid timezones
@@ -1,12 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net6.0</TargetFrameworks> <TargetFrameworks>net8.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Dapper" Version="2.0.151" /> <PackageReference Include="Dapper" Version="2.1.66" />
<PackageReference Include="NBuilder" Version="6.1.0" /> <PackageReference Include="NBuilder" Version="6.1.0" />
<PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.115.5-18" /> <PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.115.5-18" />
<PackageReference Include="YamlDotNet" Version="13.1.1" /> <PackageReference Include="YamlDotNet" Version="16.3.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\NzbDrone.Test.Common\Prowlarr.Test.Common.csproj" /> <ProjectReference Include="..\NzbDrone.Test.Common\Prowlarr.Test.Common.csproj" />
@@ -16,7 +16,7 @@ namespace NzbDrone.Core.Applications
protected readonly IAppIndexerMapService _appIndexerMapService; protected readonly IAppIndexerMapService _appIndexerMapService;
protected readonly Logger _logger; protected readonly Logger _logger;
protected static readonly Regex AppIndexerRegex = new (@"\/(?<indexer>\d{1,3})(?:\/(?:api)?\/?)?$", RegexOptions.IgnoreCase | RegexOptions.Compiled); protected static readonly Regex AppIndexerRegex = new(@"\/(?<indexer>\d{1,3})(?:\/(?:api)?\/?)?$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
public abstract string Name { get; } public abstract string Name { get; }
@@ -19,7 +19,7 @@ namespace NzbDrone.Core.Applications.LazyLibrarian
public class LazyLibrarianSettings : IApplicationSettings public class LazyLibrarianSettings : IApplicationSettings
{ {
private static readonly LazyLibrarianSettingsValidator Validator = new (); private static readonly LazyLibrarianSettingsValidator Validator = new();
public LazyLibrarianSettings() public LazyLibrarianSettings()
{ {
@@ -121,9 +121,16 @@ namespace NzbDrone.Core.Applications.Lidarr
{ {
var indexerCapabilities = GetIndexerCapabilities(indexer); var indexerCapabilities = GetIndexerCapabilities(indexer);
if (!indexerCapabilities.MusicSearchAvailable && !indexerCapabilities.SearchAvailable)
{
_logger.Debug("Skipping add for indexer {0} [{1}] due to missing music or basic search support by the indexer", indexer.Name, indexer.Id);
return;
}
if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Empty()) if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Empty())
{ {
_logger.Trace("Skipping add for indexer {0} [{1}] due to no app Sync Categories supported by the indexer", indexer.Name, indexer.Id); _logger.Debug("Skipping add for indexer {0} [{1}] due to no app Sync Categories supported by the indexer", indexer.Name, indexer.Id);
return; return;
} }
@@ -178,7 +185,8 @@ namespace NzbDrone.Core.Applications.Lidarr
{ {
_logger.Debug("Syncing remote indexer with current settings"); _logger.Debug("Syncing remote indexer with current settings");
if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any()) if ((indexerCapabilities.MusicSearchAvailable || indexerCapabilities.SearchAvailable) &&
indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any())
{ {
// Retain user fields not-affiliated with Prowlarr // Retain user fields not-affiliated with Prowlarr
lidarrIndexer.Fields.AddRange(remoteIndexer.Fields.Where(f => lidarrIndexer.Fields.All(s => s.Name != f.Name))); lidarrIndexer.Fields.AddRange(remoteIndexer.Fields.Where(f => lidarrIndexer.Fields.All(s => s.Name != f.Name)));
@@ -204,7 +212,8 @@ namespace NzbDrone.Core.Applications.Lidarr
{ {
_appIndexerMapService.Delete(indexerMapping.Id); _appIndexerMapService.Delete(indexerMapping.Id);
if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any()) if ((indexerCapabilities.MusicSearchAvailable || indexerCapabilities.SearchAvailable) &&
indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any())
{ {
_logger.Debug("Remote indexer not found, re-adding {0} [{1}] to Lidarr", indexer.Name, indexer.Id); _logger.Debug("Remote indexer not found, re-adding {0} [{1}] to Lidarr", indexer.Name, indexer.Id);
lidarrIndexer.Id = 0; lidarrIndexer.Id = 0;
@@ -18,7 +18,7 @@ namespace NzbDrone.Core.Applications.Lidarr
public class LidarrSettings : IApplicationSettings public class LidarrSettings : IApplicationSettings
{ {
private static readonly LidarrSettingsValidator Validator = new (); private static readonly LidarrSettingsValidator Validator = new();
public LidarrSettings() public LidarrSettings()
{ {
@@ -23,7 +23,7 @@ namespace NzbDrone.Core.Applications.Lidarr
public class LidarrV1Proxy : ILidarrV1Proxy public class LidarrV1Proxy : ILidarrV1Proxy
{ {
private static Version MinimumApplicationVersion => new (1, 0, 2, 0); private static Version MinimumApplicationVersion => new(1, 0, 2, 0);
private const string AppApiRoute = "/api/v1"; private const string AppApiRoute = "/api/v1";
private const string AppIndexerApiRoute = $"{AppApiRoute}/indexer"; private const string AppIndexerApiRoute = $"{AppApiRoute}/indexer";
@@ -19,7 +19,7 @@ namespace NzbDrone.Core.Applications.Mylar
public class MylarSettings : IApplicationSettings public class MylarSettings : IApplicationSettings
{ {
private static readonly MylarSettingsValidator Validator = new (); private static readonly MylarSettingsValidator Validator = new();
public MylarSettings() public MylarSettings()
{ {
@@ -121,9 +121,16 @@ namespace NzbDrone.Core.Applications.Radarr
{ {
var indexerCapabilities = GetIndexerCapabilities(indexer); var indexerCapabilities = GetIndexerCapabilities(indexer);
if (!indexerCapabilities.MovieSearchAvailable && !indexerCapabilities.SearchAvailable)
{
_logger.Debug("Skipping add for indexer {0} [{1}] due to missing movie or basic search support by the indexer", indexer.Name, indexer.Id);
return;
}
if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Empty()) if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Empty())
{ {
_logger.Trace("Skipping add for indexer {0} [{1}] due to no app Sync Categories supported by the indexer", indexer.Name, indexer.Id); _logger.Debug("Skipping add for indexer {0} [{1}] due to no app Sync Categories supported by the indexer", indexer.Name, indexer.Id);
return; return;
} }
@@ -176,7 +183,8 @@ namespace NzbDrone.Core.Applications.Radarr
if (!radarrIndexer.Equals(remoteIndexer) || forceSync) if (!radarrIndexer.Equals(remoteIndexer) || forceSync)
{ {
if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any()) if ((indexerCapabilities.MovieSearchAvailable || indexerCapabilities.SearchAvailable) &&
indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any())
{ {
// Retain user fields not-affiliated with Prowlarr // Retain user fields not-affiliated with Prowlarr
radarrIndexer.Fields.AddRange(remoteIndexer.Fields.Where(f => radarrIndexer.Fields.All(s => s.Name != f.Name))); radarrIndexer.Fields.AddRange(remoteIndexer.Fields.Where(f => radarrIndexer.Fields.All(s => s.Name != f.Name)));
@@ -202,7 +210,8 @@ namespace NzbDrone.Core.Applications.Radarr
{ {
_appIndexerMapService.Delete(indexerMapping.Id); _appIndexerMapService.Delete(indexerMapping.Id);
if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any()) if ((indexerCapabilities.MovieSearchAvailable || indexerCapabilities.SearchAvailable) &&
indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any())
{ {
_logger.Debug("Remote indexer not found, re-adding {0} [{1}] to Radarr", indexer.Name, indexer.Id); _logger.Debug("Remote indexer not found, re-adding {0} [{1}] to Radarr", indexer.Name, indexer.Id);
radarrIndexer.Id = 0; radarrIndexer.Id = 0;
@@ -19,7 +19,7 @@ namespace NzbDrone.Core.Applications.Radarr
public class RadarrSettings : IApplicationSettings public class RadarrSettings : IApplicationSettings
{ {
private static readonly RadarrSettingsValidator Validator = new (); private static readonly RadarrSettingsValidator Validator = new();
public RadarrSettings() public RadarrSettings()
{ {
@@ -23,8 +23,8 @@ namespace NzbDrone.Core.Applications.Radarr
public class RadarrV3Proxy : IRadarrV3Proxy public class RadarrV3Proxy : IRadarrV3Proxy
{ {
private static Version MinimumApplicationV4Version => new (4, 0, 4, 0); private static Version MinimumApplicationV4Version => new(4, 0, 4, 0);
private static Version MinimumApplicationV3Version => new (3, 1, 1, 0); private static Version MinimumApplicationV3Version => new(3, 1, 1, 0);
private const string AppApiRoute = "/api/v3"; private const string AppApiRoute = "/api/v3";
private const string AppIndexerApiRoute = $"{AppApiRoute}/indexer"; private const string AppIndexerApiRoute = $"{AppApiRoute}/indexer";
@@ -121,9 +121,16 @@ namespace NzbDrone.Core.Applications.Readarr
{ {
var indexerCapabilities = GetIndexerCapabilities(indexer); var indexerCapabilities = GetIndexerCapabilities(indexer);
if (!indexerCapabilities.BookSearchAvailable && !indexerCapabilities.SearchAvailable)
{
_logger.Debug("Skipping add for indexer {0} [{1}] due to missing book or basic search support by the indexer", indexer.Name, indexer.Id);
return;
}
if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Empty()) if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Empty())
{ {
_logger.Trace("Skipping add for indexer {0} [{1}] due to no app Sync Categories supported by the indexer", indexer.Name, indexer.Id); _logger.Debug("Skipping add for indexer {0} [{1}] due to no app Sync Categories supported by the indexer", indexer.Name, indexer.Id);
return; return;
} }
@@ -178,7 +185,8 @@ namespace NzbDrone.Core.Applications.Readarr
{ {
_logger.Debug("Syncing remote indexer with current settings"); _logger.Debug("Syncing remote indexer with current settings");
if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any()) if ((indexerCapabilities.BookSearchAvailable || indexerCapabilities.SearchAvailable) &&
indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any())
{ {
// Retain user fields not-affiliated with Prowlarr // Retain user fields not-affiliated with Prowlarr
readarrIndexer.Fields.AddRange(remoteIndexer.Fields.Where(f => readarrIndexer.Fields.All(s => s.Name != f.Name))); readarrIndexer.Fields.AddRange(remoteIndexer.Fields.Where(f => readarrIndexer.Fields.All(s => s.Name != f.Name)));
@@ -204,7 +212,8 @@ namespace NzbDrone.Core.Applications.Readarr
{ {
_appIndexerMapService.Delete(indexerMapping.Id); _appIndexerMapService.Delete(indexerMapping.Id);
if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any()) if ((indexerCapabilities.BookSearchAvailable || indexerCapabilities.SearchAvailable) &&
indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any())
{ {
_logger.Debug("Remote indexer not found, re-adding {0} [{1}] to Readarr", indexer.Name, indexer.Id); _logger.Debug("Remote indexer not found, re-adding {0} [{1}] to Readarr", indexer.Name, indexer.Id);
readarrIndexer.Id = 0; readarrIndexer.Id = 0;
@@ -19,7 +19,7 @@ namespace NzbDrone.Core.Applications.Readarr
public class ReadarrSettings : IApplicationSettings public class ReadarrSettings : IApplicationSettings
{ {
private static readonly ReadarrSettingsValidator Validator = new (); private static readonly ReadarrSettingsValidator Validator = new();
public ReadarrSettings() public ReadarrSettings()
{ {
@@ -125,10 +125,17 @@ namespace NzbDrone.Core.Applications.Sonarr
{ {
var indexerCapabilities = GetIndexerCapabilities(indexer); var indexerCapabilities = GetIndexerCapabilities(indexer);
if (!indexerCapabilities.TvSearchAvailable && !indexerCapabilities.SearchAvailable)
{
_logger.Debug("Skipping add for indexer {0} [{1}] due to missing TV or basic search support by the indexer", indexer.Name, indexer.Id);
return;
}
if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Empty() && if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Empty() &&
indexerCapabilities.Categories.SupportedCategories(Settings.AnimeSyncCategories.ToArray()).Empty()) indexerCapabilities.Categories.SupportedCategories(Settings.AnimeSyncCategories.ToArray()).Empty())
{ {
_logger.Trace("Skipping add for indexer {0} [{1}] due to no app Sync Categories supported by the indexer", indexer.Name, indexer.Id); _logger.Debug("Skipping add for indexer {0} [{1}] due to no app Sync Categories supported by the indexer", indexer.Name, indexer.Id);
return; return;
} }
@@ -183,7 +190,8 @@ namespace NzbDrone.Core.Applications.Sonarr
{ {
_logger.Debug("Syncing remote indexer with current settings"); _logger.Debug("Syncing remote indexer with current settings");
if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any() || indexerCapabilities.Categories.SupportedCategories(Settings.AnimeSyncCategories.ToArray()).Any()) if ((indexerCapabilities.TvSearchAvailable || indexerCapabilities.SearchAvailable) &&
(indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any() || indexerCapabilities.Categories.SupportedCategories(Settings.AnimeSyncCategories.ToArray()).Any()))
{ {
// Retain user fields not-affiliated with Prowlarr // Retain user fields not-affiliated with Prowlarr
sonarrIndexer.Fields.AddRange(remoteIndexer.Fields.Where(f => sonarrIndexer.Fields.All(s => s.Name != f.Name))); sonarrIndexer.Fields.AddRange(remoteIndexer.Fields.Where(f => sonarrIndexer.Fields.All(s => s.Name != f.Name)));
@@ -210,7 +218,8 @@ namespace NzbDrone.Core.Applications.Sonarr
{ {
_appIndexerMapService.Delete(indexerMapping.Id); _appIndexerMapService.Delete(indexerMapping.Id);
if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any() || indexerCapabilities.Categories.SupportedCategories(Settings.AnimeSyncCategories.ToArray()).Any()) if ((indexerCapabilities.TvSearchAvailable || indexerCapabilities.SearchAvailable) &&
(indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any() || indexerCapabilities.Categories.SupportedCategories(Settings.AnimeSyncCategories.ToArray()).Any()))
{ {
_logger.Debug("Remote indexer not found, re-adding {0} [{1}] to Sonarr", indexer.Name, indexer.Id); _logger.Debug("Remote indexer not found, re-adding {0} [{1}] to Sonarr", indexer.Name, indexer.Id);
sonarrIndexer.Id = 0; sonarrIndexer.Id = 0;
@@ -18,7 +18,7 @@ namespace NzbDrone.Core.Applications.Sonarr
public class SonarrSettings : IApplicationSettings public class SonarrSettings : IApplicationSettings
{ {
private static readonly SonarrSettingsValidator Validator = new (); private static readonly SonarrSettingsValidator Validator = new();
public SonarrSettings() public SonarrSettings()
{ {
@@ -23,7 +23,7 @@ namespace NzbDrone.Core.Applications.Sonarr
public class SonarrV3Proxy : ISonarrV3Proxy public class SonarrV3Proxy : ISonarrV3Proxy
{ {
private static Version MinimumApplicationVersion => new (3, 0, 5, 0); private static Version MinimumApplicationVersion => new(3, 0, 5, 0);
private const string AppApiRoute = "/api/v3"; private const string AppApiRoute = "/api/v3";
private const string AppIndexerApiRoute = $"{AppApiRoute}/indexer"; private const string AppIndexerApiRoute = $"{AppApiRoute}/indexer";
@@ -19,7 +19,7 @@ namespace NzbDrone.Core.Applications.Whisparr
public class WhisparrSettings : IApplicationSettings public class WhisparrSettings : IApplicationSettings
{ {
private static readonly WhisparrSettingsValidator Validator = new (); private static readonly WhisparrSettingsValidator Validator = new();
public WhisparrSettings() public WhisparrSettings()
{ {
@@ -1,8 +1,11 @@
using System;
namespace NzbDrone.Core.Authentication namespace NzbDrone.Core.Authentication
{ {
public enum AuthenticationType public enum AuthenticationType
{ {
None = 0, None = 0,
[Obsolete("Use Forms authentication instead")]
Basic = 1, Basic = 1,
Forms = 2, Forms = 2,
External = 3 External = 3
@@ -207,8 +207,8 @@ namespace NzbDrone.Core.Configuration
if (enabled) if (enabled)
{ {
SetValue("AuthenticationMethod", AuthenticationType.Basic); SetValue("AuthenticationMethod", AuthenticationType.Forms);
return AuthenticationType.Basic; return AuthenticationType.Forms;
} }
return Enum.TryParse<AuthenticationType>(_authOptions.Method, out var enumValue) return Enum.TryParse<AuthenticationType>(_authOptions.Method, out var enumValue)
@@ -254,7 +254,7 @@ namespace NzbDrone.Core.Datastore
protected void Delete(SqlBuilder builder) protected void Delete(SqlBuilder builder)
{ {
var sql = builder.AddDeleteTemplate(typeof(TModel)).LogQuery(); var sql = builder.AddDeleteTemplate(typeof(TModel));
using (var conn = _database.OpenConnection()) using (var conn = _database.OpenConnection())
{ {
@@ -5,7 +5,7 @@ namespace NzbDrone.Core.Datastore;
public static class DatabaseVersionParser public static class DatabaseVersionParser
{ {
private static readonly Regex VersionRegex = new (@"^[^ ]+", RegexOptions.Compiled); private static readonly Regex VersionRegex = new(@"^[^ ]+", RegexOptions.Compiled);
public static Version ParseServerVersion(string serverVersion) public static Version ParseServerVersion(string serverVersion)
{ {
@@ -27,7 +27,7 @@ namespace NzbDrone.Core.Datastore
switch (expression.NodeType) switch (expression.NodeType)
{ {
case ExpressionType.Lambda: case ExpressionType.Lambda:
return VisitLamda((LambdaExpression)expression); return VisitLambda((LambdaExpression)expression);
case ExpressionType.ArrayLength: case ExpressionType.ArrayLength:
case ExpressionType.Convert: case ExpressionType.Convert:
case ExpressionType.ConvertChecked: case ExpressionType.ConvertChecked:
@@ -87,7 +87,7 @@ namespace NzbDrone.Core.Datastore
} }
/// <summary> /// <summary>
/// Visits the memeber access expression. To be implemented by user. /// Visits the member access expression. To be implemented by user.
/// </summary> /// </summary>
/// <param name="expression"></param> /// <param name="expression"></param>
/// <returns></returns> /// <returns></returns>
@@ -130,11 +130,11 @@ namespace NzbDrone.Core.Datastore
} }
/// <summary> /// <summary>
/// Visits the lamda expression. /// Visits the lambda expression.
/// </summary> /// </summary>
/// <param name="lambdaExpression"></param> /// <param name="lambdaExpression"></param>
/// <returns></returns> /// <returns></returns>
protected virtual Expression VisitLamda(LambdaExpression lambdaExpression) protected virtual Expression VisitLambda(LambdaExpression lambdaExpression)
{ {
Visit(lambdaExpression.Body); Visit(lambdaExpression.Body);
return lambdaExpression; return lambdaExpression;
@@ -7,6 +7,7 @@ using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers; using NzbDrone.Core.Indexers;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Validation; using NzbDrone.Core.Validation;
@@ -25,8 +26,9 @@ namespace NzbDrone.Core.Download.Clients.Aria2
ISeedConfigProvider seedConfigProvider, ISeedConfigProvider seedConfigProvider,
IConfigService configService, IConfigService configService,
IDiskProvider diskProvider, IDiskProvider diskProvider,
ILocalizationService localizationService,
Logger logger) Logger logger)
: base(torrentFileInfoReader, seedConfigProvider, configService, diskProvider, logger) : base(torrentFileInfoReader, seedConfigProvider, configService, diskProvider, localizationService, logger)
{ {
_proxy = proxy; _proxy = proxy;
} }
@@ -8,6 +8,7 @@ using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers; using NzbDrone.Core.Indexers;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Download.Clients.Blackhole namespace NzbDrone.Core.Download.Clients.Blackhole
@@ -20,8 +21,9 @@ namespace NzbDrone.Core.Download.Clients.Blackhole
ISeedConfigProvider seedConfigProvider, ISeedConfigProvider seedConfigProvider,
IConfigService configService, IConfigService configService,
IDiskProvider diskProvider, IDiskProvider diskProvider,
ILocalizationService localizationService,
Logger logger) Logger logger)
: base(torrentFileInfoReader, seedConfigProvider, configService, diskProvider, logger) : base(torrentFileInfoReader, seedConfigProvider, configService, diskProvider, localizationService, logger)
{ {
} }
@@ -7,6 +7,7 @@ using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Download.Clients.Blackhole namespace NzbDrone.Core.Download.Clients.Blackhole
@@ -16,8 +17,9 @@ namespace NzbDrone.Core.Download.Clients.Blackhole
public UsenetBlackhole(IHttpClient httpClient, public UsenetBlackhole(IHttpClient httpClient,
IConfigService configService, IConfigService configService,
IDiskProvider diskProvider, IDiskProvider diskProvider,
ILocalizationService localizationService,
Logger logger) Logger logger)
: base(httpClient, configService, diskProvider, logger) : base(httpClient, configService, diskProvider, localizationService, logger)
{ {
} }
@@ -9,6 +9,7 @@ using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers; using NzbDrone.Core.Indexers;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Validation; using NzbDrone.Core.Validation;
@@ -23,8 +24,9 @@ namespace NzbDrone.Core.Download.Clients.Deluge
ISeedConfigProvider seedConfigProvider, ISeedConfigProvider seedConfigProvider,
IConfigService configService, IConfigService configService,
IDiskProvider diskProvider, IDiskProvider diskProvider,
ILocalizationService localizationService,
Logger logger) Logger logger)
: base(torrentFileInfoReader, seedConfigProvider, configService, diskProvider, logger) : base(torrentFileInfoReader, seedConfigProvider, configService, diskProvider, localizationService, logger)
{ {
_proxy = proxy; _proxy = proxy;
} }
@@ -10,6 +10,7 @@ using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Download.Clients.DownloadStation.Proxies; using NzbDrone.Core.Download.Clients.DownloadStation.Proxies;
using NzbDrone.Core.Indexers; using NzbDrone.Core.Indexers;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation; using NzbDrone.Core.Validation;
@@ -33,8 +34,9 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
ISeedConfigProvider seedConfigProvider, ISeedConfigProvider seedConfigProvider,
IConfigService configService, IConfigService configService,
IDiskProvider diskProvider, IDiskProvider diskProvider,
ILocalizationService localizationService,
Logger logger) Logger logger)
: base(torrentFileInfoReader, seedConfigProvider, configService, diskProvider, logger) : base(torrentFileInfoReader, seedConfigProvider, configService, diskProvider, localizationService, logger)
{ {
_dsInfoProxy = dsInfoProxy; _dsInfoProxy = dsInfoProxy;
_dsTaskProxySelector = dsTaskProxySelector; _dsTaskProxySelector = dsTaskProxySelector;
@@ -9,6 +9,7 @@ using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Download.Clients.DownloadStation.Proxies; using NzbDrone.Core.Download.Clients.DownloadStation.Proxies;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation; using NzbDrone.Core.Validation;
@@ -31,8 +32,9 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
IHttpClient httpClient, IHttpClient httpClient,
IConfigService configService, IConfigService configService,
IDiskProvider diskProvider, IDiskProvider diskProvider,
ILocalizationService localizationService,
Logger logger) Logger logger)
: base(httpClient, configService, diskProvider, logger) : base(httpClient, configService, diskProvider, localizationService, logger)
{ {
_dsInfoProxy = dsInfoProxy; _dsInfoProxy = dsInfoProxy;
_dsTaskProxySelector = dsTaskProxySelector; _dsTaskProxySelector = dsTaskProxySelector;
@@ -8,6 +8,7 @@ using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Download.Clients.Flood.Models; using NzbDrone.Core.Download.Clients.Flood.Models;
using NzbDrone.Core.Indexers; using NzbDrone.Core.Indexers;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.ThingiProvider;
@@ -22,8 +23,9 @@ namespace NzbDrone.Core.Download.Clients.Flood
ISeedConfigProvider seedConfigProvider, ISeedConfigProvider seedConfigProvider,
IConfigService configService, IConfigService configService,
IDiskProvider diskProvider, IDiskProvider diskProvider,
ILocalizationService localizationService,
Logger logger) Logger logger)
: base(torrentFileInfoReader, seedConfigProvider, configService, diskProvider, logger) : base(torrentFileInfoReader, seedConfigProvider, configService, diskProvider, localizationService, logger)
{ {
_proxy = proxy; _proxy = proxy;
} }
@@ -36,7 +36,7 @@ namespace NzbDrone.Core.Download.Clients.FreeboxDownload
public class FreeboxDownloadSettings : IProviderConfig public class FreeboxDownloadSettings : IProviderConfig
{ {
private static readonly FreeboxDownloadSettingsValidator Validator = new (); private static readonly FreeboxDownloadSettingsValidator Validator = new();
public FreeboxDownloadSettings() public FreeboxDownloadSettings()
{ {
@@ -6,6 +6,7 @@ using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers; using NzbDrone.Core.Indexers;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Download.Clients.FreeboxDownload namespace NzbDrone.Core.Download.Clients.FreeboxDownload
@@ -19,8 +20,9 @@ namespace NzbDrone.Core.Download.Clients.FreeboxDownload
ISeedConfigProvider seedConfigProvider, ISeedConfigProvider seedConfigProvider,
IConfigService configService, IConfigService configService,
IDiskProvider diskProvider, IDiskProvider diskProvider,
ILocalizationService localizationService,
Logger logger) Logger logger)
: base(torrentFileInfoReader, seedConfigProvider, configService, diskProvider, logger) : base(torrentFileInfoReader, seedConfigProvider, configService, diskProvider, localizationService, logger)
{ {
_proxy = proxy; _proxy = proxy;
} }
@@ -6,6 +6,7 @@ using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers; using NzbDrone.Core.Indexers;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Validation; using NzbDrone.Core.Validation;
@@ -20,8 +21,9 @@ namespace NzbDrone.Core.Download.Clients.Hadouken
ISeedConfigProvider seedConfigProvider, ISeedConfigProvider seedConfigProvider,
IConfigService configService, IConfigService configService,
IDiskProvider diskProvider, IDiskProvider diskProvider,
ILocalizationService localizationService,
Logger logger) Logger logger)
: base(torrentFileInfoReader, seedConfigProvider, configService, diskProvider, logger) : base(torrentFileInfoReader, seedConfigProvider, configService, diskProvider, localizationService, logger)
{ {
_proxy = proxy; _proxy = proxy;
} }
@@ -7,6 +7,7 @@ using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Validation; using NzbDrone.Core.Validation;
@@ -20,8 +21,9 @@ namespace NzbDrone.Core.Download.Clients.NzbVortex
IHttpClient httpClient, IHttpClient httpClient,
IConfigService configService, IConfigService configService,
IDiskProvider diskProvider, IDiskProvider diskProvider,
ILocalizationService localizationService,
Logger logger) Logger logger)
: base(httpClient, configService, diskProvider, logger) : base(httpClient, configService, diskProvider, localizationService, logger)
{ {
_proxy = proxy; _proxy = proxy;
} }
@@ -10,6 +10,7 @@ using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Exceptions; using NzbDrone.Core.Exceptions;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Validation; using NzbDrone.Core.Validation;
@@ -18,15 +19,14 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
public class Nzbget : UsenetClientBase<NzbgetSettings> public class Nzbget : UsenetClientBase<NzbgetSettings>
{ {
private readonly INzbgetProxy _proxy; private readonly INzbgetProxy _proxy;
private readonly string[] _successStatus = { "SUCCESS", "NONE" };
private readonly string[] _deleteFailedStatus = { "HEALTH", "DUPE", "SCAN", "COPY", "BAD" };
public Nzbget(INzbgetProxy proxy, public Nzbget(INzbgetProxy proxy,
IHttpClient httpClient, IHttpClient httpClient,
IConfigService configService, IConfigService configService,
IDiskProvider diskProvider, IDiskProvider diskProvider,
ILocalizationService localizationService,
Logger logger) Logger logger)
: base(httpClient, configService, diskProvider, logger) : base(httpClient, configService, diskProvider, localizationService, logger)
{ {
_proxy = proxy; _proxy = proxy;
} }
@@ -8,6 +8,7 @@ using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers; using NzbDrone.Core.Indexers;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
@@ -17,8 +18,9 @@ namespace NzbDrone.Core.Download.Clients.Pneumatic
{ {
public Pneumatic(IConfigService configService, public Pneumatic(IConfigService configService,
IDiskProvider diskProvider, IDiskProvider diskProvider,
ILocalizationService localizationService,
Logger logger) Logger logger)
: base(configService, diskProvider, logger) : base(configService, diskProvider, localizationService, logger)
{ {
} }
@@ -8,6 +8,7 @@ using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers; using NzbDrone.Core.Indexers;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Validation; using NzbDrone.Core.Validation;
@@ -30,8 +31,9 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
IConfigService configService, IConfigService configService,
IDiskProvider diskProvider, IDiskProvider diskProvider,
ICacheManager cacheManager, ICacheManager cacheManager,
ILocalizationService localizationService,
Logger logger) Logger logger)
: base(torrentFileInfoReader, seedConfigProvider, configService, diskProvider, logger) : base(torrentFileInfoReader, seedConfigProvider, configService, diskProvider, localizationService, logger)
{ {
_proxySelector = proxySelector; _proxySelector = proxySelector;
@@ -9,6 +9,7 @@ using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Exceptions; using NzbDrone.Core.Exceptions;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Validation; using NzbDrone.Core.Validation;
@@ -22,8 +23,9 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
IHttpClient httpClient, IHttpClient httpClient,
IConfigService configService, IConfigService configService,
IDiskProvider diskProvider, IDiskProvider diskProvider,
ILocalizationService localizationService,
Logger logger) Logger logger)
: base(httpClient, configService, diskProvider, logger) : base(httpClient, configService, diskProvider, localizationService, logger)
{ {
_proxy = proxy; _proxy = proxy;
} }
@@ -5,6 +5,7 @@ using NLog;
using NzbDrone.Common.Disk; using NzbDrone.Common.Disk;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers; using NzbDrone.Core.Indexers;
using NzbDrone.Core.Localization;
namespace NzbDrone.Core.Download.Clients.Transmission namespace NzbDrone.Core.Download.Clients.Transmission
{ {
@@ -15,8 +16,9 @@ namespace NzbDrone.Core.Download.Clients.Transmission
ISeedConfigProvider seedConfigProvider, ISeedConfigProvider seedConfigProvider,
IConfigService configService, IConfigService configService,
IDiskProvider diskProvider, IDiskProvider diskProvider,
ILocalizationService localizationService,
Logger logger) Logger logger)
: base(proxy, torrentFileInfoReader, seedConfigProvider, configService, diskProvider, logger) : base(proxy, torrentFileInfoReader, seedConfigProvider, configService, diskProvider, localizationService, logger)
{ {
} }
@@ -6,6 +6,7 @@ using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers; using NzbDrone.Core.Indexers;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Validation; using NzbDrone.Core.Validation;
@@ -20,8 +21,9 @@ namespace NzbDrone.Core.Download.Clients.Transmission
ISeedConfigProvider seedConfigProvider, ISeedConfigProvider seedConfigProvider,
IConfigService configService, IConfigService configService,
IDiskProvider diskProvider, IDiskProvider diskProvider,
ILocalizationService localizationService,
Logger logger) Logger logger)
: base(torrentFileInfoReader, seedConfigProvider, configService, diskProvider, logger) : base(torrentFileInfoReader, seedConfigProvider, configService, diskProvider, localizationService, logger)
{ {
_proxy = proxy; _proxy = proxy;
} }
@@ -4,6 +4,7 @@ using NzbDrone.Common.Disk;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Download.Clients.Transmission; using NzbDrone.Core.Download.Clients.Transmission;
using NzbDrone.Core.Indexers; using NzbDrone.Core.Indexers;
using NzbDrone.Core.Localization;
namespace NzbDrone.Core.Download.Clients.Vuze namespace NzbDrone.Core.Download.Clients.Vuze
{ {
@@ -16,8 +17,9 @@ namespace NzbDrone.Core.Download.Clients.Vuze
ISeedConfigProvider seedConfigProvider, ISeedConfigProvider seedConfigProvider,
IConfigService configService, IConfigService configService,
IDiskProvider diskProvider, IDiskProvider diskProvider,
ILocalizationService localizationService,
Logger logger) Logger logger)
: base(proxy, torrentFileInfoReader, seedConfigProvider, configService, diskProvider, logger) : base(proxy, torrentFileInfoReader, seedConfigProvider, configService, diskProvider, localizationService, logger)
{ {
} }
@@ -10,6 +10,7 @@ using NzbDrone.Core.Configuration;
using NzbDrone.Core.Download.Clients.rTorrent; using NzbDrone.Core.Download.Clients.rTorrent;
using NzbDrone.Core.Exceptions; using NzbDrone.Core.Exceptions;
using NzbDrone.Core.Indexers; using NzbDrone.Core.Indexers;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation; using NzbDrone.Core.Validation;
@@ -27,8 +28,9 @@ namespace NzbDrone.Core.Download.Clients.RTorrent
IConfigService configService, IConfigService configService,
IDiskProvider diskProvider, IDiskProvider diskProvider,
IRTorrentDirectoryValidator rTorrentDirectoryValidator, IRTorrentDirectoryValidator rTorrentDirectoryValidator,
ILocalizationService localizationService,
Logger logger) Logger logger)
: base(torrentFileInfoReader, seedConfigProvider, configService, diskProvider, logger) : base(torrentFileInfoReader, seedConfigProvider, configService, diskProvider, localizationService, logger)
{ {
_proxy = proxy; _proxy = proxy;
_rTorrentDirectoryValidator = rTorrentDirectoryValidator; _rTorrentDirectoryValidator = rTorrentDirectoryValidator;
@@ -7,7 +7,9 @@ using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers; using NzbDrone.Core.Indexers;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation; using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Download.Clients.UTorrent namespace NzbDrone.Core.Download.Clients.UTorrent
@@ -21,8 +23,9 @@ namespace NzbDrone.Core.Download.Clients.UTorrent
ISeedConfigProvider seedConfigProvider, ISeedConfigProvider seedConfigProvider,
IConfigService configService, IConfigService configService,
IDiskProvider diskProvider, IDiskProvider diskProvider,
ILocalizationService localizationService,
Logger logger) Logger logger)
: base(torrentFileInfoReader, seedConfigProvider, configService, diskProvider, logger) : base(torrentFileInfoReader, seedConfigProvider, configService, diskProvider, localizationService, logger)
{ {
_proxy = proxy; _proxy = proxy;
} }
@@ -72,6 +75,9 @@ namespace NzbDrone.Core.Download.Clients.UTorrent
} }
public override string Name => "uTorrent"; public override string Name => "uTorrent";
public override ProviderMessage Message => new(_localizationService.GetLocalizedString("DownloadClientUTorrentProviderMessage"), ProviderMessageType.Warning);
public override bool SupportsCategories => true; public override bool SupportsCategories => true;
protected override void Test(List<ValidationFailure> failures) protected override void Test(List<ValidationFailure> failures)
@@ -8,6 +8,7 @@ using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers; using NzbDrone.Core.Indexers;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation; using NzbDrone.Core.Validation;
@@ -19,6 +20,7 @@ namespace NzbDrone.Core.Download
{ {
protected readonly IConfigService _configService; protected readonly IConfigService _configService;
protected readonly IDiskProvider _diskProvider; protected readonly IDiskProvider _diskProvider;
protected readonly ILocalizationService _localizationService;
protected readonly Logger _logger; protected readonly Logger _logger;
public abstract string Name { get; } public abstract string Name { get; }
@@ -40,10 +42,12 @@ namespace NzbDrone.Core.Download
protected DownloadClientBase(IConfigService configService, protected DownloadClientBase(IConfigService configService,
IDiskProvider diskProvider, IDiskProvider diskProvider,
ILocalizationService localizationService,
Logger logger) Logger logger)
{ {
_configService = configService; _configService = configService;
_diskProvider = diskProvider; _diskProvider = diskProvider;
_localizationService = localizationService;
_logger = logger; _logger = logger;
} }
@@ -1,3 +1,4 @@
using System;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Xml; using System.Xml;
@@ -15,39 +16,53 @@ namespace NzbDrone.Core.Download
{ {
public void Validate(byte[] fileContent) public void Validate(byte[] fileContent)
{ {
var reader = new StreamReader(new MemoryStream(fileContent)); try
using (var xmlTextReader = XmlReader.Create(reader, new XmlReaderSettings { DtdProcessing = DtdProcessing.Ignore, IgnoreComments = true }))
{ {
var xDoc = XDocument.Load(xmlTextReader); var reader = new StreamReader(new MemoryStream(fileContent));
var nzb = xDoc.Root;
if (nzb == null) using (var xmlTextReader = XmlReader.Create(reader,
new XmlReaderSettings { DtdProcessing = DtdProcessing.Ignore, IgnoreComments = true }))
{ {
throw new InvalidNzbException("Invalid NZB: No Root element"); var xDoc = XDocument.Load(xmlTextReader);
} var nzb = xDoc.Root;
// nZEDb has an bug in their error reporting code spitting out invalid http status codes if (nzb == null)
if (nzb.Name.LocalName.Equals("error") && {
nzb.TryGetAttributeValue("code", out var code) && throw new InvalidNzbException("Invalid NZB: No Root element");
nzb.TryGetAttributeValue("description", out var description)) }
{
throw new InvalidNzbException("Invalid NZB: Contains indexer error: {0} - {1}", code, description);
}
if (!nzb.Name.LocalName.Equals("nzb")) // nZEDb has a bug in their error reporting code spitting out invalid http status codes
{ if (nzb.Name.LocalName.Equals("error") &&
throw new InvalidNzbException("Invalid NZB: Unexpected root element. Expected 'nzb' found '{0}'", nzb.Name.LocalName); nzb.TryGetAttributeValue("code", out var code) &&
} nzb.TryGetAttributeValue("description", out var description))
{
throw new InvalidNzbException("Invalid NZB: Contains indexer error: {0} - {1}", code, description);
}
var ns = nzb.Name.Namespace; if (!nzb.Name.LocalName.Equals("nzb"))
var files = nzb.Elements(ns + "file").ToList(); {
throw new InvalidNzbException(
"Invalid NZB: Unexpected root element. Expected 'nzb' found '{0}'", nzb.Name.LocalName);
}
if (files.Empty()) var ns = nzb.Name.Namespace;
{ var files = nzb.Elements(ns + "file").ToList();
throw new InvalidNzbException("Invalid NZB: No files");
if (files.Empty())
{
throw new InvalidNzbException("Invalid NZB: No files");
}
} }
} }
catch (InvalidNzbException)
{
// Throw the original exception
throw;
}
catch (Exception ex)
{
throw new InvalidNzbException("Invalid NZB: Unable to parse", ex);
}
} }
} }
} }
@@ -8,6 +8,7 @@ using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Exceptions; using NzbDrone.Core.Exceptions;
using NzbDrone.Core.Indexers; using NzbDrone.Core.Indexers;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.ThingiProvider;
@@ -24,8 +25,9 @@ namespace NzbDrone.Core.Download
ISeedConfigProvider seedConfigProvider, ISeedConfigProvider seedConfigProvider,
IConfigService configService, IConfigService configService,
IDiskProvider diskProvider, IDiskProvider diskProvider,
ILocalizationService localizationService,
Logger logger) Logger logger)
: base(configService, diskProvider, logger) : base(configService, diskProvider, localizationService, logger)
{ {
_torrentFileInfoReader = torrentFileInfoReader; _torrentFileInfoReader = torrentFileInfoReader;
_seedConfigProvider = seedConfigProvider; _seedConfigProvider = seedConfigProvider;
@@ -5,6 +5,7 @@ using NzbDrone.Common.Disk;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers; using NzbDrone.Core.Indexers;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.ThingiProvider;
@@ -19,8 +20,9 @@ namespace NzbDrone.Core.Download
protected UsenetClientBase(IHttpClient httpClient, protected UsenetClientBase(IHttpClient httpClient,
IConfigService configService, IConfigService configService,
IDiskProvider diskProvider, IDiskProvider diskProvider,
ILocalizationService localizationService,
Logger logger) Logger logger)
: base(configService, diskProvider, logger) : base(configService, diskProvider, localizationService, logger)
{ {
_httpClient = httpClient; _httpClient = httpClient;
} }
+1 -1
View File
@@ -224,7 +224,7 @@ namespace NzbDrone.Core.History
if (message.Release.PublishDate != DateTime.MinValue) if (message.Release.PublishDate != DateTime.MinValue)
{ {
history.Data.Add("PublishedDate", message.Release.PublishDate.ToString("s") + "Z"); history.Data.Add("PublishedDate", message.Release.PublishDate.ToUniversalTime().ToString("s") + "Z");
} }
_historyRepository.Insert(history); _historyRepository.Insert(history);

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