Compare commits

...

42 Commits

Author SHA1 Message Date
bakerboy448
749684e24a New: Indexer Messaging and Error Improvements
(cherry picked from commit 3b505d8734dcbe3fa53acba7f94f1361151e6a44)
2023-06-19 16:12:15 +03:00
Bogdan
3a0ca45aa9 Fix sorting queue items by size 2023-06-18 15:00:49 +03:00
Bogdan
595efd498e Close database connections in housekeeping tasks
Co-authored-by: ferencmarkizay <ferencmarkizay@gmail.com>
2023-06-18 15:00:11 +03:00
Bogdan
dea1060d61 Bump version to 0.2.0 2023-06-18 07:18:42 +03:00
Weblate
f6049b8bf2 Translated using Weblate (Portuguese (Brazil)) [skip ci]
Currently translated at 100.0% (942 of 942 strings)

Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt_BR/
Translation: Servarr/Readarr
2023-06-18 04:53:21 +03:00
Bogdan
53ced38221 New: Improved page loading errors
Closes #2605
2023-06-17 00:51:10 +03:00
Tristan Kennedy
3a3cf8511e Added padding to search tab to maintain visual consistancy
(cherry picked from commit 55ef505d740a9aadc7f161274006e150b0d9cf8f)
2023-06-17 00:50:55 +03:00
Servarr
9ec913337d Automated API Docs update [skip ci] 2023-06-15 13:26:07 +03:00
Weblate
9a2120ae92 Update translation files [skip ci]
Updated by "Cleanup translation files" hook in Weblate.

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

Currently translated at 16.0% (151 of 942 strings)

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

Currently translated at 100.0% (942 of 942 strings)

Translated using Weblate (Turkish) [skip ci]

Currently translated at 61.6% (581 of 942 strings)

Translated using Weblate (Romanian) [skip ci]

Currently translated at 59.9% (565 of 942 strings)

Translated using Weblate (Polish) [skip ci]

Currently translated at 65.9% (621 of 942 strings)

Translated using Weblate (Korean) [skip ci]

Currently translated at 60.9% (574 of 942 strings)

Translated using Weblate (Japanese) [skip ci]

Currently translated at 61.4% (579 of 942 strings)

Translated using Weblate (Icelandic) [skip ci]

Currently translated at 61.5% (580 of 942 strings)

Translated using Weblate (Hindi) [skip ci]

Currently translated at 61.4% (579 of 942 strings)

Translated using Weblate (Hebrew) [skip ci]

Currently translated at 64.0% (603 of 942 strings)

Translated using Weblate (French) [skip ci]

Currently translated at 78.5% (740 of 942 strings)

Translated using Weblate (Finnish) [skip ci]

Currently translated at 88.1% (830 of 942 strings)

Translated using Weblate (Danish) [skip ci]

Currently translated at 61.9% (584 of 942 strings)

Translated using Weblate (Czech) [skip ci]

Currently translated at 61.6% (581 of 942 strings)

Translated using Weblate (Bulgarian) [skip ci]

Currently translated at 61.5% (580 of 942 strings)

Translated using Weblate (Arabic) [skip ci]

Currently translated at 61.6% (581 of 942 strings)

Translated using Weblate (Spanish) [skip ci]

Currently translated at 68.2% (643 of 942 strings)

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: fatalicus <fatalicus@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ar/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/bg/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/cs/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/da/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/he/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/hi/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/is/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ja/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ko/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/nb_NO/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pl/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ro/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/tr/
Translation: Servarr/Readarr
2023-06-15 13:16:52 +03:00
Bogdan
818d3a94d5 Add skip ci to API docs update commit 2023-06-15 13:15:37 +03:00
Bogdan
4e493b74e6 Update cleansing rules for RSS TL feed and homedir for Mac
(cherry picked from commit e5ff4aafa3f0b855fec332788e9fc490a03dfce3)

Closes #2593
2023-06-15 13:06:26 +03:00
Bogdan
c7eaf1e85c Update translations
(cherry picked from commit 26031389757f6b5270bbe5591101b08e58debb73)

Closes #2599
2023-06-15 13:02:50 +03:00
Bogdan
31fe15c911 Add HelpTextWarning support in FieldDefinition
(cherry picked from commit 0e07d54ee77d5f83716e17b6757e23f38ff73694)

Closes #2595
2023-06-15 13:00:42 +03:00
Bogdan
2c36a6c25f Require ApiKey for all actions in SonarrImport
(cherry picked from commit 19b8fbe13bf584b915a05fe9fc87622adbaee0b7)

Closes #2600
2023-06-15 12:58:43 +03:00
Bogdan
6af56f7a15 Fixed: Treat redirects as errors in Readarr Import List
(cherry picked from commit 059a156f4a34c6b9cbe139fa1973b814e8a534ae)

Closes #2601
2023-06-15 12:57:09 +03:00
Qstick
6e13191c25 Fixed: Correctly handle 302 and 303 redirects in HttpClient
(cherry picked from commit ed7c5a937f4b50fcdf819e8fe347c8c0bc6bd2e7)

(cherry picked from commit 11bd764a75d3b97117098738d3489c4b3329738f)
2023-06-14 08:13:20 +03:00
bakerboy448
921ddfc962 Fixed: Handle checkingResumeData state form qBittorrent
(cherry picked from commit 8d8a16225ff7772ccb57784f272ca31e28bb8455)
2023-06-14 08:12:58 +03:00
Weblate
22f977401a Update translation files [skip ci]
Updated by "Cleanup translation files" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/
Translation: Servarr/Readarr
2023-06-13 01:38:53 +03:00
Bogdan
113d9a07ef Update translations 2023-06-13 01:35:03 +03:00
Qstick
0560d65ea1 Update Remote Path Mapping delete modal title
(cherry picked from commit 18716a00516a971f7f2eb369b920266bea24fe08)

Closes #2588
Fixes #2587
2023-06-12 22:31:04 +03:00
Weblate
94ff105104 Translated using Weblate (Indonesian) [skip ci]
Currently translated at 3.7% (35 of 928 strings)

Co-authored-by: liimee <git.taaa@fedora.email>
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/id/
Translation: Servarr/Readarr
2023-06-12 21:58:09 +03:00
Bogdan
9bcf258aa9 Bump version to 0.1.9 2023-06-11 09:38:16 +03:00
Bogdan
54985bd4ca Use more specific styling for kinds in ProgressBar
(cherry picked from commit dd31c913d2a974d95f3be251714ce749cfd99a72)
2023-06-10 02:07:40 +03:00
Weblate
9e4d551f08 Translated using Weblate (Russian) [skip ci]
Currently translated at 67.7% (629 of 928 strings)

Co-authored-by: Андрей <andryfly7@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ru/
Translation: Servarr/Readarr
2023-06-10 02:02:58 +03:00
Weblate
8390da1c2a Translated using Weblate (Greek) [skip ci]
Currently translated at 99.8% (927 of 928 strings)

Translated using Weblate (French) [skip ci]

Currently translated at 78.4% (728 of 928 strings)

Translated using Weblate (Portuguese) [skip ci]

Currently translated at 77.0% (715 of 928 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 98.3% (913 of 928 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 98.3% (913 of 928 strings)

Translated using Weblate (Indonesian) [skip ci]

Currently translated at 3.5% (33 of 928 strings)

Translated using Weblate (Croatian) [skip ci]

Currently translated at 15.7% (146 of 928 strings)

Translated using Weblate (Ukrainian) [skip ci]

Currently translated at 66.7% (619 of 928 strings)

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

Currently translated at 15.7% (146 of 928 strings)

Translated using Weblate (Catalan) [skip ci]

Currently translated at 67.7% (629 of 928 strings)

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

Currently translated at 100.0% (928 of 928 strings)

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

Currently translated at 100.0% (928 of 928 strings)

Translated using Weblate (Portuguese) [skip ci]

Currently translated at 76.9% (714 of 928 strings)

Translated using Weblate (Vietnamese) [skip ci]

Currently translated at 61.5% (571 of 928 strings)

Translated using Weblate (Turkish) [skip ci]

Currently translated at 61.6% (572 of 928 strings)

Translated using Weblate (Swedish) [skip ci]

Currently translated at 86.7% (805 of 928 strings)

Translated using Weblate (Russian) [skip ci]

Currently translated at 67.6% (628 of 928 strings)

Translated using Weblate (Polish) [skip ci]

Currently translated at 65.7% (610 of 928 strings)

Translated using Weblate (Japanese) [skip ci]

Currently translated at 61.5% (571 of 928 strings)

Translated using Weblate (Italian) [skip ci]

Currently translated at 73.0% (678 of 928 strings)

Translated using Weblate (Hungarian) [skip ci]

Currently translated at 98.0% (910 of 928 strings)

Translated using Weblate (French) [skip ci]

Currently translated at 78.3% (727 of 928 strings)

Translated using Weblate (Greek) [skip ci]

Currently translated at 98.5% (915 of 928 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 98.1% (911 of 928 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 98.1% (911 of 928 strings)

Translated using Weblate (Dutch) [skip ci]

Currently translated at 68.2% (633 of 928 strings)

Translated using Weblate (Dutch) [skip ci]

Currently translated at 68.2% (633 of 928 strings)

Translated using Weblate (French) [skip ci]

Currently translated at 78.3% (727 of 928 strings)

Translated using Weblate (Thai) [skip ci]

Currently translated at 61.5% (571 of 928 strings)

Translated using Weblate (Romanian) [skip ci]

Currently translated at 60.0% (557 of 928 strings)

Translated using Weblate (Icelandic) [skip ci]

Currently translated at 61.5% (571 of 928 strings)

Translated using Weblate (Hindi) [skip ci]

Currently translated at 61.5% (571 of 928 strings)

Translated using Weblate (Hebrew) [skip ci]

Currently translated at 64.0% (594 of 928 strings)

Translated using Weblate (Finnish) [skip ci]

Currently translated at 88.2% (819 of 928 strings)

Translated using Weblate (Danish) [skip ci]

Currently translated at 61.9% (575 of 928 strings)

Translated using Weblate (Bulgarian) [skip ci]

Currently translated at 61.5% (571 of 928 strings)

Translated using Weblate (Spanish) [skip ci]

Currently translated at 67.9% (631 of 928 strings)

Translated using Weblate (Arabic) [skip ci]

Currently translated at 61.6% (572 of 928 strings)

Translated using Weblate (Czech) [skip ci]

Currently translated at 61.6% (572 of 928 strings)

Update translation files [skip ci]

Updated by "Cleanup translation files" hook in Weblate.

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Jens <jensmahnke@me.com>
Co-authored-by: MoowGlax <matthieu.derouet.pro@gmail.com>
Co-authored-by: Thijs Waalen <contact@thijswaalen.com>
Co-authored-by: Thodoris Kalatzis <teo.kal@hotmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: emacsdias <emacs.dias@gmail.com>
Co-authored-by: foXaCe <foxace66@gmail.com>
Co-authored-by: reloxx <reloxx@interia.pl>
Co-authored-by: splifter <a.strahlke@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ar/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/bg/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/cs/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/da/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/el/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/he/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/hi/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/hr/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/id/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/is/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ja/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/nb_NO/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/nl/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pl/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ro/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ru/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/sv/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/th/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/tr/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/uk/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/vi/
Translation: Servarr/Readarr
2023-06-07 19:21:06 +03:00
Qstick
44ae043c58 Bump version to 0.1.8 2023-06-04 14:48:35 -05:00
Bogdan
bb7e2fc70c Fixed: Don't log handled exceptions in API 2023-05-31 06:51:57 +03:00
Bogdan
b05938a9a8 Revert "Fixed: Don't log handled exceptions in API"
This reverts commit fecb3895ed.
2023-05-31 06:51:56 +03:00
Weblate
1e42ac572e Update translation files [skip ci]
Updated by "Cleanup translation files" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/
Translation: Servarr/Readarr
2023-05-28 22:28:24 +03:00
Servarr
649dd0bda0 Automated API Docs update 2023-05-28 22:27:52 +03:00
Bogdan
de24aef059 Deserialize asynchronously in LocalizationService
(cherry picked from commit 86a7f7bd54aa733b0e3abd3ec9463a85dd348118)

Closes #2561
2023-05-28 22:15:01 +03:00
Qstick
10766dd227 Faster tag view in UI for large libraries
(cherry picked from commit b050e1d2eb3bff9e28e7a1545d121be091789308)

Closes #2571
2023-05-28 22:08:34 +03:00
Bogdan
257d279e43 Fixed: Enforce validation warnings
(cherry picked from commit 48ee1158ad4213fd0690842e2672f52d08f7ad26)

Closes #2570
2023-05-28 22:02:41 +03:00
Bogdan
1db333088a Add minimum length as const in ApiKeyValidationCheck
(cherry picked from commit b06269544cfa11015f3fb938fd8c2ef07d9cac4a)

Closes #2565
2023-05-28 22:00:31 +03:00
Bogdan
d1aff31593 Use 'var' instead of explicit type
(cherry picked from commit 12374f7f0038e5b25548f5ab3f71122410832393)

Closes #2559
2023-05-28 21:59:25 +03:00
Bogdan
89dd4d3271 Inline 'out' variable declarations
(cherry picked from commit 281add47de1d3940990156c841362125dea9cc7d)

Closes #2558
2023-05-28 21:55:43 +03:00
Bogdan
fc6c78a54e Standardize variable declaration
(cherry picked from commit 909f2ded6b75998fa8e1addd0dcf849279e7b120)

Closes #2556
Closes #2557
2023-05-28 21:47:48 +03:00
Bogdan
c98f4512df Enforce rule IDE0005 on build
(cherry picked from commit 6b1e4ef81938d264a2ddc8b626b0502f799aa640)

Closes #2555
2023-05-28 21:46:59 +03:00
Matthew Strapp
0a43481aed Fixed: Use relative paths instead of absolute paths for webmanifest
(cherry picked from commit 8e771f95ade919a8f1ed7b48675f032a6c508cb2)
2023-05-28 21:42:27 +03:00
Bogdan
df6c142250 Simplify ShouldHaveApiKey and HasErrors
(cherry picked from commit 7343616a47cd538bba4c9128d2c1094561f9b3a5)
2023-05-28 21:41:07 +03:00
Weblate
58cf93e360 Update translation files [skip ci]
Updated by "Cleanup translation files" hook in Weblate.

Translated using Weblate (Icelandic) [skip ci]

Currently translated at 61.4% (567 of 922 strings)

Translated using Weblate (Hindi) [skip ci]

Currently translated at 61.4% (567 of 922 strings)

Translated using Weblate (Hebrew) [skip ci]

Currently translated at 63.9% (590 of 922 strings)

Translated using Weblate (Finnish) [skip ci]

Currently translated at 88.3% (815 of 922 strings)

Translated using Weblate (Danish) [skip ci]

Currently translated at 61.9% (571 of 922 strings)

Translated using Weblate (Czech) [skip ci]

Currently translated at 61.6% (568 of 922 strings)

Translated using Weblate (Bulgarian) [skip ci]

Currently translated at 61.4% (567 of 922 strings)

Translated using Weblate (Arabic) [skip ci]

Currently translated at 61.6% (568 of 922 strings)

Translated using Weblate (Spanish) [skip ci]

Currently translated at 68.0% (627 of 922 strings)

Update translation files [skip ci]

Updated by "Cleanup translation files" hook in Weblate.

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/ar/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/bg/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/cs/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/da/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/he/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/hi/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/is/
Translation: Servarr/Readarr
2023-05-28 10:25:24 -05:00
Qstick
7be282ad12 Bump version to 0.1.7 2023-05-28 09:27:02 -05:00
218 changed files with 1257 additions and 819 deletions

View File

@@ -36,12 +36,18 @@ dotnet_naming_style.instance_field_style.capitalization = camel_case
dotnet_naming_style.instance_field_style.required_prefix = _
# Prefer "var" everywhere
csharp_style_var_for_built_in_types = true:suggestion
csharp_style_var_when_type_is_apparent = true:suggestion
csharp_style_var_elsewhere = true:suggestion
csharp_style_var_for_built_in_types = true
csharp_style_var_when_type_is_apparent = true
csharp_style_var_elsewhere = true
# Prefer "out" variables to be declared inline
csharp_style_inlined_variable_declaration = true
# Using directive is unnecessary.
dotnet_diagnostic.IDE0005.severity = error
# Use var instead of explicit type
dotnet_diagnostic.IDE0007.severity = error
# Inline variable declaration
dotnet_diagnostic.IDE0018.severity = error
# Stylecop Rules
dotnet_diagnostic.SA0001.severity = none

View File

@@ -9,7 +9,7 @@ variables:
testsFolder: './_tests'
yarnCacheFolder: $(Pipeline.Workspace)/.yarn
nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages
majorVersion: '0.1.6'
majorVersion: '0.2.0'
minorVersion: $[counter('minorVersion', 1)]
readarrVersion: '$(majorVersion).$(minorVersion)'
buildName: '$(Build.SourceBranchName).$(readarrVersion)'
@@ -984,7 +984,7 @@ stages:
git status
if git status | grep modified
then
git commit -am 'Automated API Docs update'
git commit -am 'Automated API Docs update [skip ci]'
git push -f --set-upstream origin api-docs
curl -X POST -H "Authorization: token ${GITHUBTOKEN}" -H "Accept: application/vnd.github.v3+json" https://api.github.com/repos/readarr/readarr/pulls -d '{"head":"api-docs","base":"develop","title":"Update API docs"}'
else

View File

@@ -1,5 +1,6 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import ConfirmModal from 'Components/Modal/ConfirmModal';
import PageContent from 'Components/Page/PageContent';
@@ -161,16 +162,16 @@ class Blocklist extends Component {
{
!isAnyFetching && !!error &&
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadBlocklist')}
</div>
</Alert>
}
{
isAllPopulated && !error && !items.length &&
<div>
<Alert kind={kinds.INFO}>
{translate('NoHistoryBlocklist')}
</div>
</Alert>
}
{
@@ -214,7 +215,7 @@ class Blocklist extends Component {
isOpen={isConfirmRemoveModalOpen}
kind={kinds.DANGER}
title={translate('RemoveSelected')}
message={translate('RemoveSelectedMessageText')}
message={translate('RemoveSelectedItemBlocklistMessageText')}
confirmLabel={translate('RemoveSelected')}
onConfirm={this.onRemoveSelectedConfirmed}
onCancel={this.onConfirmRemoveModalClose}

View File

@@ -1,5 +1,6 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import FilterMenu from 'Components/Menu/FilterMenu';
import PageContent from 'Components/Page/PageContent';
@@ -11,7 +12,7 @@ import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody';
import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper';
import TablePager from 'Components/Table/TablePager';
import { align, icons } from 'Helpers/Props';
import { align, icons, kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import HistoryRowConnector from './HistoryRowConnector';
@@ -85,9 +86,9 @@ class History extends Component {
{
!isFetchingAny && hasError &&
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadHistory')}
</div>
</Alert>
}
{
@@ -95,9 +96,9 @@ class History extends Component {
// wait for the books to populate because they are never coming.
isPopulated && !hasError && !items.length &&
<div>
No history found
</div>
<Alert kind={kinds.INFO}>
{translate('NoHistory')}
</Alert>
}
{

View File

@@ -1,6 +1,7 @@
import _ from 'lodash';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import PageContent from 'Components/Page/PageContent';
import PageContentBody from 'Components/Page/PageContentBody';
@@ -12,7 +13,7 @@ import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody';
import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper';
import TablePager from 'Components/Table/TablePager';
import { align, icons } from 'Helpers/Props';
import { align, icons, kinds } from 'Helpers/Props';
import getRemovedItems from 'Utilities/Object/getRemovedItems';
import hasDifferentItems from 'Utilities/Object/hasDifferentItems';
import translate from 'Utilities/String/translate';
@@ -233,17 +234,17 @@ class Queue extends Component {
{
!isRefreshing && hasError ?
<div>
<Alert kind={kinds.DANGER}>
{translate('FailedToLoadQueue')}
</div> :
</Alert> :
null
}
{
isAllPopulated && !hasError && !items.length ?
<div>
<Alert kind={kinds.INFO}>
{translate('QueueIsEmpty')}
</div> :
</Alert> :
null
}

View File

@@ -89,12 +89,12 @@ class RemoveQueueItemsModal extends Component {
onModalClose={this.onModalClose}
>
<ModalHeader>
Remove Selected Item{selectedCount > 1 ? 's' : ''}
{selectedCount > 1 ? translate('RemoveSelectedItems') : translate('RemoveSelectedItem')}
</ModalHeader>
<ModalBody>
<div className={styles.message}>
Are you sure you want to remove {selectedCount} item{selectedCount > 1 ? 's' : ''} from the queue?
{selectedCount > 1 ? translate('RemoveSelectedItemsQueueMessageText', selectedCount) : translate('RemoveSelectedItemQueueMessageText')}
</div>
{
@@ -118,14 +118,14 @@ class RemoveQueueItemsModal extends Component {
<FormGroup>
<FormLabel>
Add Release{selectedCount > 1 ? 's' : ''} To Blocklist
{selectedCount > 1 ? translate('BlocklistReleases') : translate('BlocklistRelease')}
</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="blocklist"
value={blocklist}
helpText={translate('BlocklistHelpText')}
helpText={translate('BlocklistReleaseHelpText')}
onChange={this.onBlocklistChange}
/>
</FormGroup>
@@ -150,14 +150,14 @@ class RemoveQueueItemsModal extends Component {
<ModalFooter>
<Button onPress={this.onModalClose}>
Close
{translate('Close')}
</Button>
<Button
kind={kinds.DANGER}
onPress={this.onRemoveConfirmed}
>
Remove
{translate('Remove')}
</Button>
</ModalFooter>
</ModalContent>

View File

@@ -1,8 +1,10 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody';
import { kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import AuthorHistoryRowConnector from './AuthorHistoryRowConnector';
@@ -70,9 +72,9 @@ class AuthorHistoryTableContent extends Component {
{
!isFetching && !!error &&
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadHistory')}
</div>
</Alert>
}
{

View File

@@ -1,6 +1,8 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import { kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import AgendaConnector from './Agenda/AgendaConnector';
import * as calendarViews from './calendarViews';
@@ -31,9 +33,9 @@ class Calendar extends Component {
{
!isFetching && !!error &&
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadTheCalendar')}
</div>
</Alert>
}
{

View File

@@ -62,6 +62,7 @@ function ProviderFieldFormGroup(props) {
name,
label,
helpText,
helpTextWarning,
helpLink,
placeholder,
value,
@@ -95,6 +96,7 @@ function ProviderFieldFormGroup(props) {
name={name}
label={label}
helpText={helpText}
helpTextWarning={helpTextWarning}
helpLink={helpLink}
placeholder={placeholder}
value={value}
@@ -121,6 +123,7 @@ ProviderFieldFormGroup.propTypes = {
name: PropTypes.string.isRequired,
label: PropTypes.string.isRequired,
helpText: PropTypes.string,
helpTextWarning: PropTypes.string,
helpLink: PropTypes.string,
placeholder: PropTypes.string,
value: PropTypes.any,

View File

@@ -1,6 +1,8 @@
import PropTypes from 'prop-types';
import React from 'react';
import Alert from 'Components/Alert';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import { kinds } from 'Helpers/Props';
function PageSectionContent(props) {
const {
@@ -17,7 +19,7 @@ function PageSectionContent(props) {
);
} else if (!isFetching && !!error) {
return (
<div>{errorMessage}</div>
<Alert kind={kinds.DANGER}>{errorMessage}</Alert>
);
} else if (isPopulated && !error) {
return (

View File

@@ -16,6 +16,38 @@
box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
color: var(--white);
transition: width 0.6s ease;
&.primary {
background-color: var(--primaryColor);
}
&.danger {
background-color: var(--dangerColor);
&:global(.colorImpaired) {
background: repeating-linear-gradient(90deg, color(#f05050 shade(5%)), color(#f05050 shade(5%)) 5px, color(#f05050 shade(15%)) 5px, color(#f05050 shade(15%)) 10px);
}
}
&.success {
background-color: var(--successColor);
}
&.purple {
background-color: var(--purple);
}
&.warning {
background-color: var(--warningColor);
&:global(.colorImpaired) {
background: repeating-linear-gradient(45deg, #ffa500, #ffa500 5px, color(#ffa500 tint(15%)) 5px, color(#ffa500 tint(15%)) 10px);
}
}
&.info {
background-color: var(--infoColor);
}
}
.frontTextContainer {
@@ -45,38 +77,6 @@
cursor: default;
}
.primary {
background-color: var(--primaryColor);
}
.danger {
background-color: var(--dangerColor);
&:global(.colorImpaired) {
background: repeating-linear-gradient(90deg, color(#f05050 shade(5%)), color(#f05050 shade(5%)) 5px, color(#f05050 shade(15%)) 5px, color(#f05050 shade(15%)) 10px);
}
}
.success {
background-color: var(--successColor);
}
.purple {
background-color: var(--purple);
}
.warning {
background-color: var(--warningColor);
&:global(.colorImpaired) {
background: repeating-linear-gradient(45deg, #ffa500, #ffa500 5px, color(#ffa500 tint(15%)) 5px, color(#ffa500 tint(15%)) 10px);
}
}
.info {
background-color: var(--infoColor);
}
.small {
height: $progressBarSmallHeight;

View File

@@ -38,7 +38,7 @@ function ProgressBar(props) {
{
showText && width ?
<div
className={styles.backTextContainer}
className={classNames(styles.backTextContainer, styles[kind])}
style={{ width: actualWidth }}
>
<div className={styles.backText}>
@@ -67,7 +67,7 @@ function ProgressBar(props) {
{
showText ?
<div
className={styles.frontTextContainer}
className={classNames(styles.frontTextContainer, styles[kind])}
style={{ width: progressPercent }}
>
<div

View File

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

View File

@@ -1,5 +1,6 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import Form from 'Components/Form/Form';
import FormGroup from 'Components/Form/FormGroup';
import FormInputGroup from 'Components/Form/FormInputGroup';
@@ -92,9 +93,9 @@ class SelectQualityModalContent extends Component {
{
!isFetching && !!error &&
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadQualities')}
</div>
</Alert>
}
{

View File

@@ -7,3 +7,9 @@
.filteredMessage {
margin-top: 10px;
}
.blankpad {
padding-top: 10px;
padding-bottom: 10px;
padding-left: 2em;
}

View File

@@ -1,6 +1,7 @@
// This file is automatically generated.
// Please do not change this file!
interface CssExports {
'blankpad': string;
'filterMenuContainer': string;
'filteredMessage': string;
}

View File

@@ -104,7 +104,7 @@ function InteractiveSearch(props) {
{
!isFetching && error ?
<div>
<div className={styles.blankpad}>
Unable to load results for this book search. Try again later
</div> :
null
@@ -112,7 +112,7 @@ function InteractiveSearch(props) {
{
!isFetching && isPopulated && !totalReleasesCount ?
<div>
<div className={styles.blankpad}>
No results found
</div> :
null
@@ -120,7 +120,7 @@ function InteractiveSearch(props) {
{
!!totalReleasesCount && isPopulated && !items.length ?
<div>
<div className={styles.blankpad}>
All results are hidden by the applied filter
</div> :
null

View File

@@ -78,7 +78,7 @@ class Specification extends Component {
<IconButton
className={styles.cloneButton}
title={translate('Clone')}
title={translate('CloneCondition')}
name={icons.CLONE}
onPress={this.onCloneSpecificationPress}
/>
@@ -92,14 +92,14 @@ class Specification extends Component {
{
negate &&
<Label kind={kinds.DANGER}>
Negated
{translate('Negated')}
</Label>
}
{
required &&
<Label kind={kinds.SUCCESS}>
Required
{translate('Required')}
</Label>
}
</div>
@@ -114,8 +114,8 @@ class Specification extends Component {
<ConfirmModal
isOpen={this.state.isDeleteSpecificationModalOpen}
kind={kinds.DANGER}
title={translate('DeleteFormat')}
message={translate('DeleteFormatMessageText', [name])}
title={translate('DeleteCondition')}
message={translate('DeleteConditionMessageText', [name])}
confirmLabel={translate('Delete')}
onConfirm={this.onConfirmDeleteSpecification}
onCancel={this.onDeleteSpecificationModalClose}

View File

@@ -1,12 +1,13 @@
import PropTypes from 'prop-types';
import React from 'react';
import Alert from 'Components/Alert';
import FieldSet from 'Components/FieldSet';
import Form from 'Components/Form/Form';
import FormGroup from 'Components/Form/FormGroup';
import FormInputGroup from 'Components/Form/FormInputGroup';
import FormLabel from 'Components/Form/FormLabel';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import { inputTypes, sizes } from 'Helpers/Props';
import { inputTypes, kinds, sizes } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
function DownloadClientOptions(props) {
@@ -28,9 +29,9 @@ function DownloadClientOptions(props) {
{
!isFetching && error &&
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadDownloadClientOptions')}
</div>
</Alert>
}
{

View File

@@ -88,8 +88,8 @@ class RemotePathMapping extends Component {
<ConfirmModal
isOpen={this.state.isDeleteRemotePathMappingModalOpen}
kind={kinds.DANGER}
title={translate('DeleteDelayProfile')}
message={translate('DeleteDelayProfileMessageText')}
title={translate('DeleteRemotePathMapping')}
message={translate('DeleteRemotePathMappingMessageText')}
confirmLabel={translate('Delete')}
onConfirm={this.onConfirmDeleteRemotePathMapping}
onCancel={this.onDeleteRemotePathMappingModalClose}

View File

@@ -1,6 +1,7 @@
import _ from 'lodash';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import Form from 'Components/Form/Form';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import ConfirmModal from 'Components/Modal/ConfirmModal';
@@ -124,9 +125,9 @@ class GeneralSettings extends Component {
{
!isFetching && error &&
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadGeneralSettings')}
</div>
</Alert>
}
{

View File

@@ -1,12 +1,13 @@
import PropTypes from 'prop-types';
import React from 'react';
import Alert from 'Components/Alert';
import FieldSet from 'Components/FieldSet';
import Form from 'Components/Form/Form';
import FormGroup from 'Components/Form/FormGroup';
import FormInputGroup from 'Components/Form/FormInputGroup';
import FormLabel from 'Components/Form/FormLabel';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import { inputTypes } from 'Helpers/Props';
import { inputTypes, kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
function IndexerOptions(props) {
@@ -28,9 +29,9 @@ function IndexerOptions(props) {
{
!isFetching && error &&
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadIndexerOptions')}
</div>
</Alert>
}
{

View File

@@ -1,5 +1,6 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import FieldSet from 'Components/FieldSet';
import Form from 'Components/Form/Form';
import FormGroup from 'Components/Form/FormGroup';
@@ -8,7 +9,7 @@ import FormLabel from 'Components/Form/FormLabel';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import PageContent from 'Components/Page/PageContent';
import PageContentBody from 'Components/Page/PageContentBody';
import { inputTypes, sizes } from 'Helpers/Props';
import { inputTypes, kinds, sizes } from 'Helpers/Props';
import RemotePathMappingsConnector from 'Settings/DownloadClients/RemotePathMappings/RemotePathMappingsConnector';
import SettingsToolbarConnector from 'Settings/SettingsToolbarConnector';
import translate from 'Utilities/String/translate';
@@ -79,9 +80,9 @@ class MediaManagement extends Component {
{
!isFetching && error &&
<FieldSet legend={translate('NamingSettings')}>
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadMediaManagementSettings')}
</div>
</Alert>
</FieldSet>
}

View File

@@ -1,5 +1,6 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import FieldSet from 'Components/FieldSet';
import Form from 'Components/Form/Form';
import FormGroup from 'Components/Form/FormGroup';
@@ -7,7 +8,7 @@ import FormInputButton from 'Components/Form/FormInputButton';
import FormInputGroup from 'Components/Form/FormInputGroup';
import FormLabel from 'Components/Form/FormLabel';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import { inputTypes, sizes } from 'Helpers/Props';
import { inputTypes, kinds, sizes } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import NamingModal from './NamingModal';
import styles from './Naming.css';
@@ -118,9 +119,9 @@ class Naming extends Component {
{
!isFetching && error &&
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadNamingSettings')}
</div>
</Alert>
}
{

View File

@@ -1,12 +1,13 @@
import PropTypes from 'prop-types';
import React from 'react';
import Alert from 'Components/Alert';
import FieldSet from 'Components/FieldSet';
import Form from 'Components/Form/Form';
import FormGroup from 'Components/Form/FormGroup';
import FormInputGroup from 'Components/Form/FormInputGroup';
import FormLabel from 'Components/Form/FormLabel';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import { inputTypes } from 'Helpers/Props';
import { inputTypes, kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
const writeAudioTagOptions = [
@@ -41,9 +42,9 @@ function MetadataProvider(props) {
{
!isFetching && error &&
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadMetadataProviderSettings')}
</div>
</Alert>
}
{

View File

@@ -55,12 +55,12 @@ class ResetQualityDefinitionsModalContent extends Component {
onModalClose={onModalClose}
>
<ModalHeader>
Reset Quality Definitions
{translate('ResetQualityDefinitions')}
</ModalHeader>
<ModalBody>
<div className={styles.messageContainer}>
Are you sure you want to reset quality definitions?
{translate('ResetQualityDefinitionsMessageText')}
</div>
<FormGroup>
@@ -81,7 +81,7 @@ class ResetQualityDefinitionsModalContent extends Component {
<ModalFooter>
<Button onPress={onModalClose}>
Cancel
{translate('Cancel')}
</Button>
<Button
@@ -89,7 +89,7 @@ class ResetQualityDefinitionsModalContent extends Component {
onPress={this.onResetQualityDefinitionsConfirmed}
isDisabled={isResettingQualityDefinitions}
>
Reset
{translate('Reset')}
</Button>
</ModalFooter>
</ModalContent>

View File

@@ -1,5 +1,6 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import FieldSet from 'Components/FieldSet';
import Form from 'Components/Form/Form';
import FormGroup from 'Components/Form/FormGroup';
@@ -8,7 +9,7 @@ import FormLabel from 'Components/Form/FormLabel';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import PageContent from 'Components/Page/PageContent';
import PageContentBody from 'Components/Page/PageContentBody';
import { inputTypes } from 'Helpers/Props';
import { inputTypes, kinds } from 'Helpers/Props';
import SettingsToolbarConnector from 'Settings/SettingsToolbarConnector';
import themes from 'Styles/Themes';
import titleCase from 'Utilities/String/titleCase';
@@ -81,9 +82,9 @@ class UISettings extends Component {
{
!isFetching && error &&
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadUISettings')}
</div>
</Alert>
}
{

View File

@@ -32,9 +32,9 @@ function createSaveProviderHandler(section, url, options = {}, removeStale = fal
const params = { ...queryParams };
// If the user is re-saving the same provider without changes
// force it to be saved. Only applies to editing existing providers.
// force it to be saved.
if (id && _.isEqual(saveData, lastSaveData)) {
if (_.isEqual(saveData, lastSaveData)) {
params.forceSave = true;
}

View File

@@ -1,5 +1,6 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import PageContent from 'Components/Page/PageContent';
import PageContentBody from 'Components/Page/PageContentBody';
@@ -8,7 +9,7 @@ import PageToolbarButton from 'Components/Page/Toolbar/PageToolbarButton';
import PageToolbarSection from 'Components/Page/Toolbar/PageToolbarSection';
import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody';
import { icons } from 'Helpers/Props';
import { icons, kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import BackupRow from './BackupRow';
import RestoreBackupModalConnector from './RestoreBackupModalConnector';
@@ -107,16 +108,16 @@ class Backups extends Component {
{
!isFetching && !!error &&
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadBackups')}
</div>
</Alert>
}
{
noBackups &&
<div>
<Alert kind={kinds.INFO}>
{translate('NoBackupsAreAvailable')}
</div>
</Alert>
}
{

View File

@@ -30,6 +30,13 @@
<!-- A test project gets the test sdk packages automatically added -->
<TestProject>false</TestProject>
<TestProject Condition="$(MSBuildProjectName.EndsWith('.Test'))">true</TestProject>
<!-- XML documentation comments are needed to enforce rule IDE0005 on build -->
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<!--
CS1591: Missing XML comment for publicly visible type or member 'Type_or_Member'
-->
<NoWarn>$(NoWarn);CS1591</NoWarn>
</PropertyGroup>
<PropertyGroup>

View File

@@ -27,35 +27,36 @@ namespace NzbDrone.Api.Test.ClientSchemaTests
var schema = SchemaBuilder.ToSchema(model);
schema.Should().Contain(c =>
c.Order == 1 && c.Name == "lastName" && c.Label == "Last Name" && c.HelpText == "Your Last Name" &&
(string)c.Value == "Poop");
schema.Should().Contain(c =>
c.Order == 0 && c.Name == "firstName" && c.Label == "First Name" && c.HelpText == "Your First Name" &&
(string)c.Value == "Bob");
schema.Should().Contain(c => c.Order == 1 && c.Name == "lastName" && c.Label == "Last Name" && c.HelpText == "Your Last Name" && c.HelpTextWarning == "Mandatory Last Name" && (string)c.Value == "Poop");
schema.Should().Contain(c => c.Order == 0 && c.Name == "firstName" && c.Label == "First Name" && c.HelpText == "Your First Name" && c.HelpTextWarning == "Mandatory First Name" && (string)c.Value == "Bob");
}
[Test]
public void schema_should_have_nested_fields()
{
var model = new NestedTestModel();
model.Name.FirstName = "Bob";
model.Name.LastName = "Poop";
var model = new NestedTestModel
{
Name =
{
FirstName = "Bob",
LastName = "Poop"
}
};
var schema = SchemaBuilder.ToSchema(model);
schema.Should().Contain(c => c.Order == 0 && c.Name == "name.firstName" && c.Label == "First Name" && c.HelpText == "Your First Name" && (string)c.Value == "Bob");
schema.Should().Contain(c => c.Order == 1 && c.Name == "name.lastName" && c.Label == "Last Name" && c.HelpText == "Your Last Name" && (string)c.Value == "Poop");
schema.Should().Contain(c => c.Order == 0 && c.Name == "name.firstName" && c.Label == "First Name" && c.HelpText == "Your First Name" && c.HelpTextWarning == "Mandatory First Name" && (string)c.Value == "Bob");
schema.Should().Contain(c => c.Order == 1 && c.Name == "name.lastName" && c.Label == "Last Name" && c.HelpText == "Your Last Name" && c.HelpTextWarning == "Mandatory Last Name" && (string)c.Value == "Poop");
schema.Should().Contain(c => c.Order == 2 && c.Name == "quote" && c.Label == "Quote" && c.HelpText == "Your Favorite Quote");
}
}
public class TestModel
{
[FieldDefinition(0, Label = "First Name", HelpText = "Your First Name")]
[FieldDefinition(0, Label = "First Name", HelpText = "Your First Name", HelpTextWarning = "Mandatory First Name")]
public string FirstName { get; set; }
[FieldDefinition(1, Label = "Last Name", HelpText = "Your Last Name")]
[FieldDefinition(1, Label = "Last Name", HelpText = "Your Last Name", HelpTextWarning = "Mandatory Last Name")]
public string LastName { get; set; }
public string Other { get; set; }

View File

@@ -68,7 +68,7 @@ namespace NzbDrone.Automation.Test
{
try
{
Screenshot image = ((ITakesScreenshot)driver).GetScreenshot();
var image = ((ITakesScreenshot)driver).GetScreenshot();
image.SaveAsFile($"./{name}_test_screenshot.png", ScreenshotImageFormat.Png);
}
catch (Exception ex)

View File

@@ -37,7 +37,7 @@ namespace NzbDrone.Automation.Test.PageModel
{
try
{
IWebElement element = d.FindElement(By.ClassName("followingBalls"));
var element = d.FindElement(By.ClassName("followingBalls"));
return !element.Displayed;
}
catch (NoSuchElementException)

View File

@@ -65,9 +65,9 @@ namespace NzbDrone.Common.Test.CacheTests
[Test]
public void should_store_null()
{
int hitCount = 0;
var hitCount = 0;
for (int i = 0; i < 10; i++)
for (var i = 0; i < 10; i++)
{
_cachedString.Get("key", () =>
{
@@ -83,10 +83,10 @@ namespace NzbDrone.Common.Test.CacheTests
[Platform(Exclude = "MacOsX")]
public void should_honor_ttl()
{
int hitCount = 0;
var hitCount = 0;
_cachedString = new Cached<string>();
for (int i = 0; i < 10; i++)
for (var i = 0; i < 10; i++)
{
_cachedString.Get("key",
() =>
@@ -107,10 +107,10 @@ namespace NzbDrone.Common.Test.CacheTests
[Platform(Exclude = "MacOsX")]
public void should_clear_expired_when_they_expire()
{
int hitCount = 0;
var hitCount = 0;
_cachedString = new Cached<string>(rollingExpiry: true);
for (int i = 0; i < 10; i++)
for (var i = 0; i < 10; i++)
{
_cachedString.Get("key",
() =>

View File

@@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using FluentAssertions;
using Moq;
using NUnit.Framework;
@@ -142,7 +142,7 @@ namespace NzbDrone.Common.Test
[Test]
public void SaveDictionary_should_save_proper_value()
{
int port = 20555;
var port = 20555;
var dic = Subject.GetConfigDictionary();
dic["Port"] = 20555;
@@ -155,9 +155,9 @@ namespace NzbDrone.Common.Test
[Test]
public void SaveDictionary_should_only_save_specified_values()
{
int port = 20555;
int origSslPort = 20551;
int sslPort = 20552;
var port = 20555;
var origSslPort = 20551;
var sslPort = 20552;
var dic = Subject.GetConfigDictionary();
dic["Port"] = port;

View File

@@ -43,7 +43,7 @@ namespace NzbDrone.Common.Test.DiskTests
[Test]
public void should_not_contain_recycling_bin_for_root_of_drive()
{
string root = @"C:\".AsOsAgnostic();
var root = @"C:\".AsOsAgnostic();
SetupFolders(root);
Mocker.GetMock<IDiskProvider>()
@@ -56,7 +56,7 @@ namespace NzbDrone.Common.Test.DiskTests
[Test]
public void should_not_contain_system_volume_information()
{
string root = @"C:\".AsOsAgnostic();
var root = @"C:\".AsOsAgnostic();
SetupFolders(root);
Mocker.GetMock<IDiskProvider>()
@@ -69,7 +69,7 @@ namespace NzbDrone.Common.Test.DiskTests
[Test]
public void should_not_contain_recycling_bin_or_system_volume_information_for_root_of_drive()
{
string root = @"C:\".AsOsAgnostic();
var root = @"C:\".AsOsAgnostic();
SetupFolders(root);
Mocker.GetMock<IDiskProvider>()

View File

@@ -791,7 +791,7 @@ namespace NzbDrone.Common.Test.Http
try
{
// the date is bad in the below - should be 13-Jul-2026
string malformedCookie = @"__cfduid=d29e686a9d65800021c66faca0a29b4261436890790; expires=Mon, 13-Jul-26 16:19:50 GMT; path=/; HttpOnly";
var malformedCookie = @"__cfduid=d29e686a9d65800021c66faca0a29b4261436890790; expires=Mon, 13-Jul-26 16:19:50 GMT; path=/; HttpOnly";
var requestSet = new HttpRequestBuilder($"https://{_httpBinHost}/response-headers")
.AddQueryParam("Set-Cookie", malformedCookie)
.Build();
@@ -825,7 +825,7 @@ namespace NzbDrone.Common.Test.Http
{
try
{
string url = $"https://{_httpBinHost}/response-headers?Set-Cookie={Uri.EscapeDataString(malformedCookie)}";
var url = $"https://{_httpBinHost}/response-headers?Set-Cookie={Uri.EscapeDataString(malformedCookie)}";
var requestSet = new HttpRequest(url);
requestSet.AllowAutoRedirect = false;

View File

@@ -10,7 +10,9 @@ namespace NzbDrone.Common.Test.InstrumentationTests
// Indexer Urls
[TestCase(@"https://iptorrents.com/torrents/rss?u=mySecret;tp=mySecret;l5;download")]
[TestCase(@"http://rss.torrentleech.org/mySecret")]
[TestCase(@"http://rss.torrentleech.org/rss/download/12345/01233210/filename.torrent")]
[TestCase(@"https://rss24h.torrentleech.org/mySecret")]
[TestCase(@"http://rss.torrentleech.org/rss/download/12345/01233210/file.name-RLSGRP.torrent")]
[TestCase(@"https://www.torrentleech.org/rss/download/12345/01233210/file.name-RLSGRP.torrent")]
[TestCase(@"http://www.bitmetv.org/rss.php?uid=mySecret&passkey=mySecret")]
[TestCase(@"https://rss.omgwtfnzbs.org/rss-search.php?catid=19,20&user=Readarr&api=mySecret&eng=1")]
[TestCase(@"https://dognzb.cr/fetch/2b51db35e1912ffc138825a12b9933d2/2b51db35e1910123321025a12b9933d2")]
@@ -44,6 +46,7 @@ namespace NzbDrone.Common.Test.InstrumentationTests
// Deluge
[TestCase(@",{""download_location"": ""C:\Users\\mySecret mySecret\\Downloads""}")]
[TestCase(@",{""download_location"": ""/home/mySecret/Downloads""}")]
[TestCase(@",{""download_location"": ""/Users/mySecret/Downloads""}")]
[TestCase(@"auth.login(""mySecret"")")]
// Download Station
@@ -56,8 +59,11 @@ namespace NzbDrone.Common.Test.InstrumentationTests
// Internal
[TestCase(@"OutputPath=/home/mySecret/Downloads")]
[TestCase(@"OutputPath=/Users/mySecret/Downloads")]
[TestCase("Hardlinking episode file: /home/mySecret/Downloads to /media/abc.mkv")]
[TestCase("Hardlinking episode file: /Users/mySecret/Downloads to /media/abc.mkv")]
[TestCase("Hardlink '/home/mySecret/Downloads/abs.mkv' to '/media/abc.mkv' failed.")]
[TestCase("Hardlink '/Users/mySecret/Downloads/abs.mkv' to '/media/abc.mkv' failed.")]
[TestCase("https://notifiarr.com/notifier.php: api=1234530f-422f-4aac-b6b3-01233210aaaa&radarr_health_issue_message=Download")]
[TestCase("/readarr/signalr/messages/negotiate?access_token=1234530f422f4aacb6b301233210aaaa&negotiateVersion=1")]
[TestCase(@"[Info] MigrationController: *** Migrating Database=readarr-main;Host=postgres14;Username=mySecret;Password=mySecret;Port=5432;Enlist=False ***")]

View File

@@ -74,17 +74,17 @@ namespace NzbDrone.Common
continue; // Ignore directories
}
string entryFileName = zipEntry.Name;
var entryFileName = zipEntry.Name;
// to remove the folder from the entry:- entryFileName = Path.GetFileName(entryFileName);
// Optionally match entrynames against a selection list here to skip as desired.
// The unpacked length is available in the zipEntry.Size property.
byte[] buffer = new byte[4096]; // 4K is optimum
Stream zipStream = zipFile.GetInputStream(zipEntry);
var buffer = new byte[4096]; // 4K is optimum
var zipStream = zipFile.GetInputStream(zipEntry);
// Manipulate the output filename here as desired.
string fullZipToPath = Path.Combine(destination, entryFileName);
string directoryName = Path.GetDirectoryName(fullZipToPath);
var fullZipToPath = Path.Combine(destination, entryFileName);
var directoryName = Path.GetDirectoryName(fullZipToPath);
if (directoryName.Length > 0)
{
Directory.CreateDirectory(directoryName);
@@ -93,7 +93,7 @@ namespace NzbDrone.Common
// Unzip file in buffered chunks. This is just as fast as unpacking to a buffer the full size
// of the file, but does not waste memory.
// The "using" will close the stream even if an exception occurs.
using (FileStream streamWriter = File.Create(fullZipToPath))
using (var streamWriter = File.Create(fullZipToPath))
{
StreamUtils.Copy(zipStream, streamWriter, buffer);
}
@@ -106,7 +106,7 @@ namespace NzbDrone.Common
Stream inStream = File.OpenRead(compressedFile);
Stream gzipStream = new GZipInputStream(inStream);
TarArchive tarArchive = TarArchive.CreateInputTarArchive(gzipStream, null);
var tarArchive = TarArchive.CreateInputTarArchive(gzipStream, null);
tarArchive.ExtractContents(destination);
tarArchive.Close();

View File

@@ -54,8 +54,7 @@ namespace NzbDrone.Common.Cache
public T Find(string key)
{
CacheItem cacheItem;
if (!_store.TryGetValue(key, out cacheItem))
if (!_store.TryGetValue(key, out var cacheItem))
{
return default(T);
}
@@ -84,8 +83,7 @@ namespace NzbDrone.Common.Cache
public void Remove(string key)
{
CacheItem value;
_store.TryRemove(key, out value);
_store.TryRemove(key, out _);
}
public int Count => _store.Count;
@@ -96,9 +94,7 @@ namespace NzbDrone.Common.Cache
lifeTime = lifeTime ?? _defaultLifeTime;
CacheItem cacheItem;
if (_store.TryGetValue(key, out cacheItem) && !cacheItem.IsExpired())
if (_store.TryGetValue(key, out var cacheItem) && !cacheItem.IsExpired())
{
if (_rollingExpiry && lifeTime.HasValue)
{

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
@@ -86,9 +86,7 @@ namespace NzbDrone.Common.Cache
{
RefreshIfExpired();
TValue result;
if (!_items.TryGetValue(key, out result))
if (!_items.TryGetValue(key, out var result))
{
throw new KeyNotFoundException(string.Format("Item {0} not found in cache.", key));
}
@@ -100,9 +98,7 @@ namespace NzbDrone.Common.Cache
{
RefreshIfExpired();
TValue result;
_items.TryGetValue(key, out result);
_items.TryGetValue(key, out var result);
return result;
}
@@ -128,8 +124,7 @@ namespace NzbDrone.Common.Cache
public void Remove(string key)
{
TValue item;
_items.TryRemove(key, out item);
_items.TryRemove(key, out _);
}
}
}

View File

@@ -1,4 +1,4 @@
namespace NzbDrone.Common
namespace NzbDrone.Common
{
public static class ConvertBase32
{
@@ -6,17 +6,17 @@
public static byte[] FromBase32String(string str)
{
int numBytes = str.Length * 5 / 8;
byte[] bytes = new byte[numBytes];
var numBytes = str.Length * 5 / 8;
var bytes = new byte[numBytes];
// all UPPERCASE chars
str = str.ToUpper();
int bitBuffer = 0;
int bitBufferCount = 0;
int index = 0;
var bitBuffer = 0;
var bitBufferCount = 0;
var index = 0;
for (int i = 0; i < str.Length; i++)
for (var i = 0; i < str.Length; i++)
{
bitBuffer = (bitBuffer << 5) | ValidChars.IndexOf(str[i]);
bitBufferCount += 5;

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using NzbDrone.Common.Extensions;
@@ -255,7 +255,7 @@ namespace NzbDrone.Common.Disk
var stringComparison = (Kind == OsPathKind.Windows || other.Kind == OsPathKind.Windows) ? StringComparison.InvariantCultureIgnoreCase : StringComparison.InvariantCulture;
for (int i = 0; i < leftFragments.Length; i++)
for (var i = 0; i < leftFragments.Length; i++)
{
if (!string.Equals(leftFragments[i], rightFragments[i], stringComparison))
{
@@ -372,12 +372,12 @@ namespace NzbDrone.Common.Disk
var newFragments = new List<string>();
for (int j = i; j < rightFragments.Length; j++)
for (var j = i; j < rightFragments.Length; j++)
{
newFragments.Add("..");
}
for (int j = i; j < leftFragments.Length; j++)
for (var j = i; j < leftFragments.Length; j++)
{
newFragments.Add(leftFragments[j]);
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
@@ -107,7 +107,7 @@ namespace NzbDrone.Common.EnvironmentInfo
private static string RunAndCapture(string filename, string args)
{
Process p = new Process();
var p = new Process();
p.StartInfo.FileName = filename;
p.StartInfo.Arguments = args;
p.StartInfo.UseShellExecute = false;
@@ -117,7 +117,7 @@ namespace NzbDrone.Common.EnvironmentInfo
p.Start();
// To avoid deadlocks, always read the output stream first and then wait.
string output = p.StandardOutput.ReadToEnd();
var output = p.StandardOutput.ReadToEnd();
p.WaitForExit(1000);
return output;

View File

@@ -356,34 +356,34 @@ namespace NzbDrone.Common.Extensions
}
/**
* Computes the highest row in which the distance {@code p} appears
* in diagonal {@code k} of the edit distance computation for
* strings {@code a} and {@code b}. The diagonal number is
* represented by the difference in the indices for the two strings;
* it can range from {@code -b.length()} through {@code a.length()}.
*
* More precisely, this computes the highest value x such that
* <pre>
* p = edit-distance(a[0:(x+k)), b[0:x)).
* </pre>
*
* This is the "f" function described by Ukkonen.
*
* The caller must assure that abs(k) &le; p, the only values for
* which this is well-defined.
*
* The implementation depends on the cached results of prior
* computeRow calls for diagonals k-1, k, and k+1 for distance p-1.
* These must be supplied in {@code knownLeft}, {@code knownAbove},
* and {@code knownRight}, respectively.
* @param k diagonal number
* @param p edit distance
* @param a one string to be compared
* @param b other string to be compared
* @param knownLeft value of {@code computeRow(k-1, p-1, ...)}
* @param knownAbove value of {@code computeRow(k, p-1, ...)}
* @param knownRight value of {@code computeRow(k+1, p-1, ...)}
*/
* Computes the highest row in which the distance {@code p} appears
* in diagonal {@code k} of the edit distance computation for
* strings {@code a} and {@code b}. The diagonal number is
* represented by the difference in the indices for the two strings;
* it can range from {@code -b.length()} through {@code a.length()}.
*
* More precisely, this computes the highest value x such that
* <pre>
* p = edit-distance(a[0:(x+k)), b[0:x)).
* </pre>
*
* This is the "f" function described by Ukkonen.
*
* The caller must assure that abs(k) &#x2264; p, the only values for
* which this is well-defined.
*
* The implementation depends on the cached results of prior
* computeRow calls for diagonals k-1, k, and k+1 for distance p-1.
* These must be supplied in {@code knownLeft}, {@code knownAbove},
* and {@code knownRight}, respectively.
* @param k diagonal number
* @param p edit distance
* @param a one string to be compared
* @param b other string to be compared
* @param knownLeft value of {@code computeRow(k-1, p-1, ...)}
* @param knownAbove value of {@code computeRow(k, p-1, ...)}
* @param knownRight value of {@code computeRow(k+1, p-1, ...)}
*/
private static int ComputeRow(int k,
int p,
char[] a,

View File

@@ -136,7 +136,7 @@ namespace NzbDrone.Common.Extensions
for (var j = finish; j >= start; j--)
{
T charMatch = charMatches[j - 1];
var charMatch = charMatches[j - 1];
if (d == 0)
{
@@ -181,7 +181,7 @@ namespace NzbDrone.Common.Extensions
// match. But check anyway.
var score = BitapScore(d, pattern);
bool isOnWordBoundary = true;
var isOnWordBoundary = true;
if (wordDelimiters != null)
{
@@ -233,8 +233,8 @@ namespace NzbDrone.Common.Extensions
return new List<char>();
}
char curr = text[j - 1];
bool take = true;
var curr = text[j - 1];
var take = true;
if (!s.TryGetValue(curr, out var charMatch))
{

View File

@@ -255,13 +255,13 @@ namespace NzbDrone.Common.Extensions
var firstPath = paths.First();
var length = firstPath.Length;
for (int i = 1; i < paths.Count; i++)
for (var i = 1; i < paths.Count; i++)
{
var path = paths[i];
length = Math.Min(length, path.Length);
for (int characterIndex = 0; characterIndex < length; characterIndex++)
for (var characterIndex = 0; characterIndex < length; characterIndex++)
{
if (path[characterIndex] != firstPath[characterIndex])
{

View File

@@ -188,11 +188,11 @@ namespace NzbDrone.Common.Extensions
{
double weightDenom = Math.Max(a.Length, b.Length);
double sum = 0;
for (int i = 0; i < a.Length; i++)
for (var i = 0; i < a.Length; i++)
{
double high = 0.0;
int indexDistance = 0;
for (int x = 0; x < b.Length; x++)
var high = 0.0;
var indexDistance = 0;
for (var x = 0; x < b.Length; x++)
{
var coef = LevenshteinCoefficient(a[i], b[x]);
if (coef > high)

View File

@@ -6,9 +6,7 @@ namespace NzbDrone.Common.Extensions
{
public static int? ParseInt32(this string source)
{
int result;
if (int.TryParse(source, out result))
if (int.TryParse(source, out var result))
{
return result;
}
@@ -18,9 +16,7 @@ namespace NzbDrone.Common.Extensions
public static long? ParseInt64(this string source)
{
long result;
if (long.TryParse(source, out result))
if (long.TryParse(source, out var result))
{
return result;
}
@@ -30,9 +26,7 @@ namespace NzbDrone.Common.Extensions
public static double? ParseDouble(this string source)
{
double result;
if (double.TryParse(source.Replace(',', '.'), NumberStyles.Number, CultureInfo.InvariantCulture, out result))
if (double.TryParse(source.Replace(',', '.'), NumberStyles.Number, CultureInfo.InvariantCulture, out var result))
{
return result;
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Text;
namespace NzbDrone.Common
@@ -7,9 +7,9 @@ namespace NzbDrone.Common
{
public static string CalculateCrc(string input)
{
uint mCrc = 0xffffffff;
byte[] bytes = Encoding.UTF8.GetBytes(input);
foreach (byte myByte in bytes)
var mCrc = 0xffffffff;
var bytes = Encoding.UTF8.GetBytes(input);
foreach (var myByte in bytes)
{
mCrc ^= (uint)myByte << 24;
for (var i = 0; i < 8; i++)

View File

@@ -60,8 +60,7 @@ namespace NzbDrone.Common.Http
if (request.AllowAutoRedirect && response.HasHttpRedirect)
{
var autoRedirectChain = new List<string>();
autoRedirectChain.Add(request.Url.ToString());
var autoRedirectChain = new List<string> { request.Url.ToString() };
do
{
@@ -75,6 +74,14 @@ namespace NzbDrone.Common.Http
throw new WebException($"Too many automatic redirections were attempted for {autoRedirectChain.Join(" -> ")}", WebExceptionStatus.ProtocolError);
}
// 302 or 303 should default to GET on redirect even if POST on original
if (RequestRequiresForceGet(response.StatusCode, response.Request.Method))
{
request.Method = HttpMethod.Get;
request.ContentData = null;
request.ContentSummary = null;
}
response = ExecuteRequest(request, cookieContainer);
}
while (response.HasHttpRedirect);
@@ -105,6 +112,16 @@ namespace NzbDrone.Common.Http
return response;
}
private static bool RequestRequiresForceGet(HttpStatusCode statusCode, HttpMethod requestMethod)
{
return statusCode switch
{
HttpStatusCode.Moved or HttpStatusCode.Found or HttpStatusCode.MultipleChoices => requestMethod == HttpMethod.Post,
HttpStatusCode.SeeOther => requestMethod != HttpMethod.Get && requestMethod != HttpMethod.Head,
_ => false,
};
}
private HttpResponse ExecuteRequest(HttpRequest request, CookieContainer cookieContainer)
{
foreach (var interceptor in _requestInterceptors)

View File

@@ -50,6 +50,8 @@ namespace NzbDrone.Common.Http
public bool HasHttpError => (int)StatusCode >= 400;
public bool HasHttpServerError => (int)StatusCode >= 500;
public bool HasHttpRedirect => StatusCode == HttpStatusCode.Moved ||
StatusCode == HttpStatusCode.MovedPermanently ||
StatusCode == HttpStatusCode.Found ||

View File

@@ -22,7 +22,7 @@ namespace NzbDrone.Common.Http
public HttpUri(string scheme, string host, int? port, string path, string query, string fragment)
{
StringBuilder builder = new StringBuilder();
var builder = new StringBuilder();
if (scheme.IsNotNullOrWhiteSpace())
{

View File

@@ -1,4 +1,4 @@
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Extensions;
namespace NzbDrone.Common.Http.Proxy
{
@@ -30,7 +30,7 @@ namespace NzbDrone.Common.Http.Proxy
if (!string.IsNullOrWhiteSpace(BypassFilter))
{
var hostlist = BypassFilter.Split(',');
for (int i = 0; i < hostlist.Length; i++)
for (var i = 0; i < hostlist.Length; i++)
{
if (hostlist[i].StartsWith("*"))
{

View File

@@ -12,14 +12,12 @@ namespace NzbDrone.Common.Http
if (response.Headers.ContainsKey("Retry-After"))
{
var retryAfter = response.Headers["Retry-After"].ToString();
int seconds;
DateTime date;
if (int.TryParse(retryAfter, out seconds))
if (int.TryParse(retryAfter, out var seconds))
{
RetryAfter = TimeSpan.FromSeconds(seconds);
}
else if (DateTime.TryParse(retryAfter, out date))
else if (DateTime.TryParse(retryAfter, out var date))
{
RetryAfter = date.ToUniversalTime() - DateTime.UtcNow;
}

View File

@@ -7,56 +7,56 @@ namespace NzbDrone.Common.Instrumentation
{
public class CleanseLogMessage
{
private static readonly Regex[] CleansingRules = new[]
{
// Url
new Regex(@"(?<=\?|&|: )((?:api|auth|pass)?key|(?:access[-_]?)?token|auth|user|uid|api|[a-z_]*apikey|account|passwd)=(?<secret>[^&=""]+?)(?=[ ""&=]|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"(?<=\?|&)[^=]*?(username|password)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"torrentleech\.org/(?!rss)(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"torrentleech\.org/rss/download/[0-9]+/(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"iptorrents\.com/[/a-z0-9?&;]*?(?:[?&;](u|tp)=(?<secret>[^&=;]+?))+(?= |;|&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"/fetch/[a-z0-9]{32}/(?<secret>[a-z0-9]{32})", RegexOptions.Compiled),
new Regex(@"getnzb.*?(?<=\?|&)(r)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"\b(\w*)?(_?(?<!use|get_)token|username|passwo?rd)=(?<secret>[^&=]+?)(?= |&|$|;)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
private static readonly Regex[] CleansingRules =
{
// Url
new (@"(?<=\?|&|: )((?:api|auth|pass)?key|(?:access[-_]?)?token|auth|user|uid|api|[a-z_]*apikey|account|passwd)=(?<secret>[^&=""]+?)(?=[ ""&=]|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new (@"(?<=\?|&)[^=]*?(username|password)=(?<secret>[^&=]+?)(?= |&|$)", 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 (@"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 (@"getnzb.*?(?<=\?|&)(r)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new (@"\b(\w*)?(_?(?<!use|get_)token|username|passwo?rd)=(?<secret>[^&=]+?)(?= |&|$|;)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// Trackers Announce Keys; Designed for Qbit Json; should work for all in theory
new Regex(@"announce(\.php)?(/|%2f|%3fpasskey%3d)(?<secret>[a-z0-9]{16,})|(?<secret>[a-z0-9]{16,})(/|%2f)announce"),
// 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"),
// Path
new Regex(@"C:\\Users\\(?<secret>[^\""]+?)(\\|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"/home/(?<secret>[^/""]+?)(/|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// Path
new (@"C:\\Users\\(?<secret>[^\""]+?)(\\|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new (@"/(home|Users)/(?<secret>[^/""]+?)(/|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// NzbGet
new Regex(@"""Name""\s*:\s*""[^""]*(username|password)""\s*,\s*""Value""\s*:\s*""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// NzbGet
new (@"""Name""\s*:\s*""[^""]*(username|password)""\s*,\s*""Value""\s*:\s*""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// Sabnzbd
new Regex(@"""[^""]*(username|password|api_?key|nzb_key)""\s*:\s*""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"""email_(account|to|from|pwd)""\s*:\s*""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// Sabnzbd
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),
// uTorrent
new Regex(@"\[""[a-z._]*(username|password)"",\d,""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"\[""(boss_key|boss_key_salt|proxy\.proxy)"",\d,""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// uTorrent
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),
// Deluge
new Regex(@"auth.login\(""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// Deluge
new (@"auth.login\(""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// BroadcastheNet
new Regex(@"""?method""?\s*:\s*""(getTorrents)"",\s*""?params""?\s*:\s*\[\s*""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"getTorrents\(""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"(?<=\?|&)(authkey|torrent_pass)=(?<secret>[^&=]+?)(?=""|&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// BroadcastheNet
new (@"""?method""?\s*:\s*""(getTorrents)"",\s*""?params""?\s*:\s*\[\s*""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new (@"getTorrents\(""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new (@"(?<=\?|&)(authkey|torrent_pass)=(?<secret>[^&=]+?)(?=""|&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// Good Reads
new Regex(@"(?<=""(token|tokensecret)"":\s)""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// Good Reads
new (@"(?<=""(token|tokensecret)"":\s)""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// Webhooks
// Notifiarr
new Regex(@"api/v[0-9]/notification/readarr/(?<secret>[\w-]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// Webhooks
// Notifiarr
new (@"api/v[0-9]/notification/readarr/(?<secret>[\w-]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// Discord
new Regex(@"discord.com/api/webhooks/((?<secret>[\w-]+)/)?(?<secret>[\w-]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase)
};
// Discord
new (@"discord.com/api/webhooks/((?<secret>[\w-]+)/)?(?<secret>[\w-]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase)
};
private static readonly Regex CleanseRemoteIPRegex = new Regex(@"(?: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)
{
@@ -68,15 +68,15 @@ namespace NzbDrone.Common.Instrumentation
foreach (var regex in CleansingRules)
{
message = regex.Replace(message, m =>
{
var value = m.Value;
foreach (var capture in m.Groups["secret"].Captures.OfType<Capture>().Reverse())
{
var value = m.Value;
foreach (var capture in m.Groups["secret"].Captures.OfType<Capture>().Reverse())
{
value = value.Replace(capture.Index - m.Index, capture.Length, "(removed)");
}
value = value.Replace(capture.Index - m.Index, capture.Length, "(removed)");
}
return value;
});
return value;
});
}
message = CleanseRemoteIPRegex.Replace(message, CleanseRemoteIP);
@@ -87,7 +87,6 @@ namespace NzbDrone.Common.Instrumentation
private static string CleanseRemoteIP(Match match)
{
var group = match.Groups[1];
var valueAll = match.Value;
var valueIP = group.Value;
if (IPAddress.TryParse(valueIP, out var address) && !address.IsLocalAddress())

View File

@@ -1,4 +1,4 @@
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Linq;
using NzbDrone.Common.Serializer;
namespace NzbDrone.Common.Instrumentation
@@ -16,7 +16,7 @@ namespace NzbDrone.Common.Instrumentation
}
}
foreach (JToken token in json)
foreach (var token in json)
{
Visit(token);
}

View File

@@ -94,7 +94,7 @@ namespace NzbDrone.Common.Instrumentation
private static void RegisterDebugger()
{
DebuggerTarget target = new DebuggerTarget();
var target = new DebuggerTarget();
target.Name = "debuggerLogger";
target.Layout = "[${level}] [${threadid}] ${logger}: ${message} ${onexception:inner=${newline}${newline}[v${assembly-version}] ${exception:format=ToString}${newline}${exception:format=Data}${newline}}";
@@ -107,9 +107,10 @@ namespace NzbDrone.Common.Instrumentation
{
LogManager.Setup().LoadConfiguration(c =>
{
c.ForLogger("System.*").WriteToNil(LogLevel.Warn);
c.ForLogger("Microsoft.*").WriteToNil(LogLevel.Warn);
c.ForLogger("Microsoft.Hosting.Lifetime*").WriteToNil(LogLevel.Info);
c.ForLogger("System*").WriteToNil(LogLevel.Warn);
c.ForLogger("Microsoft*").WriteToNil(LogLevel.Warn);
c.ForLogger("Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware").WriteToNil(LogLevel.Fatal);
});
}

View File

@@ -29,7 +29,7 @@ namespace NzbDrone.Common.OAuth
public virtual string Version { get; set; }
public virtual string SessionHandle { get; set; }
/// <seealso cref="http://oauth.net/core/1.0#request_urls"/>
/// <seealso href="http://oauth.net/core/1.0#request_urls"/>
public virtual string RequestUrl { get; set; }
public virtual Dictionary<string, string> Parameters { get; set; }

View File

@@ -1,4 +1,4 @@
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Linq;
namespace NzbDrone.Common.Serializer
{
@@ -60,7 +60,7 @@ namespace NzbDrone.Common.Serializer
public virtual void Visit(JArray json)
{
foreach (JToken token in json)
foreach (var token in json)
{
Visit(token);
}
@@ -72,7 +72,7 @@ namespace NzbDrone.Common.Serializer
public virtual void Visit(JObject json)
{
foreach (JProperty property in json.Properties())
foreach (var property in json.Properties())
{
Visit(property);
}

View File

@@ -42,7 +42,7 @@ namespace NzbDrone.Common.Serializer
var enumText = value.ToString();
var builder = new StringBuilder(enumText.Length + 4);
builder.Append(char.ToLower(enumText[0]));
for (int i = 1; i < enumText.Length; i++)
for (var i = 1; i < enumText.Length; i++)
{
if (char.IsUpper(enumText[i]))
{

View File

@@ -18,7 +18,7 @@ namespace NzbDrone.Common.Serializer
{
try
{
Version v = new Version(reader.GetString());
var v = new Version(reader.GetString());
return v;
}
catch (Exception)

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
@@ -137,7 +137,7 @@ namespace NzbDrone.Common.TPL
/// <returns>An enumerable of the tasks currently scheduled.</returns>
protected sealed override IEnumerable<Task> GetScheduledTasks()
{
bool lockTaken = false;
var lockTaken = false;
try
{
Monitor.TryEnter(_tasks, ref lockTaken);

View File

@@ -110,7 +110,7 @@ namespace NzbDrone.Console
}
System.Console.WriteLine("Non-recoverable failure, waiting for user intervention...");
for (int i = 0; i < 3600; i++)
for (var i = 0; i < 3600; i++)
{
System.Threading.Thread.Sleep(1000);

View File

@@ -197,7 +197,7 @@ namespace NzbDrone.Core.Test.Datastore
Subject.SetFields(_basicList, x => x.Interval);
for (int i = 0; i < _basicList.Count; i++)
for (var i = 0; i < _basicList.Count; i++)
{
_basicList[i].LastExecution = executionBackup[i];
}

View File

@@ -87,7 +87,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
[Test]
public void should_return_true_if_cutoffs_are_met_but_is_a_revision_upgrade()
{
QualityProfile profile = new QualityProfile
var profile = new QualityProfile
{
Cutoff = Quality.MP3.Id,
Items = Qualities.QualityFixture.GetDefaultQualities(),
@@ -104,7 +104,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
[Test]
public void should_return_false_if_quality_profile_does_not_allow_upgrades_but_cutoff_is_set_to_highest_quality()
{
QualityProfile profile = new QualityProfile
var profile = new QualityProfile
{
Cutoff = Quality.FLAC.Id,
Items = Qualities.QualityFixture.GetDefaultQualities(),

View File

@@ -83,7 +83,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole
VerifySingleItem(DownloadItemStatus.Downloading);
// If we keep changing the file every 20ms we should stay Downloading.
for (int i = 0; i < 10; i++)
for (var i = 0; i < 10; i++)
{
TestLogger.Info("Iteration {0}", i);

View File

@@ -225,6 +225,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests
[TestCase("checkingDL")]
[TestCase("checkingUP")]
[TestCase("metaDL")]
[TestCase("checkingResumeData")]
public void queued_item_should_have_required_properties(string state)
{
var torrent = new QBittorrentTorrent

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Text;
using FluentAssertions;
@@ -57,7 +57,7 @@ namespace NzbDrone.Core.Test
[Test]
public void ToBestDateTime_DayOfWeek()
{
for (int i = 2; i < 7; i++)
for (var i = 2; i < 7; i++)
{
var dateTime = DateTime.Today.AddDays(i);

View File

@@ -79,7 +79,7 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
[Test]
public void should_return_ok_if_not_downloading_to_root_folder()
{
string rootFolderPath = "c:\\Test2".AsOsAgnostic();
var rootFolderPath = "c:\\Test2".AsOsAgnostic();
GivenRootFolder(rootFolderPath);

View File

@@ -48,7 +48,7 @@ namespace NzbDrone.Core.Test.Instrumentation
public void write_long_log()
{
var message = string.Empty;
for (int i = 0; i < 100; i++)
for (var i = 0; i < 100; i++)
{
message += Guid.NewGuid();
}

View File

@@ -100,7 +100,7 @@ namespace NzbDrone.Core.Test.MediaFiles.BookImport.Aggregation.Aggregators
{
get
{
int i = 0;
var i = 0;
foreach (var tokens in tokenList)
{
@@ -128,7 +128,7 @@ namespace NzbDrone.Core.Test.MediaFiles.BookImport.Aggregation.Aggregators
private List<string> GivenFilenames(string[] fields, string fieldSeparator, string whitespace)
{
var outp = new List<string>();
for (int i = 1; i <= 3; i++)
for (var i = 1; i <= 3; i++)
{
var components = new List<string>();
foreach (var field in fields)
@@ -161,7 +161,7 @@ namespace NzbDrone.Core.Test.MediaFiles.BookImport.Aggregation.Aggregators
private void VerifyDataAuto(List<LocalBook> tracks, string[] tokens, string whitespace)
{
for (int i = 1; i <= tracks.Count; i++)
for (var i = 1; i <= tracks.Count; i++)
{
var info = tracks[i - 1].FileTrackInfo;

View File

@@ -71,7 +71,7 @@ namespace NzbDrone.Core.Test.MediaFiles.BookImport.Identification
Mocker.SetConstant<ICandidateService>(Mocker.Resolve<CandidateService>());
// set up the augmenters
List<IAggregate<LocalEdition>> aggregators = new List<IAggregate<LocalEdition>>
var aggregators = new List<IAggregate<LocalEdition>>
{
Mocker.Resolve<AggregateFilenameInfo>()
};
@@ -89,7 +89,7 @@ namespace NzbDrone.Core.Test.MediaFiles.BookImport.Identification
private List<Author> GivenAuthors(List<AuthorTestCase> authors)
{
var outp = new List<Author>();
for (int i = 0; i < authors.Count; i++)
for (var i = 0; i < authors.Count; i++)
{
var meta = authors[i].MetadataProfile;
meta.Id = i + 1;

View File

@@ -30,17 +30,17 @@ namespace NzbDrone.Core.Test.MediaFiles.BookImport.Identification
static RandomValueNamerShortStrings()
{
AllowedChars = new List<char>();
for (char c = 'a'; c < 'z'; c++)
for (var c = 'a'; c < 'z'; c++)
{
AllowedChars.Add(c);
}
for (char c = 'A'; c < 'Z'; c++)
for (var c = 'A'; c < 'Z'; c++)
{
AllowedChars.Add(c);
}
for (char c = '0'; c < '9'; c++)
for (var c = '0'; c < '9'; c++)
{
AllowedChars.Add(c);
}
@@ -48,17 +48,17 @@ namespace NzbDrone.Core.Test.MediaFiles.BookImport.Identification
protected override string GetString(MemberInfo memberInfo)
{
int length = _generator.Next(1, 100);
var length = _generator.Next(1, 100);
char[] chars = new char[length];
var chars = new char[length];
for (int i = 0; i < length; i++)
for (var i = 0; i < length; i++)
{
int index = _generator.Next(0, AllowedChars.Count - 1);
var index = _generator.Next(0, AllowedChars.Count - 1);
chars[i] = AllowedChars[index];
}
byte[] bytes = Encoding.UTF8.GetBytes(chars);
var bytes = Encoding.UTF8.GetBytes(chars);
return Encoding.UTF8.GetString(bytes, 0, bytes.Length);
}
}
@@ -90,7 +90,7 @@ namespace NzbDrone.Core.Test.MediaFiles.BookImport.Identification
{
var outp = new List<LocalBook>();
for (int i = 0; i < count; i++)
for (var i = 0; i < count; i++)
{
var track = Builder<LocalBook>
.CreateNew()
@@ -283,7 +283,7 @@ namespace NzbDrone.Core.Test.MediaFiles.BookImport.Identification
public void should_separate_many_books_in_same_directory()
{
var tracks = new List<LocalBook>();
for (int i = 0; i < 100; i++)
for (var i = 0; i < 100; i++)
{
tracks.AddRange(GivenTracks($"C:\\music".AsOsAgnostic(), "author" + i, "book" + i, 10));
}

View File

@@ -14,8 +14,8 @@ namespace NzbDrone.Core.Test.MetadataSource.Goodreads.Resources
[Test]
public void parse_non_work()
{
XElement element = new XElement("Dummy", "entry");
WorkResource work = new WorkResource();
var element = new XElement("Dummy", "entry");
var work = new WorkResource();
Assert.Throws<NullReferenceException>(() => work.Parse(element));
@@ -27,11 +27,11 @@ namespace NzbDrone.Core.Test.MetadataSource.Goodreads.Resources
[Test]
public void parse_minimal_work()
{
XElement element = new XElement("work",
var element = new XElement("work",
new XElement("original_title", "Book Title"),
new XElement("id", "123456789"));
WorkResource work = new WorkResource();
var work = new WorkResource();
work.Parse(element);
@@ -44,12 +44,12 @@ namespace NzbDrone.Core.Test.MetadataSource.Goodreads.Resources
[Test]
public void parse_minimal_work_with_surrounding_tags()
{
XElement element = new XElement("series_works",
var element = new XElement("series_works",
new XElement("work",
new XElement("original_title", "Book Title"),
new XElement("id", "123456789")));
WorkResource work = new WorkResource();
var work = new WorkResource();
work.Parse(element);

View File

@@ -115,7 +115,7 @@ namespace NzbDrone.Core.Test.MusicTests.AuthorRepositoryTests
{
GivenAuthors();
string name = "Alice Cooper";
var name = "Alice Cooper";
AddAuthor(name, "ee58c59f-8e7f-4430-b8ca-236c4d3745ae");
AddAuthor(name, "4d7928cd-7ed2-4282-8c29-c0c9f966f1bd");

View File

@@ -39,13 +39,13 @@ namespace NzbDrone.Core.Test.ParserTests
[Test]
public void should_not_parse_md5()
{
string hash = "CRAPPY TEST SEED";
var hash = "CRAPPY TEST SEED";
var hashAlgo = System.Security.Cryptography.MD5.Create();
var repetitions = 100;
var success = 0;
for (int i = 0; i < repetitions; i++)
for (var i = 0; i < repetitions; i++)
{
var hashData = hashAlgo.ComputeHash(System.Text.Encoding.Default.GetBytes(hash));
@@ -64,17 +64,17 @@ namespace NzbDrone.Core.Test.ParserTests
[TestCase(40)]
public void should_not_parse_random(int length)
{
string charset = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
var charset = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
var hashAlgo = new Random();
var repetitions = 500;
var success = 0;
for (int i = 0; i < repetitions; i++)
for (var i = 0; i < repetitions; i++)
{
StringBuilder hash = new StringBuilder(length);
var hash = new StringBuilder(length);
for (int x = 0; x < length; x++)
for (var x = 0; x < length; x++)
{
hash.Append(charset[hashAlgo.Next() % charset.Length]);
}

View File

@@ -67,7 +67,7 @@ namespace NzbDrone.Core.Test.Profiles.Delay
var moving = _last;
var result = Subject.Reorder(moving.Id, null).OrderBy(d => d.Order).ToList();
for (int i = 1; i < result.Count; i++)
for (var i = 1; i < result.Count; i++)
{
var delayProfile = result[i];

View File

@@ -15,6 +15,7 @@ namespace NzbDrone.Core.Annotations
public string Label { get; set; }
public string Unit { get; set; }
public string HelpText { get; set; }
public string HelpTextWarning { get; set; }
public string HelpLink { get; set; }
public FieldType Type { get; set; }
public bool Advanced { get; set; }

View File

@@ -32,7 +32,7 @@ namespace NzbDrone.Core.Books
var existingMetadata = FindById(data.Select(x => x.ForeignAuthorId).ToList());
var updateMetadataList = new List<AuthorMetadata>();
var addMetadataList = new List<AuthorMetadata>();
int upToDateMetadataCount = 0;
var upToDateMetadataCount = 0;
foreach (var meta in data)
{

View File

@@ -13,6 +13,7 @@ namespace NzbDrone.Core.Books
Author FindByName(string cleanName);
Author FindById(string foreignAuthorId);
Dictionary<int, string> AllAuthorPaths();
Dictionary<int, List<int>> AllAuthorTags();
Author GetAuthorByMetadataId(int authorMetadataId);
List<Author> GetAuthorsByMetadataId(IEnumerable<int> authorMetadataId);
}
@@ -65,6 +66,15 @@ namespace NzbDrone.Core.Books
}
}
public Dictionary<int, List<int>> AllAuthorTags()
{
using (var conn = _database.OpenConnection())
{
var strSql = "SELECT \"Id\" AS \"Key\", \"Tags\" AS \"Value\" FROM \"Authors\" WHERE \"Tags\" IS NOT NULL";
return conn.Query<KeyValuePair<int, List<int>>>(strSql).ToDictionary(x => x.Key, x => x.Value);
}
}
public Author GetAuthorByMetadataId(int authorMetadataId)
{
return Query(s => s.AuthorMetadataId == authorMetadataId).SingleOrDefault();

View File

@@ -132,7 +132,7 @@ namespace NzbDrone.Core.Books
if (_authorService.AuthorPathExists(path))
{
var basepath = path;
int i = 0;
var i = 0;
do
{
i++;

View File

@@ -24,6 +24,7 @@ namespace NzbDrone.Core.Books
List<Author> GetReportCandidates(string reportTitle);
void DeleteAuthor(int authorId, bool deleteFiles, bool addImportListExclusion = false);
List<Author> GetAllAuthors();
Dictionary<int, List<int>> GetAllAuthorTags();
List<Author> AllForTag(int tagId);
Author UpdateAuthor(Author author);
List<Author> UpdateAuthors(List<Author> authors, bool useExistingRelativeFolder);
@@ -185,6 +186,11 @@ namespace NzbDrone.Core.Books
return _cache.Get("GetAllAuthors", () => _authorRepository.All().ToList(), TimeSpan.FromSeconds(30));
}
public Dictionary<int, List<int>> GetAllAuthorTags()
{
return _authorRepository.AllAuthorTags();
}
public Dictionary<int, string> AllAuthorPaths()
{
return _authorRepository.AllAuthorPaths();

View File

@@ -117,8 +117,7 @@ namespace NzbDrone.Core.Configuration
continue;
}
object currentValue;
allWithDefaults.TryGetValue(configValue.Key, out currentValue);
allWithDefaults.TryGetValue(configValue.Key, out var currentValue);
if (currentValue == null)
{
continue;
@@ -141,7 +140,7 @@ namespace NzbDrone.Core.Configuration
{
const string defaultValue = "*";
string bindAddress = GetValue("BindAddress", defaultValue);
var bindAddress = GetValue("BindAddress", defaultValue);
if (string.IsNullOrWhiteSpace(bindAddress))
{
return defaultValue;

View File

@@ -56,8 +56,7 @@ namespace NzbDrone.Core.Configuration
foreach (var configValue in configValues)
{
object currentValue;
allWithDefaults.TryGetValue(configValue.Key, out currentValue);
allWithDefaults.TryGetValue(configValue.Key, out var currentValue);
if (currentValue == null || configValue.Value == null)
{
continue;
@@ -439,9 +438,7 @@ namespace NzbDrone.Core.Configuration
EnsureCache();
string dbValue;
if (_cache.TryGetValue(key, out dbValue) && dbValue != null && !string.IsNullOrEmpty(dbValue))
if (_cache.TryGetValue(key, out var dbValue) && dbValue != null && !string.IsNullOrEmpty(dbValue))
{
return dbValue;
}

View File

@@ -215,7 +215,7 @@ namespace NzbDrone.Core.Datastore
using (var conn = _database.OpenConnection())
{
using (IDbTransaction tran = conn.BeginTransaction(IsolationLevel.ReadCommitted))
using (var tran = conn.BeginTransaction(IsolationLevel.ReadCommitted))
{
foreach (var model in models)
{

View File

@@ -18,7 +18,7 @@ namespace NzbDrone.Core.Datastore.Converters
}
string contract;
using (JsonDocument body = JsonDocument.Parse(stringValue))
using (var body = JsonDocument.Parse(stringValue))
{
contract = body.RootElement.GetProperty("name").GetString();
}

View File

@@ -17,7 +17,7 @@ namespace NzbDrone.Core.Datastore.Migration
private void ConvertFileChmodToFolderChmod(IDbConnection conn, IDbTransaction tran)
{
using (IDbCommand getFileChmodCmd = conn.CreateCommand())
using (var getFileChmodCmd = conn.CreateCommand())
{
getFileChmodCmd.Transaction = tran;
getFileChmodCmd.CommandText = @"SELECT ""Value"" FROM ""Config"" WHERE ""Key"" = 'filechmod'";
@@ -32,7 +32,7 @@ namespace NzbDrone.Core.Datastore.Migration
var folderChmodNum = fileChmodNum | ((fileChmodNum & 0x124) >> 2);
var folderChmod = Convert.ToString(folderChmodNum, 8).PadLeft(3, '0');
using (IDbCommand insertCmd = conn.CreateCommand())
using (var insertCmd = conn.CreateCommand())
{
insertCmd.Transaction = tran;
insertCmd.CommandText = "INSERT INTO \"Config\" (\"Key\", \"Value\") VALUES ('chmodfolder', ?)";
@@ -42,7 +42,7 @@ namespace NzbDrone.Core.Datastore.Migration
}
}
using (IDbCommand deleteCmd = conn.CreateCommand())
using (var deleteCmd = conn.CreateCommand())
{
deleteCmd.Transaction = tran;
deleteCmd.CommandText = "DELETE FROM \"Config\" WHERE \"Key\" = 'filechmod'";

View File

@@ -231,11 +231,11 @@ namespace NzbDrone.Core.Datastore.Migration
{
var updatedNamingConfigs = new List<object>();
using (IDbCommand namingConfigCmd = conn.CreateCommand())
using (var namingConfigCmd = conn.CreateCommand())
{
namingConfigCmd.Transaction = tran;
namingConfigCmd.CommandText = @"SELECT * FROM ""NamingConfig"" LIMIT 1";
using (IDataReader namingConfigReader = namingConfigCmd.ExecuteReader())
using (var namingConfigReader = namingConfigCmd.ExecuteReader())
{
var standardBookFormatIndex = namingConfigReader.GetOrdinal("StandardBookFormat");

View File

@@ -201,7 +201,7 @@ namespace NzbDrone.Core.Datastore.Migration.Framework
public virtual IList<TableDefinition> ReadDbSchema()
{
IList<TableDefinition> tables = ReadTables();
var tables = ReadTables();
foreach (var table in tables)
{
table.Indexes = ReadIndexes(table.SchemaName, table.Name);
@@ -270,7 +270,7 @@ namespace NzbDrone.Core.Datastore.Migration.Framework
protected virtual IList<IndexDefinition> ReadIndexes(string schemaName, string tableName)
{
var sqlCommand = string.Format(@"SELECT type, name, sql FROM sqlite_master WHERE tbl_name = '{0}' AND type = 'index' AND name NOT LIKE 'sqlite_auto%';", tableName);
DataTable table = Read(sqlCommand).Tables[0];
var table = Read(sqlCommand).Tables[0];
IList<IndexDefinition> indexes = new List<IndexDefinition>();

View File

@@ -202,7 +202,7 @@ namespace NzbDrone.Core.Download.Clients.Deluge
private JsonRpcRequestBuilder BuildRequest(DelugeSettings settings)
{
string url = HttpRequestBuilder.BuildBaseUrl(settings.UseSsl, settings.Host, settings.Port, settings.UrlBase);
var url = HttpRequestBuilder.BuildBaseUrl(settings.UseSsl, settings.Host, settings.Port, settings.UrlBase);
var requestBuilder = new JsonRpcRequestBuilder(url);
requestBuilder.LogResponseContent = true;

View File

@@ -254,9 +254,8 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
protected long GetRemainingSize(DownloadStationTask torrent)
{
var downloadedString = torrent.Additional.Transfer["size_downloaded"];
long downloadedSize;
if (downloadedString.IsNullOrWhiteSpace() || !long.TryParse(downloadedString, out downloadedSize))
if (downloadedString.IsNullOrWhiteSpace() || !long.TryParse(downloadedString, out var downloadedSize))
{
_logger.Debug("Torrent {0} has invalid size_downloaded: {1}", torrent.Title, downloadedString);
downloadedSize = 0;
@@ -268,9 +267,8 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
protected TimeSpan? GetRemainingTime(DownloadStationTask torrent)
{
var speedString = torrent.Additional.Transfer["speed_download"];
long downloadSpeed;
if (speedString.IsNullOrWhiteSpace() || !long.TryParse(speedString, out downloadSpeed))
if (speedString.IsNullOrWhiteSpace() || !long.TryParse(speedString, out var downloadSpeed))
{
_logger.Debug("Torrent {0} has invalid speed_download: {1}", torrent.Title, speedString);
downloadSpeed = 0;

View File

@@ -63,7 +63,7 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
var items = new List<DownloadClientItem>();
long totalRemainingSize = 0;
long globalSpeed = nzbTasks.Where(t => t.Status == DownloadStationTaskStatus.Downloading)
var globalSpeed = nzbTasks.Where(t => t.Status == DownloadStationTaskStatus.Downloading)
.Select(GetDownloadSpeed)
.Sum();
@@ -351,9 +351,8 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
protected long GetRemainingSize(DownloadStationTask task)
{
var downloadedString = task.Additional.Transfer["size_downloaded"];
long downloadedSize;
if (downloadedString.IsNullOrWhiteSpace() || !long.TryParse(downloadedString, out downloadedSize))
if (downloadedString.IsNullOrWhiteSpace() || !long.TryParse(downloadedString, out var downloadedSize))
{
_logger.Debug("Task {0} has invalid size_downloaded: {1}", task.Title, downloadedString);
downloadedSize = 0;
@@ -365,9 +364,8 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
protected long GetDownloadSpeed(DownloadStationTask task)
{
var speedString = task.Additional.Transfer["speed_download"];
long downloadSpeed;
if (speedString.IsNullOrWhiteSpace() || !long.TryParse(speedString, out downloadSpeed))
if (speedString.IsNullOrWhiteSpace() || !long.TryParse(speedString, out var downloadSpeed))
{
_logger.Debug("Task {0} has invalid speed_download: {1}", task.Title, speedString);
downloadSpeed = 0;

View File

@@ -15,8 +15,7 @@ namespace NzbDrone.Core.Download.Clients.NzbVortex.JsonConverters
{
var result = reader.Value.ToString().Replace("_", string.Empty);
NzbVortexLoginResultType output;
Enum.TryParse(result, true, out output);
Enum.TryParse(result, true, out NzbVortexLoginResultType output);
return output;
}

View File

@@ -15,8 +15,7 @@ namespace NzbDrone.Core.Download.Clients.NzbVortex.JsonConverters
{
var result = reader.Value.ToString().Replace("_", string.Empty);
NzbVortexResultType output;
Enum.TryParse(result, true, out output);
Enum.TryParse(result, true, out NzbVortexResultType output);
return output;
}

View File

@@ -113,9 +113,7 @@ namespace NzbDrone.Core.Download.Clients.NzbVortex
public override void RemoveItem(DownloadClientItem item, bool deleteData)
{
// Try to find the download by numerical ID, otherwise try by AddUUID
int id;
if (int.TryParse(item.DownloadId, out id))
if (int.TryParse(item.DownloadId, out var id))
{
_proxy.Remove(id, deleteData, Settings);
}

View File

@@ -223,7 +223,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
protected IEnumerable<NzbgetCategory> GetCategories(Dictionary<string, string> config)
{
for (int i = 1; i < 100; i++)
for (var i = 1; i < 100; i++)
{
var name = config.GetValueOrDefault("Category" + i + ".Name");
@@ -310,8 +310,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
var config = _proxy.GetConfig(Settings);
var keepHistory = config.GetValueOrDefault("KeepHistory", "7");
int value;
if (!int.TryParse(keepHistory, NumberStyles.None, CultureInfo.InvariantCulture, out value) || value == 0)
if (!int.TryParse(keepHistory, NumberStyles.None, CultureInfo.InvariantCulture, out var value) || value == 0)
{
return new NzbDroneValidationFailure(string.Empty, "NzbGet setting KeepHistory should be greater than 0")
{

View File

@@ -164,11 +164,10 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
var queue = GetQueue(settings);
var history = GetHistory(settings);
int nzbId;
NzbgetQueueItem queueItem;
NzbgetHistoryItem historyItem;
if (id.Length < 10 && int.TryParse(id, out nzbId))
if (id.Length < 10 && int.TryParse(id, out var nzbId))
{
// Download wasn't grabbed by Readarr, so the id is the NzbId reported by nzbget.
queueItem = queue.SingleOrDefault(h => h.NzbId == nzbId);

View File

@@ -253,6 +253,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
case "queuedDL": // queuing is enabled and torrent is queued for download
case "checkingDL": // same as checkingUP, but torrent has NOT finished downloading
case "checkingUP": // torrent has finished downloading and is being checked. Set when `recheck torrent on completion` is enabled. In the event the check fails we shouldn't treat it as completed.
case "checkingResumeData": // torrent is checking resume data on load
item.Status = DownloadItemStatus.Queued;
break;
@@ -496,7 +497,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
return null;
}
Dictionary<string, QBittorrentLabel> labels = Proxy.GetLabels(Settings);
var labels = Proxy.GetLabels(Settings);
if (Settings.MusicCategory.IsNotNullOrWhiteSpace() && !labels.ContainsKey(Settings.MusicCategory))
{

View File

@@ -15,8 +15,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd.JsonConverters
{
var queuePriority = reader.Value.ToString();
SabnzbdPriority output;
Enum.TryParse(queuePriority, out output);
Enum.TryParse(queuePriority, out SabnzbdPriority output);
return output;
}

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