mirror of
https://github.com/Readarr/Readarr.git
synced 2026-03-14 15:44:20 -04:00
Compare commits
42 Commits
v0.1.6.186
...
v0.2.0.190
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
749684e24a | ||
|
|
3a0ca45aa9 | ||
|
|
595efd498e | ||
|
|
dea1060d61 | ||
|
|
f6049b8bf2 | ||
|
|
53ced38221 | ||
|
|
3a3cf8511e | ||
|
|
9ec913337d | ||
|
|
9a2120ae92 | ||
|
|
818d3a94d5 | ||
|
|
4e493b74e6 | ||
|
|
c7eaf1e85c | ||
|
|
31fe15c911 | ||
|
|
2c36a6c25f | ||
|
|
6af56f7a15 | ||
|
|
6e13191c25 | ||
|
|
921ddfc962 | ||
|
|
22f977401a | ||
|
|
113d9a07ef | ||
|
|
0560d65ea1 | ||
|
|
94ff105104 | ||
|
|
9bcf258aa9 | ||
|
|
54985bd4ca | ||
|
|
9e4d551f08 | ||
|
|
8390da1c2a | ||
|
|
44ae043c58 | ||
|
|
bb7e2fc70c | ||
|
|
b05938a9a8 | ||
|
|
1e42ac572e | ||
|
|
649dd0bda0 | ||
|
|
de24aef059 | ||
|
|
10766dd227 | ||
|
|
257d279e43 | ||
|
|
1db333088a | ||
|
|
d1aff31593 | ||
|
|
89dd4d3271 | ||
|
|
fc6c78a54e | ||
|
|
c98f4512df | ||
|
|
0a43481aed | ||
|
|
df6c142250 | ||
|
|
58cf93e360 | ||
|
|
7be282ad12 |
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -7,3 +7,9 @@
|
||||
.filteredMessage {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.blankpad {
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
padding-left: 2em;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// This file is automatically generated.
|
||||
// Please do not change this file!
|
||||
interface CssExports {
|
||||
'blankpad': string;
|
||||
'filterMenuContainer': string;
|
||||
'filteredMessage': string;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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",
|
||||
() =>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>()
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 ***")]
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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 _);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) ≤ 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) ≤ 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,
|
||||
|
||||
@@ -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))
|
||||
{
|
||||
|
||||
@@ -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])
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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++)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 ||
|
||||
|
||||
@@ -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())
|
||||
{
|
||||
|
||||
@@ -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("*"))
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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; }
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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]))
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -132,7 +132,7 @@ namespace NzbDrone.Core.Books
|
||||
if (_authorService.AuthorPathExists(path))
|
||||
{
|
||||
var basepath = path;
|
||||
int i = 0;
|
||||
var i = 0;
|
||||
do
|
||||
{
|
||||
i++;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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'";
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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>();
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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))
|
||||
{
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user