mirror of
https://github.com/Readarr/Readarr.git
synced 2026-04-18 21:34:28 -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 = _
|
dotnet_naming_style.instance_field_style.required_prefix = _
|
||||||
|
|
||||||
# Prefer "var" everywhere
|
# Prefer "var" everywhere
|
||||||
csharp_style_var_for_built_in_types = true:suggestion
|
csharp_style_var_for_built_in_types = true
|
||||||
csharp_style_var_when_type_is_apparent = true:suggestion
|
csharp_style_var_when_type_is_apparent = true
|
||||||
csharp_style_var_elsewhere = true:suggestion
|
csharp_style_var_elsewhere = true
|
||||||
|
# Prefer "out" variables to be declared inline
|
||||||
|
csharp_style_inlined_variable_declaration = true
|
||||||
|
|
||||||
# Using directive is unnecessary.
|
# Using directive is unnecessary.
|
||||||
dotnet_diagnostic.IDE0005.severity = error
|
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
|
# Stylecop Rules
|
||||||
dotnet_diagnostic.SA0001.severity = none
|
dotnet_diagnostic.SA0001.severity = none
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ variables:
|
|||||||
testsFolder: './_tests'
|
testsFolder: './_tests'
|
||||||
yarnCacheFolder: $(Pipeline.Workspace)/.yarn
|
yarnCacheFolder: $(Pipeline.Workspace)/.yarn
|
||||||
nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages
|
nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages
|
||||||
majorVersion: '0.1.6'
|
majorVersion: '0.2.0'
|
||||||
minorVersion: $[counter('minorVersion', 1)]
|
minorVersion: $[counter('minorVersion', 1)]
|
||||||
readarrVersion: '$(majorVersion).$(minorVersion)'
|
readarrVersion: '$(majorVersion).$(minorVersion)'
|
||||||
buildName: '$(Build.SourceBranchName).$(readarrVersion)'
|
buildName: '$(Build.SourceBranchName).$(readarrVersion)'
|
||||||
@@ -984,7 +984,7 @@ stages:
|
|||||||
git status
|
git status
|
||||||
if git status | grep modified
|
if git status | grep modified
|
||||||
then
|
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
|
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"}'
|
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
|
else
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
import Alert from 'Components/Alert';
|
||||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||||
import ConfirmModal from 'Components/Modal/ConfirmModal';
|
import ConfirmModal from 'Components/Modal/ConfirmModal';
|
||||||
import PageContent from 'Components/Page/PageContent';
|
import PageContent from 'Components/Page/PageContent';
|
||||||
@@ -161,16 +162,16 @@ class Blocklist extends Component {
|
|||||||
|
|
||||||
{
|
{
|
||||||
!isAnyFetching && !!error &&
|
!isAnyFetching && !!error &&
|
||||||
<div>
|
<Alert kind={kinds.DANGER}>
|
||||||
{translate('UnableToLoadBlocklist')}
|
{translate('UnableToLoadBlocklist')}
|
||||||
</div>
|
</Alert>
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
isAllPopulated && !error && !items.length &&
|
isAllPopulated && !error && !items.length &&
|
||||||
<div>
|
<Alert kind={kinds.INFO}>
|
||||||
{translate('NoHistoryBlocklist')}
|
{translate('NoHistoryBlocklist')}
|
||||||
</div>
|
</Alert>
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -214,7 +215,7 @@ class Blocklist extends Component {
|
|||||||
isOpen={isConfirmRemoveModalOpen}
|
isOpen={isConfirmRemoveModalOpen}
|
||||||
kind={kinds.DANGER}
|
kind={kinds.DANGER}
|
||||||
title={translate('RemoveSelected')}
|
title={translate('RemoveSelected')}
|
||||||
message={translate('RemoveSelectedMessageText')}
|
message={translate('RemoveSelectedItemBlocklistMessageText')}
|
||||||
confirmLabel={translate('RemoveSelected')}
|
confirmLabel={translate('RemoveSelected')}
|
||||||
onConfirm={this.onRemoveSelectedConfirmed}
|
onConfirm={this.onRemoveSelectedConfirmed}
|
||||||
onCancel={this.onConfirmRemoveModalClose}
|
onCancel={this.onConfirmRemoveModalClose}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
import Alert from 'Components/Alert';
|
||||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||||
import FilterMenu from 'Components/Menu/FilterMenu';
|
import FilterMenu from 'Components/Menu/FilterMenu';
|
||||||
import PageContent from 'Components/Page/PageContent';
|
import PageContent from 'Components/Page/PageContent';
|
||||||
@@ -11,7 +12,7 @@ import Table from 'Components/Table/Table';
|
|||||||
import TableBody from 'Components/Table/TableBody';
|
import TableBody from 'Components/Table/TableBody';
|
||||||
import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper';
|
import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper';
|
||||||
import TablePager from 'Components/Table/TablePager';
|
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 translate from 'Utilities/String/translate';
|
||||||
import HistoryRowConnector from './HistoryRowConnector';
|
import HistoryRowConnector from './HistoryRowConnector';
|
||||||
|
|
||||||
@@ -85,9 +86,9 @@ class History extends Component {
|
|||||||
|
|
||||||
{
|
{
|
||||||
!isFetchingAny && hasError &&
|
!isFetchingAny && hasError &&
|
||||||
<div>
|
<Alert kind={kinds.DANGER}>
|
||||||
{translate('UnableToLoadHistory')}
|
{translate('UnableToLoadHistory')}
|
||||||
</div>
|
</Alert>
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -95,9 +96,9 @@ class History extends Component {
|
|||||||
// wait for the books to populate because they are never coming.
|
// wait for the books to populate because they are never coming.
|
||||||
|
|
||||||
isPopulated && !hasError && !items.length &&
|
isPopulated && !hasError && !items.length &&
|
||||||
<div>
|
<Alert kind={kinds.INFO}>
|
||||||
No history found
|
{translate('NoHistory')}
|
||||||
</div>
|
</Alert>
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
import Alert from 'Components/Alert';
|
||||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||||
import PageContent from 'Components/Page/PageContent';
|
import PageContent from 'Components/Page/PageContent';
|
||||||
import PageContentBody from 'Components/Page/PageContentBody';
|
import PageContentBody from 'Components/Page/PageContentBody';
|
||||||
@@ -12,7 +13,7 @@ import Table from 'Components/Table/Table';
|
|||||||
import TableBody from 'Components/Table/TableBody';
|
import TableBody from 'Components/Table/TableBody';
|
||||||
import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper';
|
import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper';
|
||||||
import TablePager from 'Components/Table/TablePager';
|
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 getRemovedItems from 'Utilities/Object/getRemovedItems';
|
||||||
import hasDifferentItems from 'Utilities/Object/hasDifferentItems';
|
import hasDifferentItems from 'Utilities/Object/hasDifferentItems';
|
||||||
import translate from 'Utilities/String/translate';
|
import translate from 'Utilities/String/translate';
|
||||||
@@ -233,17 +234,17 @@ class Queue extends Component {
|
|||||||
|
|
||||||
{
|
{
|
||||||
!isRefreshing && hasError ?
|
!isRefreshing && hasError ?
|
||||||
<div>
|
<Alert kind={kinds.DANGER}>
|
||||||
{translate('FailedToLoadQueue')}
|
{translate('FailedToLoadQueue')}
|
||||||
</div> :
|
</Alert> :
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
isAllPopulated && !hasError && !items.length ?
|
isAllPopulated && !hasError && !items.length ?
|
||||||
<div>
|
<Alert kind={kinds.INFO}>
|
||||||
{translate('QueueIsEmpty')}
|
{translate('QueueIsEmpty')}
|
||||||
</div> :
|
</Alert> :
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -89,12 +89,12 @@ class RemoveQueueItemsModal extends Component {
|
|||||||
onModalClose={this.onModalClose}
|
onModalClose={this.onModalClose}
|
||||||
>
|
>
|
||||||
<ModalHeader>
|
<ModalHeader>
|
||||||
Remove Selected Item{selectedCount > 1 ? 's' : ''}
|
{selectedCount > 1 ? translate('RemoveSelectedItems') : translate('RemoveSelectedItem')}
|
||||||
</ModalHeader>
|
</ModalHeader>
|
||||||
|
|
||||||
<ModalBody>
|
<ModalBody>
|
||||||
<div className={styles.message}>
|
<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>
|
</div>
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -118,14 +118,14 @@ class RemoveQueueItemsModal extends Component {
|
|||||||
|
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<FormLabel>
|
<FormLabel>
|
||||||
Add Release{selectedCount > 1 ? 's' : ''} To Blocklist
|
{selectedCount > 1 ? translate('BlocklistReleases') : translate('BlocklistRelease')}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
|
|
||||||
<FormInputGroup
|
<FormInputGroup
|
||||||
type={inputTypes.CHECK}
|
type={inputTypes.CHECK}
|
||||||
name="blocklist"
|
name="blocklist"
|
||||||
value={blocklist}
|
value={blocklist}
|
||||||
helpText={translate('BlocklistHelpText')}
|
helpText={translate('BlocklistReleaseHelpText')}
|
||||||
onChange={this.onBlocklistChange}
|
onChange={this.onBlocklistChange}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
@@ -150,14 +150,14 @@ class RemoveQueueItemsModal extends Component {
|
|||||||
|
|
||||||
<ModalFooter>
|
<ModalFooter>
|
||||||
<Button onPress={this.onModalClose}>
|
<Button onPress={this.onModalClose}>
|
||||||
Close
|
{translate('Close')}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
kind={kinds.DANGER}
|
kind={kinds.DANGER}
|
||||||
onPress={this.onRemoveConfirmed}
|
onPress={this.onRemoveConfirmed}
|
||||||
>
|
>
|
||||||
Remove
|
{translate('Remove')}
|
||||||
</Button>
|
</Button>
|
||||||
</ModalFooter>
|
</ModalFooter>
|
||||||
</ModalContent>
|
</ModalContent>
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
import Alert from 'Components/Alert';
|
||||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||||
import Table from 'Components/Table/Table';
|
import Table from 'Components/Table/Table';
|
||||||
import TableBody from 'Components/Table/TableBody';
|
import TableBody from 'Components/Table/TableBody';
|
||||||
|
import { kinds } from 'Helpers/Props';
|
||||||
import translate from 'Utilities/String/translate';
|
import translate from 'Utilities/String/translate';
|
||||||
import AuthorHistoryRowConnector from './AuthorHistoryRowConnector';
|
import AuthorHistoryRowConnector from './AuthorHistoryRowConnector';
|
||||||
|
|
||||||
@@ -70,9 +72,9 @@ class AuthorHistoryTableContent extends Component {
|
|||||||
|
|
||||||
{
|
{
|
||||||
!isFetching && !!error &&
|
!isFetching && !!error &&
|
||||||
<div>
|
<Alert kind={kinds.DANGER}>
|
||||||
{translate('UnableToLoadHistory')}
|
{translate('UnableToLoadHistory')}
|
||||||
</div>
|
</Alert>
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
import Alert from 'Components/Alert';
|
||||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||||
|
import { kinds } from 'Helpers/Props';
|
||||||
import translate from 'Utilities/String/translate';
|
import translate from 'Utilities/String/translate';
|
||||||
import AgendaConnector from './Agenda/AgendaConnector';
|
import AgendaConnector from './Agenda/AgendaConnector';
|
||||||
import * as calendarViews from './calendarViews';
|
import * as calendarViews from './calendarViews';
|
||||||
@@ -31,9 +33,9 @@ class Calendar extends Component {
|
|||||||
|
|
||||||
{
|
{
|
||||||
!isFetching && !!error &&
|
!isFetching && !!error &&
|
||||||
<div>
|
<Alert kind={kinds.DANGER}>
|
||||||
{translate('UnableToLoadTheCalendar')}
|
{translate('UnableToLoadTheCalendar')}
|
||||||
</div>
|
</Alert>
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ function ProviderFieldFormGroup(props) {
|
|||||||
name,
|
name,
|
||||||
label,
|
label,
|
||||||
helpText,
|
helpText,
|
||||||
|
helpTextWarning,
|
||||||
helpLink,
|
helpLink,
|
||||||
placeholder,
|
placeholder,
|
||||||
value,
|
value,
|
||||||
@@ -95,6 +96,7 @@ function ProviderFieldFormGroup(props) {
|
|||||||
name={name}
|
name={name}
|
||||||
label={label}
|
label={label}
|
||||||
helpText={helpText}
|
helpText={helpText}
|
||||||
|
helpTextWarning={helpTextWarning}
|
||||||
helpLink={helpLink}
|
helpLink={helpLink}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
value={value}
|
value={value}
|
||||||
@@ -121,6 +123,7 @@ ProviderFieldFormGroup.propTypes = {
|
|||||||
name: PropTypes.string.isRequired,
|
name: PropTypes.string.isRequired,
|
||||||
label: PropTypes.string.isRequired,
|
label: PropTypes.string.isRequired,
|
||||||
helpText: PropTypes.string,
|
helpText: PropTypes.string,
|
||||||
|
helpTextWarning: PropTypes.string,
|
||||||
helpLink: PropTypes.string,
|
helpLink: PropTypes.string,
|
||||||
placeholder: PropTypes.string,
|
placeholder: PropTypes.string,
|
||||||
value: PropTypes.any,
|
value: PropTypes.any,
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import Alert from 'Components/Alert';
|
||||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||||
|
import { kinds } from 'Helpers/Props';
|
||||||
|
|
||||||
function PageSectionContent(props) {
|
function PageSectionContent(props) {
|
||||||
const {
|
const {
|
||||||
@@ -17,7 +19,7 @@ function PageSectionContent(props) {
|
|||||||
);
|
);
|
||||||
} else if (!isFetching && !!error) {
|
} else if (!isFetching && !!error) {
|
||||||
return (
|
return (
|
||||||
<div>{errorMessage}</div>
|
<Alert kind={kinds.DANGER}>{errorMessage}</Alert>
|
||||||
);
|
);
|
||||||
} else if (isPopulated && !error) {
|
} else if (isPopulated && !error) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -16,6 +16,38 @@
|
|||||||
box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
|
box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
|
||||||
color: var(--white);
|
color: var(--white);
|
||||||
transition: width 0.6s ease;
|
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 {
|
.frontTextContainer {
|
||||||
@@ -45,38 +77,6 @@
|
|||||||
cursor: default;
|
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 {
|
.small {
|
||||||
height: $progressBarSmallHeight;
|
height: $progressBarSmallHeight;
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ function ProgressBar(props) {
|
|||||||
{
|
{
|
||||||
showText && width ?
|
showText && width ?
|
||||||
<div
|
<div
|
||||||
className={styles.backTextContainer}
|
className={classNames(styles.backTextContainer, styles[kind])}
|
||||||
style={{ width: actualWidth }}
|
style={{ width: actualWidth }}
|
||||||
>
|
>
|
||||||
<div className={styles.backText}>
|
<div className={styles.backText}>
|
||||||
@@ -67,7 +67,7 @@ function ProgressBar(props) {
|
|||||||
{
|
{
|
||||||
showText ?
|
showText ?
|
||||||
<div
|
<div
|
||||||
className={styles.frontTextContainer}
|
className={classNames(styles.frontTextContainer, styles[kind])}
|
||||||
style={{ width: progressPercent }}
|
style={{ width: progressPercent }}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -1,18 +1,19 @@
|
|||||||
{
|
{
|
||||||
"name": "",
|
"name": "Readarr",
|
||||||
"icons": [
|
"icons": [
|
||||||
{
|
{
|
||||||
"src": "/Content/Images/Icons/android-chrome-192x192.png",
|
"src": "android-chrome-192x192.png",
|
||||||
"sizes": "192x192",
|
"sizes": "192x192",
|
||||||
"type": "image/png"
|
"type": "image/png"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"src": "/Content/Images/Icons/android-chrome-512x512.png",
|
"src": "android-chrome-512x512.png",
|
||||||
"sizes": "512x512",
|
"sizes": "512x512",
|
||||||
"type": "image/png"
|
"type": "image/png"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"start_url": "../../../../",
|
||||||
"theme_color": "#3a3f51",
|
"theme_color": "#3a3f51",
|
||||||
"background_color": "#3a3f51",
|
"background_color": "#3a3f51",
|
||||||
"display": "standalone"
|
"display": "standalone"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
import Alert from 'Components/Alert';
|
||||||
import Form from 'Components/Form/Form';
|
import Form from 'Components/Form/Form';
|
||||||
import FormGroup from 'Components/Form/FormGroup';
|
import FormGroup from 'Components/Form/FormGroup';
|
||||||
import FormInputGroup from 'Components/Form/FormInputGroup';
|
import FormInputGroup from 'Components/Form/FormInputGroup';
|
||||||
@@ -92,9 +93,9 @@ class SelectQualityModalContent extends Component {
|
|||||||
|
|
||||||
{
|
{
|
||||||
!isFetching && !!error &&
|
!isFetching && !!error &&
|
||||||
<div>
|
<Alert kind={kinds.DANGER}>
|
||||||
{translate('UnableToLoadQualities')}
|
{translate('UnableToLoadQualities')}
|
||||||
</div>
|
</Alert>
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,3 +7,9 @@
|
|||||||
.filteredMessage {
|
.filteredMessage {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.blankpad {
|
||||||
|
padding-top: 10px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
padding-left: 2em;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// This file is automatically generated.
|
// This file is automatically generated.
|
||||||
// Please do not change this file!
|
// Please do not change this file!
|
||||||
interface CssExports {
|
interface CssExports {
|
||||||
|
'blankpad': string;
|
||||||
'filterMenuContainer': string;
|
'filterMenuContainer': string;
|
||||||
'filteredMessage': string;
|
'filteredMessage': string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ function InteractiveSearch(props) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
!isFetching && error ?
|
!isFetching && error ?
|
||||||
<div>
|
<div className={styles.blankpad}>
|
||||||
Unable to load results for this book search. Try again later
|
Unable to load results for this book search. Try again later
|
||||||
</div> :
|
</div> :
|
||||||
null
|
null
|
||||||
@@ -112,7 +112,7 @@ function InteractiveSearch(props) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
!isFetching && isPopulated && !totalReleasesCount ?
|
!isFetching && isPopulated && !totalReleasesCount ?
|
||||||
<div>
|
<div className={styles.blankpad}>
|
||||||
No results found
|
No results found
|
||||||
</div> :
|
</div> :
|
||||||
null
|
null
|
||||||
@@ -120,7 +120,7 @@ function InteractiveSearch(props) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
!!totalReleasesCount && isPopulated && !items.length ?
|
!!totalReleasesCount && isPopulated && !items.length ?
|
||||||
<div>
|
<div className={styles.blankpad}>
|
||||||
All results are hidden by the applied filter
|
All results are hidden by the applied filter
|
||||||
</div> :
|
</div> :
|
||||||
null
|
null
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ class Specification extends Component {
|
|||||||
|
|
||||||
<IconButton
|
<IconButton
|
||||||
className={styles.cloneButton}
|
className={styles.cloneButton}
|
||||||
title={translate('Clone')}
|
title={translate('CloneCondition')}
|
||||||
name={icons.CLONE}
|
name={icons.CLONE}
|
||||||
onPress={this.onCloneSpecificationPress}
|
onPress={this.onCloneSpecificationPress}
|
||||||
/>
|
/>
|
||||||
@@ -92,14 +92,14 @@ class Specification extends Component {
|
|||||||
{
|
{
|
||||||
negate &&
|
negate &&
|
||||||
<Label kind={kinds.DANGER}>
|
<Label kind={kinds.DANGER}>
|
||||||
Negated
|
{translate('Negated')}
|
||||||
</Label>
|
</Label>
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
required &&
|
required &&
|
||||||
<Label kind={kinds.SUCCESS}>
|
<Label kind={kinds.SUCCESS}>
|
||||||
Required
|
{translate('Required')}
|
||||||
</Label>
|
</Label>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
@@ -114,8 +114,8 @@ class Specification extends Component {
|
|||||||
<ConfirmModal
|
<ConfirmModal
|
||||||
isOpen={this.state.isDeleteSpecificationModalOpen}
|
isOpen={this.state.isDeleteSpecificationModalOpen}
|
||||||
kind={kinds.DANGER}
|
kind={kinds.DANGER}
|
||||||
title={translate('DeleteFormat')}
|
title={translate('DeleteCondition')}
|
||||||
message={translate('DeleteFormatMessageText', [name])}
|
message={translate('DeleteConditionMessageText', [name])}
|
||||||
confirmLabel={translate('Delete')}
|
confirmLabel={translate('Delete')}
|
||||||
onConfirm={this.onConfirmDeleteSpecification}
|
onConfirm={this.onConfirmDeleteSpecification}
|
||||||
onCancel={this.onDeleteSpecificationModalClose}
|
onCancel={this.onDeleteSpecificationModalClose}
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import Alert from 'Components/Alert';
|
||||||
import FieldSet from 'Components/FieldSet';
|
import FieldSet from 'Components/FieldSet';
|
||||||
import Form from 'Components/Form/Form';
|
import Form from 'Components/Form/Form';
|
||||||
import FormGroup from 'Components/Form/FormGroup';
|
import FormGroup from 'Components/Form/FormGroup';
|
||||||
import FormInputGroup from 'Components/Form/FormInputGroup';
|
import FormInputGroup from 'Components/Form/FormInputGroup';
|
||||||
import FormLabel from 'Components/Form/FormLabel';
|
import FormLabel from 'Components/Form/FormLabel';
|
||||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
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 translate from 'Utilities/String/translate';
|
||||||
|
|
||||||
function DownloadClientOptions(props) {
|
function DownloadClientOptions(props) {
|
||||||
@@ -28,9 +29,9 @@ function DownloadClientOptions(props) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
!isFetching && error &&
|
!isFetching && error &&
|
||||||
<div>
|
<Alert kind={kinds.DANGER}>
|
||||||
{translate('UnableToLoadDownloadClientOptions')}
|
{translate('UnableToLoadDownloadClientOptions')}
|
||||||
</div>
|
</Alert>
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -88,8 +88,8 @@ class RemotePathMapping extends Component {
|
|||||||
<ConfirmModal
|
<ConfirmModal
|
||||||
isOpen={this.state.isDeleteRemotePathMappingModalOpen}
|
isOpen={this.state.isDeleteRemotePathMappingModalOpen}
|
||||||
kind={kinds.DANGER}
|
kind={kinds.DANGER}
|
||||||
title={translate('DeleteDelayProfile')}
|
title={translate('DeleteRemotePathMapping')}
|
||||||
message={translate('DeleteDelayProfileMessageText')}
|
message={translate('DeleteRemotePathMappingMessageText')}
|
||||||
confirmLabel={translate('Delete')}
|
confirmLabel={translate('Delete')}
|
||||||
onConfirm={this.onConfirmDeleteRemotePathMapping}
|
onConfirm={this.onConfirmDeleteRemotePathMapping}
|
||||||
onCancel={this.onDeleteRemotePathMappingModalClose}
|
onCancel={this.onDeleteRemotePathMappingModalClose}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
import Alert from 'Components/Alert';
|
||||||
import Form from 'Components/Form/Form';
|
import Form from 'Components/Form/Form';
|
||||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||||
import ConfirmModal from 'Components/Modal/ConfirmModal';
|
import ConfirmModal from 'Components/Modal/ConfirmModal';
|
||||||
@@ -124,9 +125,9 @@ class GeneralSettings extends Component {
|
|||||||
|
|
||||||
{
|
{
|
||||||
!isFetching && error &&
|
!isFetching && error &&
|
||||||
<div>
|
<Alert kind={kinds.DANGER}>
|
||||||
{translate('UnableToLoadGeneralSettings')}
|
{translate('UnableToLoadGeneralSettings')}
|
||||||
</div>
|
</Alert>
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import Alert from 'Components/Alert';
|
||||||
import FieldSet from 'Components/FieldSet';
|
import FieldSet from 'Components/FieldSet';
|
||||||
import Form from 'Components/Form/Form';
|
import Form from 'Components/Form/Form';
|
||||||
import FormGroup from 'Components/Form/FormGroup';
|
import FormGroup from 'Components/Form/FormGroup';
|
||||||
import FormInputGroup from 'Components/Form/FormInputGroup';
|
import FormInputGroup from 'Components/Form/FormInputGroup';
|
||||||
import FormLabel from 'Components/Form/FormLabel';
|
import FormLabel from 'Components/Form/FormLabel';
|
||||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||||
import { inputTypes } from 'Helpers/Props';
|
import { inputTypes, kinds } from 'Helpers/Props';
|
||||||
import translate from 'Utilities/String/translate';
|
import translate from 'Utilities/String/translate';
|
||||||
|
|
||||||
function IndexerOptions(props) {
|
function IndexerOptions(props) {
|
||||||
@@ -28,9 +29,9 @@ function IndexerOptions(props) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
!isFetching && error &&
|
!isFetching && error &&
|
||||||
<div>
|
<Alert kind={kinds.DANGER}>
|
||||||
{translate('UnableToLoadIndexerOptions')}
|
{translate('UnableToLoadIndexerOptions')}
|
||||||
</div>
|
</Alert>
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
import Alert from 'Components/Alert';
|
||||||
import FieldSet from 'Components/FieldSet';
|
import FieldSet from 'Components/FieldSet';
|
||||||
import Form from 'Components/Form/Form';
|
import Form from 'Components/Form/Form';
|
||||||
import FormGroup from 'Components/Form/FormGroup';
|
import FormGroup from 'Components/Form/FormGroup';
|
||||||
@@ -8,7 +9,7 @@ import FormLabel from 'Components/Form/FormLabel';
|
|||||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||||
import PageContent from 'Components/Page/PageContent';
|
import PageContent from 'Components/Page/PageContent';
|
||||||
import PageContentBody from 'Components/Page/PageContentBody';
|
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 RemotePathMappingsConnector from 'Settings/DownloadClients/RemotePathMappings/RemotePathMappingsConnector';
|
||||||
import SettingsToolbarConnector from 'Settings/SettingsToolbarConnector';
|
import SettingsToolbarConnector from 'Settings/SettingsToolbarConnector';
|
||||||
import translate from 'Utilities/String/translate';
|
import translate from 'Utilities/String/translate';
|
||||||
@@ -79,9 +80,9 @@ class MediaManagement extends Component {
|
|||||||
{
|
{
|
||||||
!isFetching && error &&
|
!isFetching && error &&
|
||||||
<FieldSet legend={translate('NamingSettings')}>
|
<FieldSet legend={translate('NamingSettings')}>
|
||||||
<div>
|
<Alert kind={kinds.DANGER}>
|
||||||
{translate('UnableToLoadMediaManagementSettings')}
|
{translate('UnableToLoadMediaManagementSettings')}
|
||||||
</div>
|
</Alert>
|
||||||
</FieldSet>
|
</FieldSet>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
import Alert from 'Components/Alert';
|
||||||
import FieldSet from 'Components/FieldSet';
|
import FieldSet from 'Components/FieldSet';
|
||||||
import Form from 'Components/Form/Form';
|
import Form from 'Components/Form/Form';
|
||||||
import FormGroup from 'Components/Form/FormGroup';
|
import FormGroup from 'Components/Form/FormGroup';
|
||||||
@@ -7,7 +8,7 @@ import FormInputButton from 'Components/Form/FormInputButton';
|
|||||||
import FormInputGroup from 'Components/Form/FormInputGroup';
|
import FormInputGroup from 'Components/Form/FormInputGroup';
|
||||||
import FormLabel from 'Components/Form/FormLabel';
|
import FormLabel from 'Components/Form/FormLabel';
|
||||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
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 translate from 'Utilities/String/translate';
|
||||||
import NamingModal from './NamingModal';
|
import NamingModal from './NamingModal';
|
||||||
import styles from './Naming.css';
|
import styles from './Naming.css';
|
||||||
@@ -118,9 +119,9 @@ class Naming extends Component {
|
|||||||
|
|
||||||
{
|
{
|
||||||
!isFetching && error &&
|
!isFetching && error &&
|
||||||
<div>
|
<Alert kind={kinds.DANGER}>
|
||||||
{translate('UnableToLoadNamingSettings')}
|
{translate('UnableToLoadNamingSettings')}
|
||||||
</div>
|
</Alert>
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import Alert from 'Components/Alert';
|
||||||
import FieldSet from 'Components/FieldSet';
|
import FieldSet from 'Components/FieldSet';
|
||||||
import Form from 'Components/Form/Form';
|
import Form from 'Components/Form/Form';
|
||||||
import FormGroup from 'Components/Form/FormGroup';
|
import FormGroup from 'Components/Form/FormGroup';
|
||||||
import FormInputGroup from 'Components/Form/FormInputGroup';
|
import FormInputGroup from 'Components/Form/FormInputGroup';
|
||||||
import FormLabel from 'Components/Form/FormLabel';
|
import FormLabel from 'Components/Form/FormLabel';
|
||||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||||
import { inputTypes } from 'Helpers/Props';
|
import { inputTypes, kinds } from 'Helpers/Props';
|
||||||
import translate from 'Utilities/String/translate';
|
import translate from 'Utilities/String/translate';
|
||||||
|
|
||||||
const writeAudioTagOptions = [
|
const writeAudioTagOptions = [
|
||||||
@@ -41,9 +42,9 @@ function MetadataProvider(props) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
!isFetching && error &&
|
!isFetching && error &&
|
||||||
<div>
|
<Alert kind={kinds.DANGER}>
|
||||||
{translate('UnableToLoadMetadataProviderSettings')}
|
{translate('UnableToLoadMetadataProviderSettings')}
|
||||||
</div>
|
</Alert>
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -55,12 +55,12 @@ class ResetQualityDefinitionsModalContent extends Component {
|
|||||||
onModalClose={onModalClose}
|
onModalClose={onModalClose}
|
||||||
>
|
>
|
||||||
<ModalHeader>
|
<ModalHeader>
|
||||||
Reset Quality Definitions
|
{translate('ResetQualityDefinitions')}
|
||||||
</ModalHeader>
|
</ModalHeader>
|
||||||
|
|
||||||
<ModalBody>
|
<ModalBody>
|
||||||
<div className={styles.messageContainer}>
|
<div className={styles.messageContainer}>
|
||||||
Are you sure you want to reset quality definitions?
|
{translate('ResetQualityDefinitionsMessageText')}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
@@ -81,7 +81,7 @@ class ResetQualityDefinitionsModalContent extends Component {
|
|||||||
|
|
||||||
<ModalFooter>
|
<ModalFooter>
|
||||||
<Button onPress={onModalClose}>
|
<Button onPress={onModalClose}>
|
||||||
Cancel
|
{translate('Cancel')}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
@@ -89,7 +89,7 @@ class ResetQualityDefinitionsModalContent extends Component {
|
|||||||
onPress={this.onResetQualityDefinitionsConfirmed}
|
onPress={this.onResetQualityDefinitionsConfirmed}
|
||||||
isDisabled={isResettingQualityDefinitions}
|
isDisabled={isResettingQualityDefinitions}
|
||||||
>
|
>
|
||||||
Reset
|
{translate('Reset')}
|
||||||
</Button>
|
</Button>
|
||||||
</ModalFooter>
|
</ModalFooter>
|
||||||
</ModalContent>
|
</ModalContent>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
import Alert from 'Components/Alert';
|
||||||
import FieldSet from 'Components/FieldSet';
|
import FieldSet from 'Components/FieldSet';
|
||||||
import Form from 'Components/Form/Form';
|
import Form from 'Components/Form/Form';
|
||||||
import FormGroup from 'Components/Form/FormGroup';
|
import FormGroup from 'Components/Form/FormGroup';
|
||||||
@@ -8,7 +9,7 @@ import FormLabel from 'Components/Form/FormLabel';
|
|||||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||||
import PageContent from 'Components/Page/PageContent';
|
import PageContent from 'Components/Page/PageContent';
|
||||||
import PageContentBody from 'Components/Page/PageContentBody';
|
import PageContentBody from 'Components/Page/PageContentBody';
|
||||||
import { inputTypes } from 'Helpers/Props';
|
import { inputTypes, kinds } from 'Helpers/Props';
|
||||||
import SettingsToolbarConnector from 'Settings/SettingsToolbarConnector';
|
import SettingsToolbarConnector from 'Settings/SettingsToolbarConnector';
|
||||||
import themes from 'Styles/Themes';
|
import themes from 'Styles/Themes';
|
||||||
import titleCase from 'Utilities/String/titleCase';
|
import titleCase from 'Utilities/String/titleCase';
|
||||||
@@ -81,9 +82,9 @@ class UISettings extends Component {
|
|||||||
|
|
||||||
{
|
{
|
||||||
!isFetching && error &&
|
!isFetching && error &&
|
||||||
<div>
|
<Alert kind={kinds.DANGER}>
|
||||||
{translate('UnableToLoadUISettings')}
|
{translate('UnableToLoadUISettings')}
|
||||||
</div>
|
</Alert>
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -32,9 +32,9 @@ function createSaveProviderHandler(section, url, options = {}, removeStale = fal
|
|||||||
const params = { ...queryParams };
|
const params = { ...queryParams };
|
||||||
|
|
||||||
// If the user is re-saving the same provider without changes
|
// 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;
|
params.forceSave = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
import Alert from 'Components/Alert';
|
||||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||||
import PageContent from 'Components/Page/PageContent';
|
import PageContent from 'Components/Page/PageContent';
|
||||||
import PageContentBody from 'Components/Page/PageContentBody';
|
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 PageToolbarSection from 'Components/Page/Toolbar/PageToolbarSection';
|
||||||
import Table from 'Components/Table/Table';
|
import Table from 'Components/Table/Table';
|
||||||
import TableBody from 'Components/Table/TableBody';
|
import TableBody from 'Components/Table/TableBody';
|
||||||
import { icons } from 'Helpers/Props';
|
import { icons, kinds } from 'Helpers/Props';
|
||||||
import translate from 'Utilities/String/translate';
|
import translate from 'Utilities/String/translate';
|
||||||
import BackupRow from './BackupRow';
|
import BackupRow from './BackupRow';
|
||||||
import RestoreBackupModalConnector from './RestoreBackupModalConnector';
|
import RestoreBackupModalConnector from './RestoreBackupModalConnector';
|
||||||
@@ -107,16 +108,16 @@ class Backups extends Component {
|
|||||||
|
|
||||||
{
|
{
|
||||||
!isFetching && !!error &&
|
!isFetching && !!error &&
|
||||||
<div>
|
<Alert kind={kinds.DANGER}>
|
||||||
{translate('UnableToLoadBackups')}
|
{translate('UnableToLoadBackups')}
|
||||||
</div>
|
</Alert>
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
noBackups &&
|
noBackups &&
|
||||||
<div>
|
<Alert kind={kinds.INFO}>
|
||||||
{translate('NoBackupsAreAvailable')}
|
{translate('NoBackupsAreAvailable')}
|
||||||
</div>
|
</Alert>
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -30,6 +30,13 @@
|
|||||||
<!-- A test project gets the test sdk packages automatically added -->
|
<!-- A test project gets the test sdk packages automatically added -->
|
||||||
<TestProject>false</TestProject>
|
<TestProject>false</TestProject>
|
||||||
<TestProject Condition="$(MSBuildProjectName.EndsWith('.Test'))">true</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>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
|||||||
@@ -27,35 +27,36 @@ namespace NzbDrone.Api.Test.ClientSchemaTests
|
|||||||
|
|
||||||
var schema = SchemaBuilder.ToSchema(model);
|
var schema = SchemaBuilder.ToSchema(model);
|
||||||
|
|
||||||
schema.Should().Contain(c =>
|
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");
|
||||||
c.Order == 1 && c.Name == "lastName" && c.Label == "Last Name" && c.HelpText == "Your Last Name" &&
|
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");
|
||||||
(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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void schema_should_have_nested_fields()
|
public void schema_should_have_nested_fields()
|
||||||
{
|
{
|
||||||
var model = new NestedTestModel();
|
var model = new NestedTestModel
|
||||||
model.Name.FirstName = "Bob";
|
{
|
||||||
model.Name.LastName = "Poop";
|
Name =
|
||||||
|
{
|
||||||
|
FirstName = "Bob",
|
||||||
|
LastName = "Poop"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
var schema = SchemaBuilder.ToSchema(model);
|
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 == 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" && (string)c.Value == "Poop");
|
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");
|
schema.Should().Contain(c => c.Order == 2 && c.Name == "quote" && c.Label == "Quote" && c.HelpText == "Your Favorite Quote");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TestModel
|
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; }
|
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 LastName { get; set; }
|
||||||
|
|
||||||
public string Other { get; set; }
|
public string Other { get; set; }
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ namespace NzbDrone.Automation.Test
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Screenshot image = ((ITakesScreenshot)driver).GetScreenshot();
|
var image = ((ITakesScreenshot)driver).GetScreenshot();
|
||||||
image.SaveAsFile($"./{name}_test_screenshot.png", ScreenshotImageFormat.Png);
|
image.SaveAsFile($"./{name}_test_screenshot.png", ScreenshotImageFormat.Png);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ namespace NzbDrone.Automation.Test.PageModel
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
IWebElement element = d.FindElement(By.ClassName("followingBalls"));
|
var element = d.FindElement(By.ClassName("followingBalls"));
|
||||||
return !element.Displayed;
|
return !element.Displayed;
|
||||||
}
|
}
|
||||||
catch (NoSuchElementException)
|
catch (NoSuchElementException)
|
||||||
|
|||||||
@@ -65,9 +65,9 @@ namespace NzbDrone.Common.Test.CacheTests
|
|||||||
[Test]
|
[Test]
|
||||||
public void should_store_null()
|
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", () =>
|
_cachedString.Get("key", () =>
|
||||||
{
|
{
|
||||||
@@ -83,10 +83,10 @@ namespace NzbDrone.Common.Test.CacheTests
|
|||||||
[Platform(Exclude = "MacOsX")]
|
[Platform(Exclude = "MacOsX")]
|
||||||
public void should_honor_ttl()
|
public void should_honor_ttl()
|
||||||
{
|
{
|
||||||
int hitCount = 0;
|
var hitCount = 0;
|
||||||
_cachedString = new Cached<string>();
|
_cachedString = new Cached<string>();
|
||||||
|
|
||||||
for (int i = 0; i < 10; i++)
|
for (var i = 0; i < 10; i++)
|
||||||
{
|
{
|
||||||
_cachedString.Get("key",
|
_cachedString.Get("key",
|
||||||
() =>
|
() =>
|
||||||
@@ -107,10 +107,10 @@ namespace NzbDrone.Common.Test.CacheTests
|
|||||||
[Platform(Exclude = "MacOsX")]
|
[Platform(Exclude = "MacOsX")]
|
||||||
public void should_clear_expired_when_they_expire()
|
public void should_clear_expired_when_they_expire()
|
||||||
{
|
{
|
||||||
int hitCount = 0;
|
var hitCount = 0;
|
||||||
_cachedString = new Cached<string>(rollingExpiry: true);
|
_cachedString = new Cached<string>(rollingExpiry: true);
|
||||||
|
|
||||||
for (int i = 0; i < 10; i++)
|
for (var i = 0; i < 10; i++)
|
||||||
{
|
{
|
||||||
_cachedString.Get("key",
|
_cachedString.Get("key",
|
||||||
() =>
|
() =>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
using Moq;
|
using Moq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
@@ -142,7 +142,7 @@ namespace NzbDrone.Common.Test
|
|||||||
[Test]
|
[Test]
|
||||||
public void SaveDictionary_should_save_proper_value()
|
public void SaveDictionary_should_save_proper_value()
|
||||||
{
|
{
|
||||||
int port = 20555;
|
var port = 20555;
|
||||||
|
|
||||||
var dic = Subject.GetConfigDictionary();
|
var dic = Subject.GetConfigDictionary();
|
||||||
dic["Port"] = 20555;
|
dic["Port"] = 20555;
|
||||||
@@ -155,9 +155,9 @@ namespace NzbDrone.Common.Test
|
|||||||
[Test]
|
[Test]
|
||||||
public void SaveDictionary_should_only_save_specified_values()
|
public void SaveDictionary_should_only_save_specified_values()
|
||||||
{
|
{
|
||||||
int port = 20555;
|
var port = 20555;
|
||||||
int origSslPort = 20551;
|
var origSslPort = 20551;
|
||||||
int sslPort = 20552;
|
var sslPort = 20552;
|
||||||
|
|
||||||
var dic = Subject.GetConfigDictionary();
|
var dic = Subject.GetConfigDictionary();
|
||||||
dic["Port"] = port;
|
dic["Port"] = port;
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ namespace NzbDrone.Common.Test.DiskTests
|
|||||||
[Test]
|
[Test]
|
||||||
public void should_not_contain_recycling_bin_for_root_of_drive()
|
public void should_not_contain_recycling_bin_for_root_of_drive()
|
||||||
{
|
{
|
||||||
string root = @"C:\".AsOsAgnostic();
|
var root = @"C:\".AsOsAgnostic();
|
||||||
SetupFolders(root);
|
SetupFolders(root);
|
||||||
|
|
||||||
Mocker.GetMock<IDiskProvider>()
|
Mocker.GetMock<IDiskProvider>()
|
||||||
@@ -56,7 +56,7 @@ namespace NzbDrone.Common.Test.DiskTests
|
|||||||
[Test]
|
[Test]
|
||||||
public void should_not_contain_system_volume_information()
|
public void should_not_contain_system_volume_information()
|
||||||
{
|
{
|
||||||
string root = @"C:\".AsOsAgnostic();
|
var root = @"C:\".AsOsAgnostic();
|
||||||
SetupFolders(root);
|
SetupFolders(root);
|
||||||
|
|
||||||
Mocker.GetMock<IDiskProvider>()
|
Mocker.GetMock<IDiskProvider>()
|
||||||
@@ -69,7 +69,7 @@ namespace NzbDrone.Common.Test.DiskTests
|
|||||||
[Test]
|
[Test]
|
||||||
public void should_not_contain_recycling_bin_or_system_volume_information_for_root_of_drive()
|
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);
|
SetupFolders(root);
|
||||||
|
|
||||||
Mocker.GetMock<IDiskProvider>()
|
Mocker.GetMock<IDiskProvider>()
|
||||||
|
|||||||
@@ -791,7 +791,7 @@ namespace NzbDrone.Common.Test.Http
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
// the date is bad in the below - should be 13-Jul-2026
|
// 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")
|
var requestSet = new HttpRequestBuilder($"https://{_httpBinHost}/response-headers")
|
||||||
.AddQueryParam("Set-Cookie", malformedCookie)
|
.AddQueryParam("Set-Cookie", malformedCookie)
|
||||||
.Build();
|
.Build();
|
||||||
@@ -825,7 +825,7 @@ namespace NzbDrone.Common.Test.Http
|
|||||||
{
|
{
|
||||||
try
|
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);
|
var requestSet = new HttpRequest(url);
|
||||||
requestSet.AllowAutoRedirect = false;
|
requestSet.AllowAutoRedirect = false;
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ namespace NzbDrone.Common.Test.InstrumentationTests
|
|||||||
// Indexer Urls
|
// Indexer Urls
|
||||||
[TestCase(@"https://iptorrents.com/torrents/rss?u=mySecret;tp=mySecret;l5;download")]
|
[TestCase(@"https://iptorrents.com/torrents/rss?u=mySecret;tp=mySecret;l5;download")]
|
||||||
[TestCase(@"http://rss.torrentleech.org/mySecret")]
|
[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(@"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://rss.omgwtfnzbs.org/rss-search.php?catid=19,20&user=Readarr&api=mySecret&eng=1")]
|
||||||
[TestCase(@"https://dognzb.cr/fetch/2b51db35e1912ffc138825a12b9933d2/2b51db35e1910123321025a12b9933d2")]
|
[TestCase(@"https://dognzb.cr/fetch/2b51db35e1912ffc138825a12b9933d2/2b51db35e1910123321025a12b9933d2")]
|
||||||
@@ -44,6 +46,7 @@ namespace NzbDrone.Common.Test.InstrumentationTests
|
|||||||
// Deluge
|
// Deluge
|
||||||
[TestCase(@",{""download_location"": ""C:\Users\\mySecret mySecret\\Downloads""}")]
|
[TestCase(@",{""download_location"": ""C:\Users\\mySecret mySecret\\Downloads""}")]
|
||||||
[TestCase(@",{""download_location"": ""/home/mySecret/Downloads""}")]
|
[TestCase(@",{""download_location"": ""/home/mySecret/Downloads""}")]
|
||||||
|
[TestCase(@",{""download_location"": ""/Users/mySecret/Downloads""}")]
|
||||||
[TestCase(@"auth.login(""mySecret"")")]
|
[TestCase(@"auth.login(""mySecret"")")]
|
||||||
|
|
||||||
// Download Station
|
// Download Station
|
||||||
@@ -56,8 +59,11 @@ namespace NzbDrone.Common.Test.InstrumentationTests
|
|||||||
|
|
||||||
// Internal
|
// Internal
|
||||||
[TestCase(@"OutputPath=/home/mySecret/Downloads")]
|
[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: /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 '/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("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("/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 ***")]
|
[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
|
continue; // Ignore directories
|
||||||
}
|
}
|
||||||
|
|
||||||
string entryFileName = zipEntry.Name;
|
var entryFileName = zipEntry.Name;
|
||||||
|
|
||||||
// to remove the folder from the entry:- entryFileName = Path.GetFileName(entryFileName);
|
// to remove the folder from the entry:- entryFileName = Path.GetFileName(entryFileName);
|
||||||
// Optionally match entrynames against a selection list here to skip as desired.
|
// Optionally match entrynames against a selection list here to skip as desired.
|
||||||
// The unpacked length is available in the zipEntry.Size property.
|
// The unpacked length is available in the zipEntry.Size property.
|
||||||
byte[] buffer = new byte[4096]; // 4K is optimum
|
var buffer = new byte[4096]; // 4K is optimum
|
||||||
Stream zipStream = zipFile.GetInputStream(zipEntry);
|
var zipStream = zipFile.GetInputStream(zipEntry);
|
||||||
|
|
||||||
// Manipulate the output filename here as desired.
|
// Manipulate the output filename here as desired.
|
||||||
string fullZipToPath = Path.Combine(destination, entryFileName);
|
var fullZipToPath = Path.Combine(destination, entryFileName);
|
||||||
string directoryName = Path.GetDirectoryName(fullZipToPath);
|
var directoryName = Path.GetDirectoryName(fullZipToPath);
|
||||||
if (directoryName.Length > 0)
|
if (directoryName.Length > 0)
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(directoryName);
|
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
|
// 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.
|
// of the file, but does not waste memory.
|
||||||
// The "using" will close the stream even if an exception occurs.
|
// 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);
|
StreamUtils.Copy(zipStream, streamWriter, buffer);
|
||||||
}
|
}
|
||||||
@@ -106,7 +106,7 @@ namespace NzbDrone.Common
|
|||||||
Stream inStream = File.OpenRead(compressedFile);
|
Stream inStream = File.OpenRead(compressedFile);
|
||||||
Stream gzipStream = new GZipInputStream(inStream);
|
Stream gzipStream = new GZipInputStream(inStream);
|
||||||
|
|
||||||
TarArchive tarArchive = TarArchive.CreateInputTarArchive(gzipStream, null);
|
var tarArchive = TarArchive.CreateInputTarArchive(gzipStream, null);
|
||||||
tarArchive.ExtractContents(destination);
|
tarArchive.ExtractContents(destination);
|
||||||
tarArchive.Close();
|
tarArchive.Close();
|
||||||
|
|
||||||
|
|||||||
@@ -54,8 +54,7 @@ namespace NzbDrone.Common.Cache
|
|||||||
|
|
||||||
public T Find(string key)
|
public T Find(string key)
|
||||||
{
|
{
|
||||||
CacheItem cacheItem;
|
if (!_store.TryGetValue(key, out var cacheItem))
|
||||||
if (!_store.TryGetValue(key, out cacheItem))
|
|
||||||
{
|
{
|
||||||
return default(T);
|
return default(T);
|
||||||
}
|
}
|
||||||
@@ -84,8 +83,7 @@ namespace NzbDrone.Common.Cache
|
|||||||
|
|
||||||
public void Remove(string key)
|
public void Remove(string key)
|
||||||
{
|
{
|
||||||
CacheItem value;
|
_store.TryRemove(key, out _);
|
||||||
_store.TryRemove(key, out value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Count => _store.Count;
|
public int Count => _store.Count;
|
||||||
@@ -96,9 +94,7 @@ namespace NzbDrone.Common.Cache
|
|||||||
|
|
||||||
lifeTime = lifeTime ?? _defaultLifeTime;
|
lifeTime = lifeTime ?? _defaultLifeTime;
|
||||||
|
|
||||||
CacheItem cacheItem;
|
if (_store.TryGetValue(key, out var cacheItem) && !cacheItem.IsExpired())
|
||||||
|
|
||||||
if (_store.TryGetValue(key, out cacheItem) && !cacheItem.IsExpired())
|
|
||||||
{
|
{
|
||||||
if (_rollingExpiry && lifeTime.HasValue)
|
if (_rollingExpiry && lifeTime.HasValue)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
@@ -86,9 +86,7 @@ namespace NzbDrone.Common.Cache
|
|||||||
{
|
{
|
||||||
RefreshIfExpired();
|
RefreshIfExpired();
|
||||||
|
|
||||||
TValue result;
|
if (!_items.TryGetValue(key, out var result))
|
||||||
|
|
||||||
if (!_items.TryGetValue(key, out result))
|
|
||||||
{
|
{
|
||||||
throw new KeyNotFoundException(string.Format("Item {0} not found in cache.", key));
|
throw new KeyNotFoundException(string.Format("Item {0} not found in cache.", key));
|
||||||
}
|
}
|
||||||
@@ -100,9 +98,7 @@ namespace NzbDrone.Common.Cache
|
|||||||
{
|
{
|
||||||
RefreshIfExpired();
|
RefreshIfExpired();
|
||||||
|
|
||||||
TValue result;
|
_items.TryGetValue(key, out var result);
|
||||||
|
|
||||||
_items.TryGetValue(key, out result);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -128,8 +124,7 @@ namespace NzbDrone.Common.Cache
|
|||||||
|
|
||||||
public void Remove(string key)
|
public void Remove(string key)
|
||||||
{
|
{
|
||||||
TValue item;
|
_items.TryRemove(key, out _);
|
||||||
_items.TryRemove(key, out item);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace NzbDrone.Common
|
namespace NzbDrone.Common
|
||||||
{
|
{
|
||||||
public static class ConvertBase32
|
public static class ConvertBase32
|
||||||
{
|
{
|
||||||
@@ -6,17 +6,17 @@
|
|||||||
|
|
||||||
public static byte[] FromBase32String(string str)
|
public static byte[] FromBase32String(string str)
|
||||||
{
|
{
|
||||||
int numBytes = str.Length * 5 / 8;
|
var numBytes = str.Length * 5 / 8;
|
||||||
byte[] bytes = new byte[numBytes];
|
var bytes = new byte[numBytes];
|
||||||
|
|
||||||
// all UPPERCASE chars
|
// all UPPERCASE chars
|
||||||
str = str.ToUpper();
|
str = str.ToUpper();
|
||||||
|
|
||||||
int bitBuffer = 0;
|
var bitBuffer = 0;
|
||||||
int bitBufferCount = 0;
|
var bitBufferCount = 0;
|
||||||
int index = 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]);
|
bitBuffer = (bitBuffer << 5) | ValidChars.IndexOf(str[i]);
|
||||||
bitBufferCount += 5;
|
bitBufferCount += 5;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using NzbDrone.Common.Extensions;
|
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;
|
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))
|
if (!string.Equals(leftFragments[i], rightFragments[i], stringComparison))
|
||||||
{
|
{
|
||||||
@@ -372,12 +372,12 @@ namespace NzbDrone.Common.Disk
|
|||||||
|
|
||||||
var newFragments = new List<string>();
|
var newFragments = new List<string>();
|
||||||
|
|
||||||
for (int j = i; j < rightFragments.Length; j++)
|
for (var j = i; j < rightFragments.Length; j++)
|
||||||
{
|
{
|
||||||
newFragments.Add("..");
|
newFragments.Add("..");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int j = i; j < leftFragments.Length; j++)
|
for (var j = i; j < leftFragments.Length; j++)
|
||||||
{
|
{
|
||||||
newFragments.Add(leftFragments[j]);
|
newFragments.Add(leftFragments[j]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@@ -107,7 +107,7 @@ namespace NzbDrone.Common.EnvironmentInfo
|
|||||||
|
|
||||||
private static string RunAndCapture(string filename, string args)
|
private static string RunAndCapture(string filename, string args)
|
||||||
{
|
{
|
||||||
Process p = new Process();
|
var p = new Process();
|
||||||
p.StartInfo.FileName = filename;
|
p.StartInfo.FileName = filename;
|
||||||
p.StartInfo.Arguments = args;
|
p.StartInfo.Arguments = args;
|
||||||
p.StartInfo.UseShellExecute = false;
|
p.StartInfo.UseShellExecute = false;
|
||||||
@@ -117,7 +117,7 @@ namespace NzbDrone.Common.EnvironmentInfo
|
|||||||
p.Start();
|
p.Start();
|
||||||
|
|
||||||
// To avoid deadlocks, always read the output stream first and then wait.
|
// 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);
|
p.WaitForExit(1000);
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
|
|||||||
@@ -356,34 +356,34 @@ namespace NzbDrone.Common.Extensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Computes the highest row in which the distance {@code p} appears
|
* Computes the highest row in which the distance {@code p} appears
|
||||||
* in diagonal {@code k} of the edit distance computation for
|
* in diagonal {@code k} of the edit distance computation for
|
||||||
* strings {@code a} and {@code b}. The diagonal number is
|
* strings {@code a} and {@code b}. The diagonal number is
|
||||||
* represented by the difference in the indices for the two strings;
|
* represented by the difference in the indices for the two strings;
|
||||||
* it can range from {@code -b.length()} through {@code a.length()}.
|
* it can range from {@code -b.length()} through {@code a.length()}.
|
||||||
*
|
*
|
||||||
* More precisely, this computes the highest value x such that
|
* More precisely, this computes the highest value x such that
|
||||||
* <pre>
|
* <pre>
|
||||||
* p = edit-distance(a[0:(x+k)), b[0:x)).
|
* p = edit-distance(a[0:(x+k)), b[0:x)).
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
* This is the "f" function described by Ukkonen.
|
* This is the "f" function described by Ukkonen.
|
||||||
*
|
*
|
||||||
* The caller must assure that abs(k) ≤ p, the only values for
|
* The caller must assure that abs(k) ≤ p, the only values for
|
||||||
* which this is well-defined.
|
* which this is well-defined.
|
||||||
*
|
*
|
||||||
* The implementation depends on the cached results of prior
|
* The implementation depends on the cached results of prior
|
||||||
* computeRow calls for diagonals k-1, k, and k+1 for distance p-1.
|
* computeRow calls for diagonals k-1, k, and k+1 for distance p-1.
|
||||||
* These must be supplied in {@code knownLeft}, {@code knownAbove},
|
* These must be supplied in {@code knownLeft}, {@code knownAbove},
|
||||||
* and {@code knownRight}, respectively.
|
* and {@code knownRight}, respectively.
|
||||||
* @param k diagonal number
|
* @param k diagonal number
|
||||||
* @param p edit distance
|
* @param p edit distance
|
||||||
* @param a one string to be compared
|
* @param a one string to be compared
|
||||||
* @param b other string to be compared
|
* @param b other string to be compared
|
||||||
* @param knownLeft value of {@code computeRow(k-1, p-1, ...)}
|
* @param knownLeft value of {@code computeRow(k-1, p-1, ...)}
|
||||||
* @param knownAbove value of {@code computeRow(k, p-1, ...)}
|
* @param knownAbove value of {@code computeRow(k, p-1, ...)}
|
||||||
* @param knownRight value of {@code computeRow(k+1, p-1, ...)}
|
* @param knownRight value of {@code computeRow(k+1, p-1, ...)}
|
||||||
*/
|
*/
|
||||||
private static int ComputeRow(int k,
|
private static int ComputeRow(int k,
|
||||||
int p,
|
int p,
|
||||||
char[] a,
|
char[] a,
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ namespace NzbDrone.Common.Extensions
|
|||||||
|
|
||||||
for (var j = finish; j >= start; j--)
|
for (var j = finish; j >= start; j--)
|
||||||
{
|
{
|
||||||
T charMatch = charMatches[j - 1];
|
var charMatch = charMatches[j - 1];
|
||||||
|
|
||||||
if (d == 0)
|
if (d == 0)
|
||||||
{
|
{
|
||||||
@@ -181,7 +181,7 @@ namespace NzbDrone.Common.Extensions
|
|||||||
// match. But check anyway.
|
// match. But check anyway.
|
||||||
var score = BitapScore(d, pattern);
|
var score = BitapScore(d, pattern);
|
||||||
|
|
||||||
bool isOnWordBoundary = true;
|
var isOnWordBoundary = true;
|
||||||
|
|
||||||
if (wordDelimiters != null)
|
if (wordDelimiters != null)
|
||||||
{
|
{
|
||||||
@@ -233,8 +233,8 @@ namespace NzbDrone.Common.Extensions
|
|||||||
return new List<char>();
|
return new List<char>();
|
||||||
}
|
}
|
||||||
|
|
||||||
char curr = text[j - 1];
|
var curr = text[j - 1];
|
||||||
bool take = true;
|
var take = true;
|
||||||
|
|
||||||
if (!s.TryGetValue(curr, out var charMatch))
|
if (!s.TryGetValue(curr, out var charMatch))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -255,13 +255,13 @@ namespace NzbDrone.Common.Extensions
|
|||||||
var firstPath = paths.First();
|
var firstPath = paths.First();
|
||||||
var length = firstPath.Length;
|
var length = firstPath.Length;
|
||||||
|
|
||||||
for (int i = 1; i < paths.Count; i++)
|
for (var i = 1; i < paths.Count; i++)
|
||||||
{
|
{
|
||||||
var path = paths[i];
|
var path = paths[i];
|
||||||
|
|
||||||
length = Math.Min(length, path.Length);
|
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])
|
if (path[characterIndex] != firstPath[characterIndex])
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -188,11 +188,11 @@ namespace NzbDrone.Common.Extensions
|
|||||||
{
|
{
|
||||||
double weightDenom = Math.Max(a.Length, b.Length);
|
double weightDenom = Math.Max(a.Length, b.Length);
|
||||||
double sum = 0;
|
double sum = 0;
|
||||||
for (int i = 0; i < a.Length; i++)
|
for (var i = 0; i < a.Length; i++)
|
||||||
{
|
{
|
||||||
double high = 0.0;
|
var high = 0.0;
|
||||||
int indexDistance = 0;
|
var indexDistance = 0;
|
||||||
for (int x = 0; x < b.Length; x++)
|
for (var x = 0; x < b.Length; x++)
|
||||||
{
|
{
|
||||||
var coef = LevenshteinCoefficient(a[i], b[x]);
|
var coef = LevenshteinCoefficient(a[i], b[x]);
|
||||||
if (coef > high)
|
if (coef > high)
|
||||||
|
|||||||
@@ -6,9 +6,7 @@ namespace NzbDrone.Common.Extensions
|
|||||||
{
|
{
|
||||||
public static int? ParseInt32(this string source)
|
public static int? ParseInt32(this string source)
|
||||||
{
|
{
|
||||||
int result;
|
if (int.TryParse(source, out var result))
|
||||||
|
|
||||||
if (int.TryParse(source, out result))
|
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -18,9 +16,7 @@ namespace NzbDrone.Common.Extensions
|
|||||||
|
|
||||||
public static long? ParseInt64(this string source)
|
public static long? ParseInt64(this string source)
|
||||||
{
|
{
|
||||||
long result;
|
if (long.TryParse(source, out var result))
|
||||||
|
|
||||||
if (long.TryParse(source, out result))
|
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -30,9 +26,7 @@ namespace NzbDrone.Common.Extensions
|
|||||||
|
|
||||||
public static double? ParseDouble(this string source)
|
public static double? ParseDouble(this string source)
|
||||||
{
|
{
|
||||||
double result;
|
if (double.TryParse(source.Replace(',', '.'), NumberStyles.Number, CultureInfo.InvariantCulture, out var result))
|
||||||
|
|
||||||
if (double.TryParse(source.Replace(',', '.'), NumberStyles.Number, CultureInfo.InvariantCulture, out result))
|
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace NzbDrone.Common
|
namespace NzbDrone.Common
|
||||||
@@ -7,9 +7,9 @@ namespace NzbDrone.Common
|
|||||||
{
|
{
|
||||||
public static string CalculateCrc(string input)
|
public static string CalculateCrc(string input)
|
||||||
{
|
{
|
||||||
uint mCrc = 0xffffffff;
|
var mCrc = 0xffffffff;
|
||||||
byte[] bytes = Encoding.UTF8.GetBytes(input);
|
var bytes = Encoding.UTF8.GetBytes(input);
|
||||||
foreach (byte myByte in bytes)
|
foreach (var myByte in bytes)
|
||||||
{
|
{
|
||||||
mCrc ^= (uint)myByte << 24;
|
mCrc ^= (uint)myByte << 24;
|
||||||
for (var i = 0; i < 8; i++)
|
for (var i = 0; i < 8; i++)
|
||||||
|
|||||||
@@ -60,8 +60,7 @@ namespace NzbDrone.Common.Http
|
|||||||
|
|
||||||
if (request.AllowAutoRedirect && response.HasHttpRedirect)
|
if (request.AllowAutoRedirect && response.HasHttpRedirect)
|
||||||
{
|
{
|
||||||
var autoRedirectChain = new List<string>();
|
var autoRedirectChain = new List<string> { request.Url.ToString() };
|
||||||
autoRedirectChain.Add(request.Url.ToString());
|
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@@ -75,6 +74,14 @@ namespace NzbDrone.Common.Http
|
|||||||
throw new WebException($"Too many automatic redirections were attempted for {autoRedirectChain.Join(" -> ")}", WebExceptionStatus.ProtocolError);
|
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);
|
response = ExecuteRequest(request, cookieContainer);
|
||||||
}
|
}
|
||||||
while (response.HasHttpRedirect);
|
while (response.HasHttpRedirect);
|
||||||
@@ -105,6 +112,16 @@ namespace NzbDrone.Common.Http
|
|||||||
return response;
|
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)
|
private HttpResponse ExecuteRequest(HttpRequest request, CookieContainer cookieContainer)
|
||||||
{
|
{
|
||||||
foreach (var interceptor in _requestInterceptors)
|
foreach (var interceptor in _requestInterceptors)
|
||||||
|
|||||||
@@ -50,6 +50,8 @@ namespace NzbDrone.Common.Http
|
|||||||
|
|
||||||
public bool HasHttpError => (int)StatusCode >= 400;
|
public bool HasHttpError => (int)StatusCode >= 400;
|
||||||
|
|
||||||
|
public bool HasHttpServerError => (int)StatusCode >= 500;
|
||||||
|
|
||||||
public bool HasHttpRedirect => StatusCode == HttpStatusCode.Moved ||
|
public bool HasHttpRedirect => StatusCode == HttpStatusCode.Moved ||
|
||||||
StatusCode == HttpStatusCode.MovedPermanently ||
|
StatusCode == HttpStatusCode.MovedPermanently ||
|
||||||
StatusCode == HttpStatusCode.Found ||
|
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)
|
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())
|
if (scheme.IsNotNullOrWhiteSpace())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
|
|
||||||
namespace NzbDrone.Common.Http.Proxy
|
namespace NzbDrone.Common.Http.Proxy
|
||||||
{
|
{
|
||||||
@@ -30,7 +30,7 @@ namespace NzbDrone.Common.Http.Proxy
|
|||||||
if (!string.IsNullOrWhiteSpace(BypassFilter))
|
if (!string.IsNullOrWhiteSpace(BypassFilter))
|
||||||
{
|
{
|
||||||
var hostlist = BypassFilter.Split(',');
|
var hostlist = BypassFilter.Split(',');
|
||||||
for (int i = 0; i < hostlist.Length; i++)
|
for (var i = 0; i < hostlist.Length; i++)
|
||||||
{
|
{
|
||||||
if (hostlist[i].StartsWith("*"))
|
if (hostlist[i].StartsWith("*"))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -12,14 +12,12 @@ namespace NzbDrone.Common.Http
|
|||||||
if (response.Headers.ContainsKey("Retry-After"))
|
if (response.Headers.ContainsKey("Retry-After"))
|
||||||
{
|
{
|
||||||
var retryAfter = response.Headers["Retry-After"].ToString();
|
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);
|
RetryAfter = TimeSpan.FromSeconds(seconds);
|
||||||
}
|
}
|
||||||
else if (DateTime.TryParse(retryAfter, out date))
|
else if (DateTime.TryParse(retryAfter, out var date))
|
||||||
{
|
{
|
||||||
RetryAfter = date.ToUniversalTime() - DateTime.UtcNow;
|
RetryAfter = date.ToUniversalTime() - DateTime.UtcNow;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,56 +7,56 @@ namespace NzbDrone.Common.Instrumentation
|
|||||||
{
|
{
|
||||||
public class CleanseLogMessage
|
public class CleanseLogMessage
|
||||||
{
|
{
|
||||||
private static readonly Regex[] CleansingRules = new[]
|
private static readonly Regex[] CleansingRules =
|
||||||
{
|
{
|
||||||
// Url
|
// Url
|
||||||
new Regex(@"(?<=\?|&|: )((?:api|auth|pass)?key|(?:access[-_]?)?token|auth|user|uid|api|[a-z_]*apikey|account|passwd)=(?<secret>[^&=""]+?)(?=[ ""&=]|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
new (@"(?<=\?|&|: )((?: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 (@"(?<=\?|&)[^=]*?(username|password)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||||
new Regex(@"torrentleech\.org/(?!rss)(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
new (@"rss(24h)?\.torrentleech\.org/(?!rss)(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||||
new Regex(@"torrentleech\.org/rss/download/[0-9]+/(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
new (@"torrentleech\.org/rss/download/[0-9]+/(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||||
new Regex(@"iptorrents\.com/[/a-z0-9?&;]*?(?:[?&;](u|tp)=(?<secret>[^&=;]+?))+(?= |;|&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
new (@"iptorrents\.com/[/a-z0-9?&;]*?(?:[?&;](u|tp)=(?<secret>[^&=;]+?))+(?= |;|&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||||
new Regex(@"/fetch/[a-z0-9]{32}/(?<secret>[a-z0-9]{32})", RegexOptions.Compiled),
|
new (@"/fetch/[a-z0-9]{32}/(?<secret>[a-z0-9]{32})", RegexOptions.Compiled),
|
||||||
new Regex(@"getnzb.*?(?<=\?|&)(r)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
new (@"getnzb.*?(?<=\?|&)(r)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||||
new Regex(@"\b(\w*)?(_?(?<!use|get_)token|username|passwo?rd)=(?<secret>[^&=]+?)(?= |&|$|;)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
new (@"\b(\w*)?(_?(?<!use|get_)token|username|passwo?rd)=(?<secret>[^&=]+?)(?= |&|$|;)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||||
|
|
||||||
// Trackers Announce Keys; Designed for Qbit Json; should work for all in theory
|
// Trackers Announce Keys; Designed for Qbit Json; should work for all in theory
|
||||||
new Regex(@"announce(\.php)?(/|%2f|%3fpasskey%3d)(?<secret>[a-z0-9]{16,})|(?<secret>[a-z0-9]{16,})(/|%2f)announce"),
|
new (@"announce(\.php)?(/|%2f|%3fpasskey%3d)(?<secret>[a-z0-9]{16,})|(?<secret>[a-z0-9]{16,})(/|%2f)announce"),
|
||||||
|
|
||||||
// Path
|
// Path
|
||||||
new Regex(@"C:\\Users\\(?<secret>[^\""]+?)(\\|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
new (@"C:\\Users\\(?<secret>[^\""]+?)(\\|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||||
new Regex(@"/home/(?<secret>[^/""]+?)(/|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
new (@"/(home|Users)/(?<secret>[^/""]+?)(/|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||||
|
|
||||||
// NzbGet
|
// NzbGet
|
||||||
new Regex(@"""Name""\s*:\s*""[^""]*(username|password)""\s*,\s*""Value""\s*:\s*""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
new (@"""Name""\s*:\s*""[^""]*(username|password)""\s*,\s*""Value""\s*:\s*""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||||
|
|
||||||
// Sabnzbd
|
// Sabnzbd
|
||||||
new Regex(@"""[^""]*(username|password|api_?key|nzb_key)""\s*:\s*""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
new (@"""[^""]*(username|password|api_?key|nzb_key)""\s*:\s*""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||||
new Regex(@"""email_(account|to|from|pwd)""\s*:\s*""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
new (@"""email_(account|to|from|pwd)""\s*:\s*""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||||
|
|
||||||
// uTorrent
|
// uTorrent
|
||||||
new Regex(@"\[""[a-z._]*(username|password)"",\d,""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
new (@"\[""[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),
|
new (@"\[""(boss_key|boss_key_salt|proxy\.proxy)"",\d,""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||||
|
|
||||||
// Deluge
|
// Deluge
|
||||||
new Regex(@"auth.login\(""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
new (@"auth.login\(""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||||
|
|
||||||
// BroadcastheNet
|
// BroadcastheNet
|
||||||
new Regex(@"""?method""?\s*:\s*""(getTorrents)"",\s*""?params""?\s*:\s*\[\s*""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
new (@"""?method""?\s*:\s*""(getTorrents)"",\s*""?params""?\s*:\s*\[\s*""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||||
new Regex(@"getTorrents\(""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
new (@"getTorrents\(""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||||
new Regex(@"(?<=\?|&)(authkey|torrent_pass)=(?<secret>[^&=]+?)(?=""|&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
new (@"(?<=\?|&)(authkey|torrent_pass)=(?<secret>[^&=]+?)(?=""|&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||||
|
|
||||||
// Good Reads
|
// Good Reads
|
||||||
new Regex(@"(?<=""(token|tokensecret)"":\s)""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
new (@"(?<=""(token|tokensecret)"":\s)""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||||
|
|
||||||
// Webhooks
|
// Webhooks
|
||||||
// Notifiarr
|
// Notifiarr
|
||||||
new Regex(@"api/v[0-9]/notification/readarr/(?<secret>[\w-]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
new (@"api/v[0-9]/notification/readarr/(?<secret>[\w-]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||||
|
|
||||||
// Discord
|
// Discord
|
||||||
new Regex(@"discord.com/api/webhooks/((?<secret>[\w-]+)/)?(?<secret>[\w-]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase)
|
new (@"discord.com/api/webhooks/((?<secret>[\w-]+)/)?(?<secret>[\w-]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase)
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly Regex CleanseRemoteIPRegex = new 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)
|
public static string Cleanse(string message)
|
||||||
{
|
{
|
||||||
@@ -68,15 +68,15 @@ namespace NzbDrone.Common.Instrumentation
|
|||||||
foreach (var regex in CleansingRules)
|
foreach (var regex in CleansingRules)
|
||||||
{
|
{
|
||||||
message = regex.Replace(message, m =>
|
message = regex.Replace(message, m =>
|
||||||
|
{
|
||||||
|
var value = m.Value;
|
||||||
|
foreach (var capture in m.Groups["secret"].Captures.OfType<Capture>().Reverse())
|
||||||
{
|
{
|
||||||
var value = m.Value;
|
value = value.Replace(capture.Index - m.Index, capture.Length, "(removed)");
|
||||||
foreach (var capture in m.Groups["secret"].Captures.OfType<Capture>().Reverse())
|
}
|
||||||
{
|
|
||||||
value = value.Replace(capture.Index - m.Index, capture.Length, "(removed)");
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
message = CleanseRemoteIPRegex.Replace(message, CleanseRemoteIP);
|
message = CleanseRemoteIPRegex.Replace(message, CleanseRemoteIP);
|
||||||
@@ -87,7 +87,6 @@ namespace NzbDrone.Common.Instrumentation
|
|||||||
private static string CleanseRemoteIP(Match match)
|
private static string CleanseRemoteIP(Match match)
|
||||||
{
|
{
|
||||||
var group = match.Groups[1];
|
var group = match.Groups[1];
|
||||||
var valueAll = match.Value;
|
|
||||||
var valueIP = group.Value;
|
var valueIP = group.Value;
|
||||||
|
|
||||||
if (IPAddress.TryParse(valueIP, out var address) && !address.IsLocalAddress())
|
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;
|
using NzbDrone.Common.Serializer;
|
||||||
|
|
||||||
namespace NzbDrone.Common.Instrumentation
|
namespace NzbDrone.Common.Instrumentation
|
||||||
@@ -16,7 +16,7 @@ namespace NzbDrone.Common.Instrumentation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (JToken token in json)
|
foreach (var token in json)
|
||||||
{
|
{
|
||||||
Visit(token);
|
Visit(token);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ namespace NzbDrone.Common.Instrumentation
|
|||||||
|
|
||||||
private static void RegisterDebugger()
|
private static void RegisterDebugger()
|
||||||
{
|
{
|
||||||
DebuggerTarget target = new DebuggerTarget();
|
var target = new DebuggerTarget();
|
||||||
target.Name = "debuggerLogger";
|
target.Name = "debuggerLogger";
|
||||||
target.Layout = "[${level}] [${threadid}] ${logger}: ${message} ${onexception:inner=${newline}${newline}[v${assembly-version}] ${exception:format=ToString}${newline}${exception:format=Data}${newline}}";
|
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 =>
|
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("Microsoft.Hosting.Lifetime*").WriteToNil(LogLevel.Info);
|
||||||
c.ForLogger("System*").WriteToNil(LogLevel.Warn);
|
c.ForLogger("Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware").WriteToNil(LogLevel.Fatal);
|
||||||
c.ForLogger("Microsoft*").WriteToNil(LogLevel.Warn);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ namespace NzbDrone.Common.OAuth
|
|||||||
public virtual string Version { get; set; }
|
public virtual string Version { get; set; }
|
||||||
public virtual string SessionHandle { 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 string RequestUrl { get; set; }
|
||||||
public virtual Dictionary<string, string> Parameters { 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
|
namespace NzbDrone.Common.Serializer
|
||||||
{
|
{
|
||||||
@@ -60,7 +60,7 @@ namespace NzbDrone.Common.Serializer
|
|||||||
|
|
||||||
public virtual void Visit(JArray json)
|
public virtual void Visit(JArray json)
|
||||||
{
|
{
|
||||||
foreach (JToken token in json)
|
foreach (var token in json)
|
||||||
{
|
{
|
||||||
Visit(token);
|
Visit(token);
|
||||||
}
|
}
|
||||||
@@ -72,7 +72,7 @@ namespace NzbDrone.Common.Serializer
|
|||||||
|
|
||||||
public virtual void Visit(JObject json)
|
public virtual void Visit(JObject json)
|
||||||
{
|
{
|
||||||
foreach (JProperty property in json.Properties())
|
foreach (var property in json.Properties())
|
||||||
{
|
{
|
||||||
Visit(property);
|
Visit(property);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ namespace NzbDrone.Common.Serializer
|
|||||||
var enumText = value.ToString();
|
var enumText = value.ToString();
|
||||||
var builder = new StringBuilder(enumText.Length + 4);
|
var builder = new StringBuilder(enumText.Length + 4);
|
||||||
builder.Append(char.ToLower(enumText[0]));
|
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]))
|
if (char.IsUpper(enumText[i]))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ namespace NzbDrone.Common.Serializer
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Version v = new Version(reader.GetString());
|
var v = new Version(reader.GetString());
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@@ -137,7 +137,7 @@ namespace NzbDrone.Common.TPL
|
|||||||
/// <returns>An enumerable of the tasks currently scheduled.</returns>
|
/// <returns>An enumerable of the tasks currently scheduled.</returns>
|
||||||
protected sealed override IEnumerable<Task> GetScheduledTasks()
|
protected sealed override IEnumerable<Task> GetScheduledTasks()
|
||||||
{
|
{
|
||||||
bool lockTaken = false;
|
var lockTaken = false;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Monitor.TryEnter(_tasks, ref lockTaken);
|
Monitor.TryEnter(_tasks, ref lockTaken);
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ namespace NzbDrone.Console
|
|||||||
}
|
}
|
||||||
|
|
||||||
System.Console.WriteLine("Non-recoverable failure, waiting for user intervention...");
|
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);
|
System.Threading.Thread.Sleep(1000);
|
||||||
|
|
||||||
|
|||||||
@@ -197,7 +197,7 @@ namespace NzbDrone.Core.Test.Datastore
|
|||||||
|
|
||||||
Subject.SetFields(_basicList, x => x.Interval);
|
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];
|
_basicList[i].LastExecution = executionBackup[i];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||||||
[Test]
|
[Test]
|
||||||
public void should_return_true_if_cutoffs_are_met_but_is_a_revision_upgrade()
|
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,
|
Cutoff = Quality.MP3.Id,
|
||||||
Items = Qualities.QualityFixture.GetDefaultQualities(),
|
Items = Qualities.QualityFixture.GetDefaultQualities(),
|
||||||
@@ -104,7 +104,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||||||
[Test]
|
[Test]
|
||||||
public void should_return_false_if_quality_profile_does_not_allow_upgrades_but_cutoff_is_set_to_highest_quality()
|
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,
|
Cutoff = Quality.FLAC.Id,
|
||||||
Items = Qualities.QualityFixture.GetDefaultQualities(),
|
Items = Qualities.QualityFixture.GetDefaultQualities(),
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole
|
|||||||
VerifySingleItem(DownloadItemStatus.Downloading);
|
VerifySingleItem(DownloadItemStatus.Downloading);
|
||||||
|
|
||||||
// If we keep changing the file every 20ms we should stay 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);
|
TestLogger.Info("Iteration {0}", i);
|
||||||
|
|
||||||
|
|||||||
@@ -225,6 +225,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests
|
|||||||
[TestCase("checkingDL")]
|
[TestCase("checkingDL")]
|
||||||
[TestCase("checkingUP")]
|
[TestCase("checkingUP")]
|
||||||
[TestCase("metaDL")]
|
[TestCase("metaDL")]
|
||||||
|
[TestCase("checkingResumeData")]
|
||||||
public void queued_item_should_have_required_properties(string state)
|
public void queued_item_should_have_required_properties(string state)
|
||||||
{
|
{
|
||||||
var torrent = new QBittorrentTorrent
|
var torrent = new QBittorrentTorrent
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
@@ -57,7 +57,7 @@ namespace NzbDrone.Core.Test
|
|||||||
[Test]
|
[Test]
|
||||||
public void ToBestDateTime_DayOfWeek()
|
public void ToBestDateTime_DayOfWeek()
|
||||||
{
|
{
|
||||||
for (int i = 2; i < 7; i++)
|
for (var i = 2; i < 7; i++)
|
||||||
{
|
{
|
||||||
var dateTime = DateTime.Today.AddDays(i);
|
var dateTime = DateTime.Today.AddDays(i);
|
||||||
|
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
|
|||||||
[Test]
|
[Test]
|
||||||
public void should_return_ok_if_not_downloading_to_root_folder()
|
public void should_return_ok_if_not_downloading_to_root_folder()
|
||||||
{
|
{
|
||||||
string rootFolderPath = "c:\\Test2".AsOsAgnostic();
|
var rootFolderPath = "c:\\Test2".AsOsAgnostic();
|
||||||
|
|
||||||
GivenRootFolder(rootFolderPath);
|
GivenRootFolder(rootFolderPath);
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ namespace NzbDrone.Core.Test.Instrumentation
|
|||||||
public void write_long_log()
|
public void write_long_log()
|
||||||
{
|
{
|
||||||
var message = string.Empty;
|
var message = string.Empty;
|
||||||
for (int i = 0; i < 100; i++)
|
for (var i = 0; i < 100; i++)
|
||||||
{
|
{
|
||||||
message += Guid.NewGuid();
|
message += Guid.NewGuid();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ namespace NzbDrone.Core.Test.MediaFiles.BookImport.Aggregation.Aggregators
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
int i = 0;
|
var i = 0;
|
||||||
|
|
||||||
foreach (var tokens in tokenList)
|
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)
|
private List<string> GivenFilenames(string[] fields, string fieldSeparator, string whitespace)
|
||||||
{
|
{
|
||||||
var outp = new List<string>();
|
var outp = new List<string>();
|
||||||
for (int i = 1; i <= 3; i++)
|
for (var i = 1; i <= 3; i++)
|
||||||
{
|
{
|
||||||
var components = new List<string>();
|
var components = new List<string>();
|
||||||
foreach (var field in fields)
|
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)
|
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;
|
var info = tracks[i - 1].FileTrackInfo;
|
||||||
|
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ namespace NzbDrone.Core.Test.MediaFiles.BookImport.Identification
|
|||||||
Mocker.SetConstant<ICandidateService>(Mocker.Resolve<CandidateService>());
|
Mocker.SetConstant<ICandidateService>(Mocker.Resolve<CandidateService>());
|
||||||
|
|
||||||
// set up the augmenters
|
// set up the augmenters
|
||||||
List<IAggregate<LocalEdition>> aggregators = new List<IAggregate<LocalEdition>>
|
var aggregators = new List<IAggregate<LocalEdition>>
|
||||||
{
|
{
|
||||||
Mocker.Resolve<AggregateFilenameInfo>()
|
Mocker.Resolve<AggregateFilenameInfo>()
|
||||||
};
|
};
|
||||||
@@ -89,7 +89,7 @@ namespace NzbDrone.Core.Test.MediaFiles.BookImport.Identification
|
|||||||
private List<Author> GivenAuthors(List<AuthorTestCase> authors)
|
private List<Author> GivenAuthors(List<AuthorTestCase> authors)
|
||||||
{
|
{
|
||||||
var outp = new List<Author>();
|
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;
|
var meta = authors[i].MetadataProfile;
|
||||||
meta.Id = i + 1;
|
meta.Id = i + 1;
|
||||||
|
|||||||
@@ -30,17 +30,17 @@ namespace NzbDrone.Core.Test.MediaFiles.BookImport.Identification
|
|||||||
static RandomValueNamerShortStrings()
|
static RandomValueNamerShortStrings()
|
||||||
{
|
{
|
||||||
AllowedChars = new List<char>();
|
AllowedChars = new List<char>();
|
||||||
for (char c = 'a'; c < 'z'; c++)
|
for (var c = 'a'; c < 'z'; c++)
|
||||||
{
|
{
|
||||||
AllowedChars.Add(c);
|
AllowedChars.Add(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (char c = 'A'; c < 'Z'; c++)
|
for (var c = 'A'; c < 'Z'; c++)
|
||||||
{
|
{
|
||||||
AllowedChars.Add(c);
|
AllowedChars.Add(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (char c = '0'; c < '9'; c++)
|
for (var c = '0'; c < '9'; c++)
|
||||||
{
|
{
|
||||||
AllowedChars.Add(c);
|
AllowedChars.Add(c);
|
||||||
}
|
}
|
||||||
@@ -48,17 +48,17 @@ namespace NzbDrone.Core.Test.MediaFiles.BookImport.Identification
|
|||||||
|
|
||||||
protected override string GetString(MemberInfo memberInfo)
|
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];
|
chars[i] = AllowedChars[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] bytes = Encoding.UTF8.GetBytes(chars);
|
var bytes = Encoding.UTF8.GetBytes(chars);
|
||||||
return Encoding.UTF8.GetString(bytes, 0, bytes.Length);
|
return Encoding.UTF8.GetString(bytes, 0, bytes.Length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -90,7 +90,7 @@ namespace NzbDrone.Core.Test.MediaFiles.BookImport.Identification
|
|||||||
{
|
{
|
||||||
var outp = new List<LocalBook>();
|
var outp = new List<LocalBook>();
|
||||||
|
|
||||||
for (int i = 0; i < count; i++)
|
for (var i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
var track = Builder<LocalBook>
|
var track = Builder<LocalBook>
|
||||||
.CreateNew()
|
.CreateNew()
|
||||||
@@ -283,7 +283,7 @@ namespace NzbDrone.Core.Test.MediaFiles.BookImport.Identification
|
|||||||
public void should_separate_many_books_in_same_directory()
|
public void should_separate_many_books_in_same_directory()
|
||||||
{
|
{
|
||||||
var tracks = new List<LocalBook>();
|
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));
|
tracks.AddRange(GivenTracks($"C:\\music".AsOsAgnostic(), "author" + i, "book" + i, 10));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ namespace NzbDrone.Core.Test.MetadataSource.Goodreads.Resources
|
|||||||
[Test]
|
[Test]
|
||||||
public void parse_non_work()
|
public void parse_non_work()
|
||||||
{
|
{
|
||||||
XElement element = new XElement("Dummy", "entry");
|
var element = new XElement("Dummy", "entry");
|
||||||
WorkResource work = new WorkResource();
|
var work = new WorkResource();
|
||||||
|
|
||||||
Assert.Throws<NullReferenceException>(() => work.Parse(element));
|
Assert.Throws<NullReferenceException>(() => work.Parse(element));
|
||||||
|
|
||||||
@@ -27,11 +27,11 @@ namespace NzbDrone.Core.Test.MetadataSource.Goodreads.Resources
|
|||||||
[Test]
|
[Test]
|
||||||
public void parse_minimal_work()
|
public void parse_minimal_work()
|
||||||
{
|
{
|
||||||
XElement element = new XElement("work",
|
var element = new XElement("work",
|
||||||
new XElement("original_title", "Book Title"),
|
new XElement("original_title", "Book Title"),
|
||||||
new XElement("id", "123456789"));
|
new XElement("id", "123456789"));
|
||||||
|
|
||||||
WorkResource work = new WorkResource();
|
var work = new WorkResource();
|
||||||
|
|
||||||
work.Parse(element);
|
work.Parse(element);
|
||||||
|
|
||||||
@@ -44,12 +44,12 @@ namespace NzbDrone.Core.Test.MetadataSource.Goodreads.Resources
|
|||||||
[Test]
|
[Test]
|
||||||
public void parse_minimal_work_with_surrounding_tags()
|
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("work",
|
||||||
new XElement("original_title", "Book Title"),
|
new XElement("original_title", "Book Title"),
|
||||||
new XElement("id", "123456789")));
|
new XElement("id", "123456789")));
|
||||||
|
|
||||||
WorkResource work = new WorkResource();
|
var work = new WorkResource();
|
||||||
|
|
||||||
work.Parse(element);
|
work.Parse(element);
|
||||||
|
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ namespace NzbDrone.Core.Test.MusicTests.AuthorRepositoryTests
|
|||||||
{
|
{
|
||||||
GivenAuthors();
|
GivenAuthors();
|
||||||
|
|
||||||
string name = "Alice Cooper";
|
var name = "Alice Cooper";
|
||||||
AddAuthor(name, "ee58c59f-8e7f-4430-b8ca-236c4d3745ae");
|
AddAuthor(name, "ee58c59f-8e7f-4430-b8ca-236c4d3745ae");
|
||||||
AddAuthor(name, "4d7928cd-7ed2-4282-8c29-c0c9f966f1bd");
|
AddAuthor(name, "4d7928cd-7ed2-4282-8c29-c0c9f966f1bd");
|
||||||
|
|
||||||
|
|||||||
@@ -39,13 +39,13 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||||||
[Test]
|
[Test]
|
||||||
public void should_not_parse_md5()
|
public void should_not_parse_md5()
|
||||||
{
|
{
|
||||||
string hash = "CRAPPY TEST SEED";
|
var hash = "CRAPPY TEST SEED";
|
||||||
|
|
||||||
var hashAlgo = System.Security.Cryptography.MD5.Create();
|
var hashAlgo = System.Security.Cryptography.MD5.Create();
|
||||||
|
|
||||||
var repetitions = 100;
|
var repetitions = 100;
|
||||||
var success = 0;
|
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));
|
var hashData = hashAlgo.ComputeHash(System.Text.Encoding.Default.GetBytes(hash));
|
||||||
|
|
||||||
@@ -64,17 +64,17 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||||||
[TestCase(40)]
|
[TestCase(40)]
|
||||||
public void should_not_parse_random(int length)
|
public void should_not_parse_random(int length)
|
||||||
{
|
{
|
||||||
string charset = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
var charset = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
|
|
||||||
var hashAlgo = new Random();
|
var hashAlgo = new Random();
|
||||||
|
|
||||||
var repetitions = 500;
|
var repetitions = 500;
|
||||||
var success = 0;
|
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]);
|
hash.Append(charset[hashAlgo.Next() % charset.Length]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ namespace NzbDrone.Core.Test.Profiles.Delay
|
|||||||
var moving = _last;
|
var moving = _last;
|
||||||
var result = Subject.Reorder(moving.Id, null).OrderBy(d => d.Order).ToList();
|
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];
|
var delayProfile = result[i];
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ namespace NzbDrone.Core.Annotations
|
|||||||
public string Label { get; set; }
|
public string Label { get; set; }
|
||||||
public string Unit { get; set; }
|
public string Unit { get; set; }
|
||||||
public string HelpText { get; set; }
|
public string HelpText { get; set; }
|
||||||
|
public string HelpTextWarning { get; set; }
|
||||||
public string HelpLink { get; set; }
|
public string HelpLink { get; set; }
|
||||||
public FieldType Type { get; set; }
|
public FieldType Type { get; set; }
|
||||||
public bool Advanced { 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 existingMetadata = FindById(data.Select(x => x.ForeignAuthorId).ToList());
|
||||||
var updateMetadataList = new List<AuthorMetadata>();
|
var updateMetadataList = new List<AuthorMetadata>();
|
||||||
var addMetadataList = new List<AuthorMetadata>();
|
var addMetadataList = new List<AuthorMetadata>();
|
||||||
int upToDateMetadataCount = 0;
|
var upToDateMetadataCount = 0;
|
||||||
|
|
||||||
foreach (var meta in data)
|
foreach (var meta in data)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ namespace NzbDrone.Core.Books
|
|||||||
Author FindByName(string cleanName);
|
Author FindByName(string cleanName);
|
||||||
Author FindById(string foreignAuthorId);
|
Author FindById(string foreignAuthorId);
|
||||||
Dictionary<int, string> AllAuthorPaths();
|
Dictionary<int, string> AllAuthorPaths();
|
||||||
|
Dictionary<int, List<int>> AllAuthorTags();
|
||||||
Author GetAuthorByMetadataId(int authorMetadataId);
|
Author GetAuthorByMetadataId(int authorMetadataId);
|
||||||
List<Author> GetAuthorsByMetadataId(IEnumerable<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)
|
public Author GetAuthorByMetadataId(int authorMetadataId)
|
||||||
{
|
{
|
||||||
return Query(s => s.AuthorMetadataId == authorMetadataId).SingleOrDefault();
|
return Query(s => s.AuthorMetadataId == authorMetadataId).SingleOrDefault();
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ namespace NzbDrone.Core.Books
|
|||||||
if (_authorService.AuthorPathExists(path))
|
if (_authorService.AuthorPathExists(path))
|
||||||
{
|
{
|
||||||
var basepath = path;
|
var basepath = path;
|
||||||
int i = 0;
|
var i = 0;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
i++;
|
i++;
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ namespace NzbDrone.Core.Books
|
|||||||
List<Author> GetReportCandidates(string reportTitle);
|
List<Author> GetReportCandidates(string reportTitle);
|
||||||
void DeleteAuthor(int authorId, bool deleteFiles, bool addImportListExclusion = false);
|
void DeleteAuthor(int authorId, bool deleteFiles, bool addImportListExclusion = false);
|
||||||
List<Author> GetAllAuthors();
|
List<Author> GetAllAuthors();
|
||||||
|
Dictionary<int, List<int>> GetAllAuthorTags();
|
||||||
List<Author> AllForTag(int tagId);
|
List<Author> AllForTag(int tagId);
|
||||||
Author UpdateAuthor(Author author);
|
Author UpdateAuthor(Author author);
|
||||||
List<Author> UpdateAuthors(List<Author> authors, bool useExistingRelativeFolder);
|
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));
|
return _cache.Get("GetAllAuthors", () => _authorRepository.All().ToList(), TimeSpan.FromSeconds(30));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Dictionary<int, List<int>> GetAllAuthorTags()
|
||||||
|
{
|
||||||
|
return _authorRepository.AllAuthorTags();
|
||||||
|
}
|
||||||
|
|
||||||
public Dictionary<int, string> AllAuthorPaths()
|
public Dictionary<int, string> AllAuthorPaths()
|
||||||
{
|
{
|
||||||
return _authorRepository.AllAuthorPaths();
|
return _authorRepository.AllAuthorPaths();
|
||||||
|
|||||||
@@ -117,8 +117,7 @@ namespace NzbDrone.Core.Configuration
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
object currentValue;
|
allWithDefaults.TryGetValue(configValue.Key, out var currentValue);
|
||||||
allWithDefaults.TryGetValue(configValue.Key, out currentValue);
|
|
||||||
if (currentValue == null)
|
if (currentValue == null)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
@@ -141,7 +140,7 @@ namespace NzbDrone.Core.Configuration
|
|||||||
{
|
{
|
||||||
const string defaultValue = "*";
|
const string defaultValue = "*";
|
||||||
|
|
||||||
string bindAddress = GetValue("BindAddress", defaultValue);
|
var bindAddress = GetValue("BindAddress", defaultValue);
|
||||||
if (string.IsNullOrWhiteSpace(bindAddress))
|
if (string.IsNullOrWhiteSpace(bindAddress))
|
||||||
{
|
{
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
|
|||||||
@@ -56,8 +56,7 @@ namespace NzbDrone.Core.Configuration
|
|||||||
|
|
||||||
foreach (var configValue in configValues)
|
foreach (var configValue in configValues)
|
||||||
{
|
{
|
||||||
object currentValue;
|
allWithDefaults.TryGetValue(configValue.Key, out var currentValue);
|
||||||
allWithDefaults.TryGetValue(configValue.Key, out currentValue);
|
|
||||||
if (currentValue == null || configValue.Value == null)
|
if (currentValue == null || configValue.Value == null)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
@@ -439,9 +438,7 @@ namespace NzbDrone.Core.Configuration
|
|||||||
|
|
||||||
EnsureCache();
|
EnsureCache();
|
||||||
|
|
||||||
string dbValue;
|
if (_cache.TryGetValue(key, out var dbValue) && dbValue != null && !string.IsNullOrEmpty(dbValue))
|
||||||
|
|
||||||
if (_cache.TryGetValue(key, out dbValue) && dbValue != null && !string.IsNullOrEmpty(dbValue))
|
|
||||||
{
|
{
|
||||||
return dbValue;
|
return dbValue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -215,7 +215,7 @@ namespace NzbDrone.Core.Datastore
|
|||||||
|
|
||||||
using (var conn = _database.OpenConnection())
|
using (var conn = _database.OpenConnection())
|
||||||
{
|
{
|
||||||
using (IDbTransaction tran = conn.BeginTransaction(IsolationLevel.ReadCommitted))
|
using (var tran = conn.BeginTransaction(IsolationLevel.ReadCommitted))
|
||||||
{
|
{
|
||||||
foreach (var model in models)
|
foreach (var model in models)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ namespace NzbDrone.Core.Datastore.Converters
|
|||||||
}
|
}
|
||||||
|
|
||||||
string contract;
|
string contract;
|
||||||
using (JsonDocument body = JsonDocument.Parse(stringValue))
|
using (var body = JsonDocument.Parse(stringValue))
|
||||||
{
|
{
|
||||||
contract = body.RootElement.GetProperty("name").GetString();
|
contract = body.RootElement.GetProperty("name").GetString();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ namespace NzbDrone.Core.Datastore.Migration
|
|||||||
|
|
||||||
private void ConvertFileChmodToFolderChmod(IDbConnection conn, IDbTransaction tran)
|
private void ConvertFileChmodToFolderChmod(IDbConnection conn, IDbTransaction tran)
|
||||||
{
|
{
|
||||||
using (IDbCommand getFileChmodCmd = conn.CreateCommand())
|
using (var getFileChmodCmd = conn.CreateCommand())
|
||||||
{
|
{
|
||||||
getFileChmodCmd.Transaction = tran;
|
getFileChmodCmd.Transaction = tran;
|
||||||
getFileChmodCmd.CommandText = @"SELECT ""Value"" FROM ""Config"" WHERE ""Key"" = 'filechmod'";
|
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 folderChmodNum = fileChmodNum | ((fileChmodNum & 0x124) >> 2);
|
||||||
var folderChmod = Convert.ToString(folderChmodNum, 8).PadLeft(3, '0');
|
var folderChmod = Convert.ToString(folderChmodNum, 8).PadLeft(3, '0');
|
||||||
|
|
||||||
using (IDbCommand insertCmd = conn.CreateCommand())
|
using (var insertCmd = conn.CreateCommand())
|
||||||
{
|
{
|
||||||
insertCmd.Transaction = tran;
|
insertCmd.Transaction = tran;
|
||||||
insertCmd.CommandText = "INSERT INTO \"Config\" (\"Key\", \"Value\") VALUES ('chmodfolder', ?)";
|
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.Transaction = tran;
|
||||||
deleteCmd.CommandText = "DELETE FROM \"Config\" WHERE \"Key\" = 'filechmod'";
|
deleteCmd.CommandText = "DELETE FROM \"Config\" WHERE \"Key\" = 'filechmod'";
|
||||||
|
|||||||
@@ -231,11 +231,11 @@ namespace NzbDrone.Core.Datastore.Migration
|
|||||||
{
|
{
|
||||||
var updatedNamingConfigs = new List<object>();
|
var updatedNamingConfigs = new List<object>();
|
||||||
|
|
||||||
using (IDbCommand namingConfigCmd = conn.CreateCommand())
|
using (var namingConfigCmd = conn.CreateCommand())
|
||||||
{
|
{
|
||||||
namingConfigCmd.Transaction = tran;
|
namingConfigCmd.Transaction = tran;
|
||||||
namingConfigCmd.CommandText = @"SELECT * FROM ""NamingConfig"" LIMIT 1";
|
namingConfigCmd.CommandText = @"SELECT * FROM ""NamingConfig"" LIMIT 1";
|
||||||
using (IDataReader namingConfigReader = namingConfigCmd.ExecuteReader())
|
using (var namingConfigReader = namingConfigCmd.ExecuteReader())
|
||||||
{
|
{
|
||||||
var standardBookFormatIndex = namingConfigReader.GetOrdinal("StandardBookFormat");
|
var standardBookFormatIndex = namingConfigReader.GetOrdinal("StandardBookFormat");
|
||||||
|
|
||||||
|
|||||||
@@ -201,7 +201,7 @@ namespace NzbDrone.Core.Datastore.Migration.Framework
|
|||||||
|
|
||||||
public virtual IList<TableDefinition> ReadDbSchema()
|
public virtual IList<TableDefinition> ReadDbSchema()
|
||||||
{
|
{
|
||||||
IList<TableDefinition> tables = ReadTables();
|
var tables = ReadTables();
|
||||||
foreach (var table in tables)
|
foreach (var table in tables)
|
||||||
{
|
{
|
||||||
table.Indexes = ReadIndexes(table.SchemaName, table.Name);
|
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)
|
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);
|
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>();
|
IList<IndexDefinition> indexes = new List<IndexDefinition>();
|
||||||
|
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ namespace NzbDrone.Core.Download.Clients.Deluge
|
|||||||
|
|
||||||
private JsonRpcRequestBuilder BuildRequest(DelugeSettings settings)
|
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);
|
var requestBuilder = new JsonRpcRequestBuilder(url);
|
||||||
requestBuilder.LogResponseContent = true;
|
requestBuilder.LogResponseContent = true;
|
||||||
|
|||||||
@@ -254,9 +254,8 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
|
|||||||
protected long GetRemainingSize(DownloadStationTask torrent)
|
protected long GetRemainingSize(DownloadStationTask torrent)
|
||||||
{
|
{
|
||||||
var downloadedString = torrent.Additional.Transfer["size_downloaded"];
|
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);
|
_logger.Debug("Torrent {0} has invalid size_downloaded: {1}", torrent.Title, downloadedString);
|
||||||
downloadedSize = 0;
|
downloadedSize = 0;
|
||||||
@@ -268,9 +267,8 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
|
|||||||
protected TimeSpan? GetRemainingTime(DownloadStationTask torrent)
|
protected TimeSpan? GetRemainingTime(DownloadStationTask torrent)
|
||||||
{
|
{
|
||||||
var speedString = torrent.Additional.Transfer["speed_download"];
|
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);
|
_logger.Debug("Torrent {0} has invalid speed_download: {1}", torrent.Title, speedString);
|
||||||
downloadSpeed = 0;
|
downloadSpeed = 0;
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
|
|||||||
var items = new List<DownloadClientItem>();
|
var items = new List<DownloadClientItem>();
|
||||||
|
|
||||||
long totalRemainingSize = 0;
|
long totalRemainingSize = 0;
|
||||||
long globalSpeed = nzbTasks.Where(t => t.Status == DownloadStationTaskStatus.Downloading)
|
var globalSpeed = nzbTasks.Where(t => t.Status == DownloadStationTaskStatus.Downloading)
|
||||||
.Select(GetDownloadSpeed)
|
.Select(GetDownloadSpeed)
|
||||||
.Sum();
|
.Sum();
|
||||||
|
|
||||||
@@ -351,9 +351,8 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
|
|||||||
protected long GetRemainingSize(DownloadStationTask task)
|
protected long GetRemainingSize(DownloadStationTask task)
|
||||||
{
|
{
|
||||||
var downloadedString = task.Additional.Transfer["size_downloaded"];
|
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);
|
_logger.Debug("Task {0} has invalid size_downloaded: {1}", task.Title, downloadedString);
|
||||||
downloadedSize = 0;
|
downloadedSize = 0;
|
||||||
@@ -365,9 +364,8 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
|
|||||||
protected long GetDownloadSpeed(DownloadStationTask task)
|
protected long GetDownloadSpeed(DownloadStationTask task)
|
||||||
{
|
{
|
||||||
var speedString = task.Additional.Transfer["speed_download"];
|
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);
|
_logger.Debug("Task {0} has invalid speed_download: {1}", task.Title, speedString);
|
||||||
downloadSpeed = 0;
|
downloadSpeed = 0;
|
||||||
|
|||||||
@@ -15,8 +15,7 @@ namespace NzbDrone.Core.Download.Clients.NzbVortex.JsonConverters
|
|||||||
{
|
{
|
||||||
var result = reader.Value.ToString().Replace("_", string.Empty);
|
var result = reader.Value.ToString().Replace("_", string.Empty);
|
||||||
|
|
||||||
NzbVortexLoginResultType output;
|
Enum.TryParse(result, true, out NzbVortexLoginResultType output);
|
||||||
Enum.TryParse(result, true, out output);
|
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,8 +15,7 @@ namespace NzbDrone.Core.Download.Clients.NzbVortex.JsonConverters
|
|||||||
{
|
{
|
||||||
var result = reader.Value.ToString().Replace("_", string.Empty);
|
var result = reader.Value.ToString().Replace("_", string.Empty);
|
||||||
|
|
||||||
NzbVortexResultType output;
|
Enum.TryParse(result, true, out NzbVortexResultType output);
|
||||||
Enum.TryParse(result, true, out output);
|
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,9 +113,7 @@ namespace NzbDrone.Core.Download.Clients.NzbVortex
|
|||||||
public override void RemoveItem(DownloadClientItem item, bool deleteData)
|
public override void RemoveItem(DownloadClientItem item, bool deleteData)
|
||||||
{
|
{
|
||||||
// Try to find the download by numerical ID, otherwise try by AddUUID
|
// Try to find the download by numerical ID, otherwise try by AddUUID
|
||||||
int id;
|
if (int.TryParse(item.DownloadId, out var id))
|
||||||
|
|
||||||
if (int.TryParse(item.DownloadId, out id))
|
|
||||||
{
|
{
|
||||||
_proxy.Remove(id, deleteData, Settings);
|
_proxy.Remove(id, deleteData, Settings);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -223,7 +223,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
|
|||||||
|
|
||||||
protected IEnumerable<NzbgetCategory> GetCategories(Dictionary<string, string> config)
|
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");
|
var name = config.GetValueOrDefault("Category" + i + ".Name");
|
||||||
|
|
||||||
@@ -310,8 +310,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
|
|||||||
var config = _proxy.GetConfig(Settings);
|
var config = _proxy.GetConfig(Settings);
|
||||||
|
|
||||||
var keepHistory = config.GetValueOrDefault("KeepHistory", "7");
|
var keepHistory = config.GetValueOrDefault("KeepHistory", "7");
|
||||||
int value;
|
if (!int.TryParse(keepHistory, NumberStyles.None, CultureInfo.InvariantCulture, out var value) || value == 0)
|
||||||
if (!int.TryParse(keepHistory, NumberStyles.None, CultureInfo.InvariantCulture, out value) || value == 0)
|
|
||||||
{
|
{
|
||||||
return new NzbDroneValidationFailure(string.Empty, "NzbGet setting KeepHistory should be greater than 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 queue = GetQueue(settings);
|
||||||
var history = GetHistory(settings);
|
var history = GetHistory(settings);
|
||||||
|
|
||||||
int nzbId;
|
|
||||||
NzbgetQueueItem queueItem;
|
NzbgetQueueItem queueItem;
|
||||||
NzbgetHistoryItem historyItem;
|
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.
|
// Download wasn't grabbed by Readarr, so the id is the NzbId reported by nzbget.
|
||||||
queueItem = queue.SingleOrDefault(h => h.NzbId == nzbId);
|
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 "queuedDL": // queuing is enabled and torrent is queued for download
|
||||||
case "checkingDL": // same as checkingUP, but torrent has NOT finished downloading
|
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 "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;
|
item.Status = DownloadItemStatus.Queued;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -496,7 +497,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Dictionary<string, QBittorrentLabel> labels = Proxy.GetLabels(Settings);
|
var labels = Proxy.GetLabels(Settings);
|
||||||
|
|
||||||
if (Settings.MusicCategory.IsNotNullOrWhiteSpace() && !labels.ContainsKey(Settings.MusicCategory))
|
if (Settings.MusicCategory.IsNotNullOrWhiteSpace() && !labels.ContainsKey(Settings.MusicCategory))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -15,8 +15,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd.JsonConverters
|
|||||||
{
|
{
|
||||||
var queuePriority = reader.Value.ToString();
|
var queuePriority = reader.Value.ToString();
|
||||||
|
|
||||||
SabnzbdPriority output;
|
Enum.TryParse(queuePriority, out SabnzbdPriority output);
|
||||||
Enum.TryParse(queuePriority, out output);
|
|
||||||
|
|
||||||
return 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