mirror of
https://github.com/lidarr/lidarr.git
synced 2025-08-19 21:13:28 -07:00
Compare commits
No commits in common. "develop" and "v2.9.5.4550" have entirely different histories.
develop
...
v2.9.5.455
179 changed files with 772 additions and 2576 deletions
|
@ -6,7 +6,7 @@
|
||||||
"features": {
|
"features": {
|
||||||
"ghcr.io/devcontainers/features/node:1": {
|
"ghcr.io/devcontainers/features/node:1": {
|
||||||
"nodeGypDependencies": true,
|
"nodeGypDependencies": true,
|
||||||
"version": "20",
|
"version": "16",
|
||||||
"nvmVersion": "latest"
|
"nvmVersion": "latest"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
1
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
1
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
|
@ -60,7 +60,6 @@ body:
|
||||||
- Master
|
- Master
|
||||||
- Develop
|
- Develop
|
||||||
- Nightly
|
- Nightly
|
||||||
- Plugins (experimental)
|
|
||||||
- Other (This issue will be closed)
|
- Other (This issue will be closed)
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
|
28
.gitignore
vendored
28
.gitignore
vendored
|
@ -158,12 +158,34 @@ Thumbs.db
|
||||||
/tools/Addins/*
|
/tools/Addins/*
|
||||||
packages.config.md5sum
|
packages.config.md5sum
|
||||||
|
|
||||||
|
|
||||||
|
# Common IntelliJ Platform excludes
|
||||||
|
|
||||||
|
# User specific
|
||||||
|
**/.idea/**/workspace.xml
|
||||||
|
**/.idea/**/tasks.xml
|
||||||
|
**/.idea/shelf/*
|
||||||
|
**/.idea/dictionaries
|
||||||
|
**/.idea/.idea.Radarr.Posix
|
||||||
|
**/.idea/.idea.Radarr.Windows
|
||||||
|
|
||||||
|
# Sensitive or high-churn files
|
||||||
|
**/.idea/**/dataSources/
|
||||||
|
**/.idea/**/dataSources.ids
|
||||||
|
**/.idea/**/dataSources.xml
|
||||||
|
**/.idea/**/dataSources.local.xml
|
||||||
|
**/.idea/**/sqlDataSources.xml
|
||||||
|
**/.idea/**/dynamic.xml
|
||||||
|
|
||||||
|
# Rider
|
||||||
|
# Rider auto-generates .iml files, and contentModel.xml
|
||||||
|
**/.idea/**/*.iml
|
||||||
|
**/.idea/**/contentModel.xml
|
||||||
|
**/.idea/**/modules.xml
|
||||||
|
|
||||||
# ignore node_modules symlink
|
# ignore node_modules symlink
|
||||||
node_modules
|
node_modules
|
||||||
node_modules.nosync
|
node_modules.nosync
|
||||||
|
|
||||||
# API doc generation
|
# API doc generation
|
||||||
.config/
|
.config/
|
||||||
|
|
||||||
# Ignore Jetbrains IntelliJ Workspace Directories
|
|
||||||
.idea/
|
|
||||||
|
|
|
@ -9,9 +9,6 @@
|
||||||
|
|
||||||
Lidarr is a music collection manager for Usenet and BitTorrent users. It can monitor multiple RSS feeds for new tracks from your favorite artists and will grab, sort and rename them. It can also be configured to automatically upgrade the quality of files already downloaded when a better quality format becomes available.
|
Lidarr is a music collection manager for Usenet and BitTorrent users. It can monitor multiple RSS feeds for new tracks from your favorite artists and will grab, sort and rename them. It can also be configured to automatically upgrade the quality of files already downloaded when a better quality format becomes available.
|
||||||
|
|
||||||
> [!WARNING]
|
|
||||||
> NOTICE - The Lidarr Metadata Server is currently down impacting adding artists, etc. Please follow [GHI 5498](https://github.com/Lidarr/Lidarr/issues/5498) or see Discord for detaila.
|
|
||||||
|
|
||||||
## Major Features Include:
|
## Major Features Include:
|
||||||
|
|
||||||
* Support for major platforms: Windows, Linux, macOS, Raspberry Pi, etc.
|
* Support for major platforms: Windows, Linux, macOS, Raspberry Pi, etc.
|
||||||
|
|
|
@ -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: '2.13.3'
|
majorVersion: '2.9.5'
|
||||||
minorVersion: $[counter('minorVersion', 1076)]
|
minorVersion: $[counter('minorVersion', 1076)]
|
||||||
lidarrVersion: '$(majorVersion).$(minorVersion)'
|
lidarrVersion: '$(majorVersion).$(minorVersion)'
|
||||||
buildName: '$(Build.SourceBranchName).$(lidarrVersion)'
|
buildName: '$(Build.SourceBranchName).$(lidarrVersion)'
|
||||||
|
@ -19,7 +19,7 @@ variables:
|
||||||
nodeVersion: '20.X'
|
nodeVersion: '20.X'
|
||||||
innoVersion: '6.2.0'
|
innoVersion: '6.2.0'
|
||||||
windowsImage: 'windows-2022'
|
windowsImage: 'windows-2022'
|
||||||
linuxImage: 'ubuntu-22.04'
|
linuxImage: 'ubuntu-20.04'
|
||||||
macImage: 'macOS-13'
|
macImage: 'macOS-13'
|
||||||
|
|
||||||
trigger:
|
trigger:
|
||||||
|
|
15
docs.sh
15
docs.sh
|
@ -1,18 +1,13 @@
|
||||||
#!/bin/bash
|
|
||||||
set -e
|
|
||||||
|
|
||||||
FRAMEWORK="net6.0"
|
|
||||||
PLATFORM=$1
|
PLATFORM=$1
|
||||||
ARCHITECTURE="${2:-x64}"
|
|
||||||
|
|
||||||
if [ "$PLATFORM" = "Windows" ]; then
|
if [ "$PLATFORM" = "Windows" ]; then
|
||||||
RUNTIME="win-$ARCHITECTURE"
|
RUNTIME="win-x64"
|
||||||
elif [ "$PLATFORM" = "Linux" ]; then
|
elif [ "$PLATFORM" = "Linux" ]; then
|
||||||
RUNTIME="linux-$ARCHITECTURE"
|
RUNTIME="linux-x64"
|
||||||
elif [ "$PLATFORM" = "Mac" ]; then
|
elif [ "$PLATFORM" = "Mac" ]; then
|
||||||
RUNTIME="osx-$ARCHITECTURE"
|
RUNTIME="osx-x64"
|
||||||
else
|
else
|
||||||
echo "Platform must be provided as first argument: Windows, Linux or Mac"
|
echo "Platform must be provided as first arguement: Windows, Linux or Mac"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -40,7 +35,7 @@ dotnet msbuild -restore $slnFile -p:Configuration=Debug -p:Platform=$platform -p
|
||||||
dotnet new tool-manifest
|
dotnet new tool-manifest
|
||||||
dotnet tool install --version 6.6.2 Swashbuckle.AspNetCore.Cli
|
dotnet tool install --version 6.6.2 Swashbuckle.AspNetCore.Cli
|
||||||
|
|
||||||
dotnet tool run swagger tofile --output ./src/Lidarr.Api.V1/openapi.json "$outputFolder/$FRAMEWORK/$RUNTIME/$application" v1 &
|
dotnet tool run swagger tofile --output ./src/Lidarr.Api.V1/openapi.json "$outputFolder/net6.0/$RUNTIME/$application" v1 &
|
||||||
|
|
||||||
sleep 45
|
sleep 45
|
||||||
|
|
||||||
|
|
|
@ -188,7 +188,7 @@ module.exports = (env) => {
|
||||||
loose: true,
|
loose: true,
|
||||||
debug: false,
|
debug: false,
|
||||||
useBuiltIns: 'entry',
|
useBuiltIns: 'entry',
|
||||||
corejs: '3.41'
|
corejs: '3.39'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
|
@ -172,8 +172,7 @@ function HistoryDetails(props) {
|
||||||
|
|
||||||
if (eventType === 'downloadFailed') {
|
if (eventType === 'downloadFailed') {
|
||||||
const {
|
const {
|
||||||
message,
|
message
|
||||||
indexer
|
|
||||||
} = data;
|
} = data;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -193,14 +192,6 @@ function HistoryDetails(props) {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
|
||||||
indexer ? (
|
|
||||||
<DescriptionListItem
|
|
||||||
title={translate('Indexer')}
|
|
||||||
data={indexer}
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
message ?
|
message ?
|
||||||
<DescriptionListItem
|
<DescriptionListItem
|
||||||
|
|
|
@ -57,40 +57,30 @@ function QueueStatusCell(props) {
|
||||||
|
|
||||||
if (status === 'paused') {
|
if (status === 'paused') {
|
||||||
iconName = icons.PAUSED;
|
iconName = icons.PAUSED;
|
||||||
title = translate('Paused');
|
title = 'Paused';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status === 'queued') {
|
if (status === 'queued') {
|
||||||
iconName = icons.QUEUED;
|
iconName = icons.QUEUED;
|
||||||
title = translate('Queued');
|
title = 'Queued';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status === 'completed') {
|
if (status === 'completed') {
|
||||||
iconName = icons.DOWNLOADED;
|
iconName = icons.DOWNLOADED;
|
||||||
title = translate('Downloaded');
|
title = 'Downloaded';
|
||||||
|
|
||||||
if (trackedDownloadState === 'importBlocked') {
|
|
||||||
title += ` - ${translate('UnableToImportAutomatically')}`;
|
|
||||||
iconKind = kinds.WARNING;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (trackedDownloadState === 'importFailed') {
|
|
||||||
title += ` - ${translate('ImportFailed', { sourceTitle })}`;
|
|
||||||
iconKind = kinds.WARNING;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (trackedDownloadState === 'importPending') {
|
if (trackedDownloadState === 'importPending') {
|
||||||
title += ` - ${translate('WaitingToImport')}`;
|
title += ' - Waiting to Import';
|
||||||
iconKind = kinds.PURPLE;
|
iconKind = kinds.PURPLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (trackedDownloadState === 'importing') {
|
if (trackedDownloadState === 'importing') {
|
||||||
title += ` - ${translate('Importing')}`;
|
title += ' - Importing';
|
||||||
iconKind = kinds.PURPLE;
|
iconKind = kinds.PURPLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (trackedDownloadState === 'failedPending') {
|
if (trackedDownloadState === 'failedPending') {
|
||||||
title += ` - ${translate('WaitingToProcess')}`;
|
title += ' - Waiting to Process';
|
||||||
iconKind = kinds.DANGER;
|
iconKind = kinds.DANGER;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,38 +91,36 @@ function QueueStatusCell(props) {
|
||||||
|
|
||||||
if (status === 'delay') {
|
if (status === 'delay') {
|
||||||
iconName = icons.PENDING;
|
iconName = icons.PENDING;
|
||||||
title = translate('Pending');
|
title = 'Pending';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status === 'downloadClientUnavailable') {
|
if (status === 'downloadClientUnavailable') {
|
||||||
iconName = icons.PENDING;
|
iconName = icons.PENDING;
|
||||||
iconKind = kinds.WARNING;
|
iconKind = kinds.WARNING;
|
||||||
title = translate('PendingDownloadClientUnavailable');
|
title = 'Pending - Download client is unavailable';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status === 'failed') {
|
if (status === 'failed') {
|
||||||
iconName = icons.DOWNLOADING;
|
iconName = icons.DOWNLOADING;
|
||||||
iconKind = kinds.DANGER;
|
iconKind = kinds.DANGER;
|
||||||
title = translate('DownloadFailed');
|
title = 'Download failed';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status === 'warning') {
|
if (status === 'warning') {
|
||||||
iconName = icons.DOWNLOADING;
|
iconName = icons.DOWNLOADING;
|
||||||
iconKind = kinds.WARNING;
|
iconKind = kinds.WARNING;
|
||||||
const warningMessage =
|
title = `Download warning: ${errorMessage || 'check download client for more details'}`;
|
||||||
errorMessage || translate('CheckDownloadClientForDetails');
|
|
||||||
title = translate('DownloadWarning', { warningMessage });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasError) {
|
if (hasError) {
|
||||||
if (status === 'completed') {
|
if (status === 'completed') {
|
||||||
iconName = icons.DOWNLOAD;
|
iconName = icons.DOWNLOAD;
|
||||||
iconKind = kinds.DANGER;
|
iconKind = kinds.DANGER;
|
||||||
title = translate('ImportFailed', { sourceTitle });
|
title = `Import failed: ${sourceTitle}`;
|
||||||
} else {
|
} else {
|
||||||
iconName = icons.DOWNLOADING;
|
iconName = icons.DOWNLOADING;
|
||||||
iconKind = kinds.DANGER;
|
iconKind = kinds.DANGER;
|
||||||
title = translate('DownloadFailed');
|
title = 'Download failed';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,17 +8,17 @@ function ArtistMonitorNewItemsOptionsPopoverContent() {
|
||||||
<DescriptionList>
|
<DescriptionList>
|
||||||
<DescriptionListItem
|
<DescriptionListItem
|
||||||
title={translate('AllAlbums')}
|
title={translate('AllAlbums')}
|
||||||
data={translate('MonitorAllAlbums')}
|
data="Monitor all new albums"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<DescriptionListItem
|
<DescriptionListItem
|
||||||
title={translate('NewAlbums')}
|
title={translate('NewAlbums')}
|
||||||
data={translate('MonitorNewAlbumsData')}
|
data="Monitor new albums released after the newest existing album"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<DescriptionListItem
|
<DescriptionListItem
|
||||||
title={translate('None')}
|
title={translate('None')}
|
||||||
data={translate('MonitorNoAlbumsData')}
|
data="Don't monitor any new albums"
|
||||||
/>
|
/>
|
||||||
</DescriptionList>
|
</DescriptionList>
|
||||||
);
|
);
|
||||||
|
|
|
@ -15,7 +15,7 @@ import ModalContent from 'Components/Modal/ModalContent';
|
||||||
import ModalFooter from 'Components/Modal/ModalFooter';
|
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||||
import Popover from 'Components/Tooltip/Popover';
|
import Popover from 'Components/Tooltip/Popover';
|
||||||
import { icons, inputTypes, kinds, sizes, tooltipPositions } from 'Helpers/Props';
|
import { icons, inputTypes, kinds, tooltipPositions } from 'Helpers/Props';
|
||||||
import translate from 'Utilities/String/translate';
|
import translate from 'Utilities/String/translate';
|
||||||
import styles from './EditArtistModalContent.css';
|
import styles from './EditArtistModalContent.css';
|
||||||
|
|
||||||
|
@ -93,7 +93,7 @@ class EditArtistModalContent extends Component {
|
||||||
|
|
||||||
<ModalBody>
|
<ModalBody>
|
||||||
<Form {...otherProps}>
|
<Form {...otherProps}>
|
||||||
<FormGroup size={sizes.MEDIUM}>
|
<FormGroup>
|
||||||
<FormLabel>
|
<FormLabel>
|
||||||
{translate('Monitored')}
|
{translate('Monitored')}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
|
@ -107,10 +107,9 @@ class EditArtistModalContent extends Component {
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|
||||||
<FormGroup size={sizes.MEDIUM}>
|
<FormGroup>
|
||||||
<FormLabel>
|
<FormLabel>
|
||||||
{translate('MonitorNewItems')}
|
{translate('MonitorNewItems')}
|
||||||
|
|
||||||
<Popover
|
<Popover
|
||||||
anchor={
|
anchor={
|
||||||
<Icon
|
<Icon
|
||||||
|
@ -133,7 +132,7 @@ class EditArtistModalContent extends Component {
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|
||||||
<FormGroup size={sizes.MEDIUM}>
|
<FormGroup>
|
||||||
<FormLabel>
|
<FormLabel>
|
||||||
{translate('QualityProfile')}
|
{translate('QualityProfile')}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
|
@ -147,10 +146,10 @@ class EditArtistModalContent extends Component {
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|
||||||
{
|
{
|
||||||
showMetadataProfile ?
|
showMetadataProfile &&
|
||||||
<FormGroup size={sizes.MEDIUM}>
|
<FormGroup>
|
||||||
<FormLabel>
|
<FormLabel>
|
||||||
{translate('MetadataProfile')}
|
Metadata Profile
|
||||||
|
|
||||||
<Popover
|
<Popover
|
||||||
anchor={
|
anchor={
|
||||||
|
@ -174,11 +173,10 @@ class EditArtistModalContent extends Component {
|
||||||
{...metadataProfileId}
|
{...metadataProfileId}
|
||||||
onChange={onInputChange}
|
onChange={onInputChange}
|
||||||
/>
|
/>
|
||||||
</FormGroup> :
|
</FormGroup>
|
||||||
null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
<FormGroup size={sizes.MEDIUM}>
|
<FormGroup>
|
||||||
<FormLabel>
|
<FormLabel>
|
||||||
{translate('Path')}
|
{translate('Path')}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
|
@ -191,7 +189,7 @@ class EditArtistModalContent extends Component {
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|
||||||
<FormGroup size={sizes.MEDIUM}>
|
<FormGroup>
|
||||||
<FormLabel>
|
<FormLabel>
|
||||||
{translate('Tags')}
|
{translate('Tags')}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
|
@ -211,7 +209,7 @@ class EditArtistModalContent extends Component {
|
||||||
kind={kinds.DANGER}
|
kind={kinds.DANGER}
|
||||||
onPress={onDeleteArtistPress}
|
onPress={onDeleteArtistPress}
|
||||||
>
|
>
|
||||||
{translate('Delete')}
|
Delete
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
|
|
|
@ -25,7 +25,7 @@ const EVENT_TYPE_OPTIONS = [
|
||||||
{
|
{
|
||||||
id: 7,
|
id: 7,
|
||||||
get name() {
|
get name() {
|
||||||
return translate('ImportCompleteFailed');
|
return translate('ImportFailed');
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -20,8 +20,6 @@ import HintedSelectInputSelectedValue from './HintedSelectInputSelectedValue';
|
||||||
import TextInput from './TextInput';
|
import TextInput from './TextInput';
|
||||||
import styles from './EnhancedSelectInput.css';
|
import styles from './EnhancedSelectInput.css';
|
||||||
|
|
||||||
const MINIMUM_DISTANCE_FROM_EDGE = 10;
|
|
||||||
|
|
||||||
function isArrowKey(keyCode) {
|
function isArrowKey(keyCode) {
|
||||||
return keyCode === keyCodes.UP_ARROW || keyCode === keyCodes.DOWN_ARROW;
|
return keyCode === keyCodes.UP_ARROW || keyCode === keyCodes.DOWN_ARROW;
|
||||||
}
|
}
|
||||||
|
@ -139,9 +137,18 @@ class EnhancedSelectInput extends Component {
|
||||||
// Listeners
|
// Listeners
|
||||||
|
|
||||||
onComputeMaxHeight = (data) => {
|
onComputeMaxHeight = (data) => {
|
||||||
|
const {
|
||||||
|
top,
|
||||||
|
bottom
|
||||||
|
} = data.offsets.reference;
|
||||||
|
|
||||||
const windowHeight = window.innerHeight;
|
const windowHeight = window.innerHeight;
|
||||||
|
|
||||||
data.styles.maxHeight = windowHeight - MINIMUM_DISTANCE_FROM_EDGE;
|
if ((/^botton/).test(data.placement)) {
|
||||||
|
data.styles.maxHeight = windowHeight - bottom;
|
||||||
|
} else {
|
||||||
|
data.styles.maxHeight = top;
|
||||||
|
}
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
@ -450,10 +457,6 @@ class EnhancedSelectInput extends Component {
|
||||||
order: 851,
|
order: 851,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
fn: this.onComputeMaxHeight
|
fn: this.onComputeMaxHeight
|
||||||
},
|
|
||||||
preventOverflow: {
|
|
||||||
enabled: true,
|
|
||||||
boundariesElement: 'viewport'
|
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
|
@ -83,6 +83,13 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: $breakpointMedium) {
|
@media only screen and (max-width: $breakpointMedium) {
|
||||||
|
.modal.small,
|
||||||
|
.modal.medium {
|
||||||
|
width: 90%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: $breakpointSmall) {
|
||||||
.modalContainer {
|
.modalContainer {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
}
|
}
|
||||||
|
|
|
@ -224,58 +224,10 @@ class SignalRConnector extends Component {
|
||||||
repopulatePage('trackFileUpdated');
|
repopulatePage('trackFileUpdated');
|
||||||
};
|
};
|
||||||
|
|
||||||
handleDownloadclient = ({ action, resource }) => {
|
|
||||||
const section = 'settings.downloadClients';
|
|
||||||
|
|
||||||
if (action === 'created' || action === 'updated') {
|
|
||||||
this.props.dispatchUpdateItem({ section, ...resource });
|
|
||||||
} else if (action === 'deleted') {
|
|
||||||
this.props.dispatchRemoveItem({ section, id: resource.id });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
handleHealth = () => {
|
handleHealth = () => {
|
||||||
this.props.dispatchFetchHealth();
|
this.props.dispatchFetchHealth();
|
||||||
};
|
};
|
||||||
|
|
||||||
handleImportlist = ({ action, resource }) => {
|
|
||||||
const section = 'settings.importLists';
|
|
||||||
|
|
||||||
if (action === 'created' || action === 'updated') {
|
|
||||||
this.props.dispatchUpdateItem({ section, ...resource });
|
|
||||||
} else if (action === 'deleted') {
|
|
||||||
this.props.dispatchRemoveItem({ section, id: resource.id });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
handleIndexer = ({ action, resource }) => {
|
|
||||||
const section = 'settings.indexers';
|
|
||||||
|
|
||||||
if (action === 'created' || action === 'updated') {
|
|
||||||
this.props.dispatchUpdateItem({ section, ...resource });
|
|
||||||
} else if (action === 'deleted') {
|
|
||||||
this.props.dispatchRemoveItem({ section, id: resource.id });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
handleMetadata = ({ action, resource }) => {
|
|
||||||
const section = 'settings.metadata';
|
|
||||||
|
|
||||||
if (action === 'updated') {
|
|
||||||
this.props.dispatchUpdateItem({ section, ...resource });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
handleNotification = ({ action, resource }) => {
|
|
||||||
const section = 'settings.notifications';
|
|
||||||
|
|
||||||
if (action === 'created' || action === 'updated') {
|
|
||||||
this.props.dispatchUpdateItem({ section, ...resource });
|
|
||||||
} else if (action === 'deleted') {
|
|
||||||
this.props.dispatchRemoveItem({ section, id: resource.id });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
handleArtist = (body) => {
|
handleArtist = (body) => {
|
||||||
const action = body.action;
|
const action = body.action;
|
||||||
const section = 'artist';
|
const section = 'artist';
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
line-height: 1.52857143;
|
line-height: 1.52857143;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: $breakpointMedium) {
|
@media only screen and (max-width: $breakpointSmall) {
|
||||||
.cell {
|
.cell {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: $breakpointMedium) {
|
@media only screen and (max-width: $breakpointSmall) {
|
||||||
.cell {
|
.cell {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: $breakpointMedium) {
|
@media only screen and (max-width: $breakpointSmall) {
|
||||||
.tableContainer {
|
.tableContainer {
|
||||||
min-width: 100%;
|
min-width: 100%;
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: $breakpointMedium) {
|
@media only screen and (max-width: $breakpointSmall) {
|
||||||
.headerCell {
|
.headerCell {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,7 @@
|
||||||
height: 25px;
|
height: 25px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: $breakpointMedium) {
|
@media only screen and (max-width: $breakpointSmall) {
|
||||||
.pager {
|
.pager {
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: $breakpointMedium) {
|
@media only screen and (max-width: $breakpointSmall) {
|
||||||
.headerCell {
|
.headerCell {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,11 +10,11 @@ import ModalBody from 'Components/Modal/ModalBody';
|
||||||
import ModalContent from 'Components/Modal/ModalContent';
|
import ModalContent from 'Components/Modal/ModalContent';
|
||||||
import ModalFooter from 'Components/Modal/ModalFooter';
|
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||||
import Column from 'Components/Table/Column';
|
|
||||||
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 useSelectState from 'Helpers/Hooks/useSelectState';
|
import useSelectState from 'Helpers/Hooks/useSelectState';
|
||||||
import { kinds } from 'Helpers/Props';
|
import { kinds } from 'Helpers/Props';
|
||||||
|
import SortDirection from 'Helpers/Props/SortDirection';
|
||||||
import {
|
import {
|
||||||
bulkDeleteCustomFormats,
|
bulkDeleteCustomFormats,
|
||||||
bulkEditCustomFormats,
|
bulkEditCustomFormats,
|
||||||
|
@ -34,7 +34,7 @@ type OnSelectedChangeCallback = React.ComponentProps<
|
||||||
typeof ManageCustomFormatsModalRow
|
typeof ManageCustomFormatsModalRow
|
||||||
>['onSelectedChange'];
|
>['onSelectedChange'];
|
||||||
|
|
||||||
const COLUMNS: Column[] = [
|
const COLUMNS = [
|
||||||
{
|
{
|
||||||
name: 'name',
|
name: 'name',
|
||||||
label: () => translate('Name'),
|
label: () => translate('Name'),
|
||||||
|
@ -56,6 +56,8 @@ const COLUMNS: Column[] = [
|
||||||
|
|
||||||
interface ManageCustomFormatsModalContentProps {
|
interface ManageCustomFormatsModalContentProps {
|
||||||
onModalClose(): void;
|
onModalClose(): void;
|
||||||
|
sortKey?: string;
|
||||||
|
sortDirection?: SortDirection;
|
||||||
}
|
}
|
||||||
|
|
||||||
function ManageCustomFormatsModalContent(
|
function ManageCustomFormatsModalContent(
|
||||||
|
|
|
@ -10,11 +10,11 @@ import ModalBody from 'Components/Modal/ModalBody';
|
||||||
import ModalContent from 'Components/Modal/ModalContent';
|
import ModalContent from 'Components/Modal/ModalContent';
|
||||||
import ModalFooter from 'Components/Modal/ModalFooter';
|
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||||
import Column from 'Components/Table/Column';
|
|
||||||
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 useSelectState from 'Helpers/Hooks/useSelectState';
|
import useSelectState from 'Helpers/Hooks/useSelectState';
|
||||||
import { kinds } from 'Helpers/Props';
|
import { kinds } from 'Helpers/Props';
|
||||||
|
import SortDirection from 'Helpers/Props/SortDirection';
|
||||||
import {
|
import {
|
||||||
bulkDeleteDownloadClients,
|
bulkDeleteDownloadClients,
|
||||||
bulkEditDownloadClients,
|
bulkEditDownloadClients,
|
||||||
|
@ -35,7 +35,7 @@ type OnSelectedChangeCallback = React.ComponentProps<
|
||||||
typeof ManageDownloadClientsModalRow
|
typeof ManageDownloadClientsModalRow
|
||||||
>['onSelectedChange'];
|
>['onSelectedChange'];
|
||||||
|
|
||||||
const COLUMNS: Column[] = [
|
const COLUMNS = [
|
||||||
{
|
{
|
||||||
name: 'name',
|
name: 'name',
|
||||||
label: () => translate('Name'),
|
label: () => translate('Name'),
|
||||||
|
@ -82,6 +82,8 @@ const COLUMNS: Column[] = [
|
||||||
|
|
||||||
interface ManageDownloadClientsModalContentProps {
|
interface ManageDownloadClientsModalContentProps {
|
||||||
onModalClose(): void;
|
onModalClose(): void;
|
||||||
|
sortKey?: string;
|
||||||
|
sortDirection?: SortDirection;
|
||||||
}
|
}
|
||||||
|
|
||||||
function ManageDownloadClientsModalContent(
|
function ManageDownloadClientsModalContent(
|
||||||
|
|
|
@ -10,11 +10,11 @@ import ModalBody from 'Components/Modal/ModalBody';
|
||||||
import ModalContent from 'Components/Modal/ModalContent';
|
import ModalContent from 'Components/Modal/ModalContent';
|
||||||
import ModalFooter from 'Components/Modal/ModalFooter';
|
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||||
import Column from 'Components/Table/Column';
|
|
||||||
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 useSelectState from 'Helpers/Hooks/useSelectState';
|
import useSelectState from 'Helpers/Hooks/useSelectState';
|
||||||
import { kinds } from 'Helpers/Props';
|
import { kinds } from 'Helpers/Props';
|
||||||
|
import SortDirection from 'Helpers/Props/SortDirection';
|
||||||
import {
|
import {
|
||||||
bulkDeleteIndexers,
|
bulkDeleteIndexers,
|
||||||
bulkEditIndexers,
|
bulkEditIndexers,
|
||||||
|
@ -35,7 +35,7 @@ type OnSelectedChangeCallback = React.ComponentProps<
|
||||||
typeof ManageIndexersModalRow
|
typeof ManageIndexersModalRow
|
||||||
>['onSelectedChange'];
|
>['onSelectedChange'];
|
||||||
|
|
||||||
const COLUMNS: Column[] = [
|
const COLUMNS = [
|
||||||
{
|
{
|
||||||
name: 'name',
|
name: 'name',
|
||||||
label: () => translate('Name'),
|
label: () => translate('Name'),
|
||||||
|
@ -82,6 +82,8 @@ const COLUMNS: Column[] = [
|
||||||
|
|
||||||
interface ManageIndexersModalContentProps {
|
interface ManageIndexersModalContentProps {
|
||||||
onModalClose(): void;
|
onModalClose(): void;
|
||||||
|
sortKey?: string;
|
||||||
|
sortDirection?: SortDirection;
|
||||||
}
|
}
|
||||||
|
|
||||||
function ManageIndexersModalContent(props: ManageIndexersModalContentProps) {
|
function ManageIndexersModalContent(props: ManageIndexersModalContentProps) {
|
||||||
|
|
|
@ -94,9 +94,9 @@ class RootFolder extends Component {
|
||||||
<ConfirmModal
|
<ConfirmModal
|
||||||
isOpen={this.state.isDeleteRootFolderModalOpen}
|
isOpen={this.state.isDeleteRootFolderModalOpen}
|
||||||
kind={kinds.DANGER}
|
kind={kinds.DANGER}
|
||||||
title={translate('RemoveRootFolder')}
|
title={translate('DeleteRootFolder')}
|
||||||
message={translate('RemoveRootFolderArtistsMessageText', { name })}
|
message={translate('DeleteRootFolderMessageText', { name })}
|
||||||
confirmLabel={translate('Remove')}
|
confirmLabel={translate('Delete')}
|
||||||
onConfirm={this.onConfirmDeleteRootFolder}
|
onConfirm={this.onConfirmDeleteRootFolder}
|
||||||
onCancel={this.onDeleteRootFolderModalClose}
|
onCancel={this.onDeleteRootFolderModalClose}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
height: 20px;
|
height: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.track {
|
.bar {
|
||||||
top: 9px;
|
top: 9px;
|
||||||
margin: 0 5px;
|
margin: 0 5px;
|
||||||
height: 3px;
|
height: 3px;
|
||||||
|
@ -36,7 +36,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.thumb {
|
.handle {
|
||||||
top: 1px;
|
top: 1px;
|
||||||
z-index: 0 !important;
|
z-index: 0 !important;
|
||||||
width: 18px;
|
width: 18px;
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
// 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 {
|
||||||
|
'bar': string;
|
||||||
|
'handle': string;
|
||||||
'kilobitsPerSecond': string;
|
'kilobitsPerSecond': string;
|
||||||
'quality': string;
|
'quality': string;
|
||||||
'qualityDefinition': string;
|
'qualityDefinition': string;
|
||||||
|
@ -8,9 +10,7 @@ interface CssExports {
|
||||||
'sizeLimit': string;
|
'sizeLimit': string;
|
||||||
'sizes': string;
|
'sizes': string;
|
||||||
'slider': string;
|
'slider': string;
|
||||||
'thumb': string;
|
|
||||||
'title': string;
|
'title': string;
|
||||||
'track': string;
|
|
||||||
}
|
}
|
||||||
export const cssExports: CssExports;
|
export const cssExports: CssExports;
|
||||||
export default cssExports;
|
export default cssExports;
|
||||||
|
|
|
@ -55,27 +55,6 @@ class QualityDefinition extends Component {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Control
|
|
||||||
|
|
||||||
trackRenderer(props, state) {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
{...props}
|
|
||||||
className={styles.track}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
thumbRenderer(props, state) {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
{...props}
|
|
||||||
className={styles.thumb}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Listeners
|
// Listeners
|
||||||
|
|
||||||
|
@ -195,7 +174,6 @@ class QualityDefinition extends Component {
|
||||||
|
|
||||||
<div className={styles.sizeLimit}>
|
<div className={styles.sizeLimit}>
|
||||||
<ReactSlider
|
<ReactSlider
|
||||||
className={styles.slider}
|
|
||||||
min={slider.min}
|
min={slider.min}
|
||||||
max={slider.max}
|
max={slider.max}
|
||||||
step={slider.step}
|
step={slider.step}
|
||||||
|
@ -204,9 +182,9 @@ class QualityDefinition extends Component {
|
||||||
withTracks={true}
|
withTracks={true}
|
||||||
allowCross={false}
|
allowCross={false}
|
||||||
snapDragDisabled={true}
|
snapDragDisabled={true}
|
||||||
pearling={true}
|
className={styles.slider}
|
||||||
renderThumb={this.thumbRenderer}
|
trackClassName={styles.bar}
|
||||||
renderTrack={this.trackRenderer}
|
thumbClassName={styles.handle}
|
||||||
onChange={this.onSliderChange}
|
onChange={this.onSliderChange}
|
||||||
onAfterChange={this.onAfterSliderChange}
|
onAfterChange={this.onAfterSliderChange}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -151,7 +151,7 @@ export const defaultState = {
|
||||||
{
|
{
|
||||||
name: 'genres',
|
name: 'genres',
|
||||||
label: () => translate('Genres'),
|
label: () => translate('Genres'),
|
||||||
isSortable: true,
|
isSortable: false,
|
||||||
isVisible: false
|
isVisible: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -150,7 +150,7 @@ export const defaultState = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'importFailed',
|
key: 'importFailed',
|
||||||
label: () => translate('ImportCompleteFailed'),
|
label: () => translate('ImportFailed'),
|
||||||
filters: [
|
filters: [
|
||||||
{
|
{
|
||||||
key: 'eventType',
|
key: 'eventType',
|
||||||
|
|
|
@ -1,8 +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 Alert from 'Components/Alert';
|
||||||
|
import Link from 'Components/Link/Link';
|
||||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||||
import InlineMarkdown from 'Components/Markdown/InlineMarkdown';
|
|
||||||
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 PageToolbar from 'Components/Page/Toolbar/PageToolbar';
|
import PageToolbar from 'Components/Page/Toolbar/PageToolbar';
|
||||||
|
@ -77,16 +77,15 @@ class LogFiles extends Component {
|
||||||
<PageContentBody>
|
<PageContentBody>
|
||||||
<Alert>
|
<Alert>
|
||||||
<div>
|
<div>
|
||||||
{translate('LogFilesLocation', {
|
Log files are located in: {location}
|
||||||
location
|
|
||||||
})}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{currentLogView === 'Log Files' ? (
|
{
|
||||||
|
currentLogView === 'Log Files' &&
|
||||||
<div>
|
<div>
|
||||||
<InlineMarkdown data={translate('TheLogLevelDefault')} />
|
The log level defaults to 'Info' and can be changed in <Link to="/settings/general">General Settings</Link>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
}
|
||||||
</Alert>
|
</Alert>
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -270,7 +270,7 @@ function Updates() {
|
||||||
|
|
||||||
{generalSettingsError ? (
|
{generalSettingsError ? (
|
||||||
<Alert kind={kinds.DANGER}>
|
<Alert kind={kinds.DANGER}>
|
||||||
{translate('FailedToFetchSettings')}
|
{translate('FailedToUpdateSettings')}
|
||||||
</Alert>
|
</Alert>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
|
|
|
@ -109,7 +109,7 @@
|
||||||
"babel-loader": "9.2.1",
|
"babel-loader": "9.2.1",
|
||||||
"babel-plugin-inline-classnames": "2.0.1",
|
"babel-plugin-inline-classnames": "2.0.1",
|
||||||
"babel-plugin-transform-react-remove-prop-types": "0.4.24",
|
"babel-plugin-transform-react-remove-prop-types": "0.4.24",
|
||||||
"core-js": "3.41.0",
|
"core-js": "3.39.0",
|
||||||
"css-loader": "6.7.3",
|
"css-loader": "6.7.3",
|
||||||
"css-modules-typescript-loader": "4.0.1",
|
"css-modules-typescript-loader": "4.0.1",
|
||||||
"eslint": "8.57.1",
|
"eslint": "8.57.1",
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
using FluentValidation;
|
|
||||||
using Lidarr.Http;
|
using Lidarr.Http;
|
||||||
using NzbDrone.Core.Download;
|
using NzbDrone.Core.Download;
|
||||||
using NzbDrone.SignalR;
|
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.DownloadClient
|
namespace Lidarr.Api.V1.DownloadClient
|
||||||
{
|
{
|
||||||
|
@ -11,10 +9,9 @@ namespace Lidarr.Api.V1.DownloadClient
|
||||||
public static readonly DownloadClientResourceMapper ResourceMapper = new ();
|
public static readonly DownloadClientResourceMapper ResourceMapper = new ();
|
||||||
public static readonly DownloadClientBulkResourceMapper BulkResourceMapper = new ();
|
public static readonly DownloadClientBulkResourceMapper BulkResourceMapper = new ();
|
||||||
|
|
||||||
public DownloadClientController(IBroadcastSignalRMessage signalRBroadcaster, IDownloadClientFactory downloadClientFactory)
|
public DownloadClientController(IDownloadClientFactory downloadClientFactory)
|
||||||
: base(signalRBroadcaster, downloadClientFactory, "downloadclient", ResourceMapper, BulkResourceMapper)
|
: base(downloadClientFactory, "downloadclient", ResourceMapper, BulkResourceMapper)
|
||||||
{
|
{
|
||||||
SharedValidator.RuleFor(c => c.Priority).InclusiveBetween(1, 50);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Lidarr.Http.REST;
|
using Lidarr.Http.REST;
|
||||||
|
using NzbDrone.Common.Http;
|
||||||
using NzbDrone.Core.HealthCheck;
|
using NzbDrone.Core.HealthCheck;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Health
|
namespace Lidarr.Api.V1.Health
|
||||||
|
@ -10,7 +11,7 @@ namespace Lidarr.Api.V1.Health
|
||||||
public string Source { get; set; }
|
public string Source { get; set; }
|
||||||
public HealthCheckResult Type { get; set; }
|
public HealthCheckResult Type { get; set; }
|
||||||
public string Message { get; set; }
|
public string Message { get; set; }
|
||||||
public string WikiUrl { get; set; }
|
public HttpUri WikiUrl { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class HealthResourceMapper
|
public static class HealthResourceMapper
|
||||||
|
@ -28,7 +29,7 @@ namespace Lidarr.Api.V1.Health
|
||||||
Source = model.Source.Name,
|
Source = model.Source.Name,
|
||||||
Type = model.Type,
|
Type = model.Type,
|
||||||
Message = model.Message,
|
Message = model.Message,
|
||||||
WikiUrl = model.WikiUrl.FullUri
|
WikiUrl = model.WikiUrl
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ using Lidarr.Http;
|
||||||
using NzbDrone.Core.ImportLists;
|
using NzbDrone.Core.ImportLists;
|
||||||
using NzbDrone.Core.Validation;
|
using NzbDrone.Core.Validation;
|
||||||
using NzbDrone.Core.Validation.Paths;
|
using NzbDrone.Core.Validation.Paths;
|
||||||
using NzbDrone.SignalR;
|
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.ImportLists
|
namespace Lidarr.Api.V1.ImportLists
|
||||||
{
|
{
|
||||||
|
@ -13,12 +12,11 @@ namespace Lidarr.Api.V1.ImportLists
|
||||||
public static readonly ImportListResourceMapper ResourceMapper = new ();
|
public static readonly ImportListResourceMapper ResourceMapper = new ();
|
||||||
public static readonly ImportListBulkResourceMapper BulkResourceMapper = new ();
|
public static readonly ImportListBulkResourceMapper BulkResourceMapper = new ();
|
||||||
|
|
||||||
public ImportListController(IBroadcastSignalRMessage signalRBroadcaster,
|
public ImportListController(IImportListFactory importListFactory,
|
||||||
IImportListFactory importListFactory,
|
|
||||||
RootFolderExistsValidator rootFolderExistsValidator,
|
RootFolderExistsValidator rootFolderExistsValidator,
|
||||||
QualityProfileExistsValidator qualityProfileExistsValidator,
|
QualityProfileExistsValidator qualityProfileExistsValidator,
|
||||||
MetadataProfileExistsValidator metadataProfileExistsValidator)
|
MetadataProfileExistsValidator metadataProfileExistsValidator)
|
||||||
: base(signalRBroadcaster, importListFactory, "importlist", ResourceMapper, BulkResourceMapper)
|
: base(importListFactory, "importlist", ResourceMapper, BulkResourceMapper)
|
||||||
{
|
{
|
||||||
SharedValidator.RuleFor(c => c.RootFolderPath).Cascade(CascadeMode.Stop)
|
SharedValidator.RuleFor(c => c.RootFolderPath).Cascade(CascadeMode.Stop)
|
||||||
.IsValidPath()
|
.IsValidPath()
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
using FluentValidation;
|
|
||||||
using Lidarr.Http;
|
using Lidarr.Http;
|
||||||
using NzbDrone.Core.Indexers;
|
using NzbDrone.Core.Indexers;
|
||||||
using NzbDrone.Core.Validation;
|
using NzbDrone.Core.Validation;
|
||||||
using NzbDrone.SignalR;
|
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Indexers
|
namespace Lidarr.Api.V1.Indexers
|
||||||
{
|
{
|
||||||
|
@ -12,12 +10,9 @@ namespace Lidarr.Api.V1.Indexers
|
||||||
public static readonly IndexerResourceMapper ResourceMapper = new ();
|
public static readonly IndexerResourceMapper ResourceMapper = new ();
|
||||||
public static readonly IndexerBulkResourceMapper BulkResourceMapper = new ();
|
public static readonly IndexerBulkResourceMapper BulkResourceMapper = new ();
|
||||||
|
|
||||||
public IndexerController(IBroadcastSignalRMessage signalRBroadcaster,
|
public IndexerController(IndexerFactory indexerFactory, DownloadClientExistsValidator downloadClientExistsValidator)
|
||||||
IndexerFactory indexerFactory,
|
: base(indexerFactory, "indexer", ResourceMapper, BulkResourceMapper)
|
||||||
DownloadClientExistsValidator downloadClientExistsValidator)
|
|
||||||
: base(signalRBroadcaster, indexerFactory, "indexer", ResourceMapper, BulkResourceMapper)
|
|
||||||
{
|
{
|
||||||
SharedValidator.RuleFor(c => c.Priority).InclusiveBetween(1, 50);
|
|
||||||
SharedValidator.RuleFor(c => c.DownloadClientId).SetValidator(downloadClientExistsValidator);
|
SharedValidator.RuleFor(c => c.DownloadClientId).SetValidator(downloadClientExistsValidator);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
<PackageReference Include="System.Reflection.TypeExtensions" Version="4.7.0" />
|
<PackageReference Include="System.Reflection.TypeExtensions" Version="4.7.0" />
|
||||||
<PackageReference Include="FluentValidation" Version="9.5.4" />
|
<PackageReference Include="FluentValidation" Version="9.5.4" />
|
||||||
<PackageReference Include="Ical.Net" Version="4.3.1" />
|
<PackageReference Include="Ical.Net" Version="4.3.1" />
|
||||||
<PackageReference Include="NLog" Version="5.4.0" />
|
<PackageReference Include="NLog" Version="5.3.4" />
|
||||||
<PackageReference Include="System.IO.Abstractions" Version="17.0.24" />
|
<PackageReference Include="System.IO.Abstractions" Version="17.0.24" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -2,7 +2,6 @@ using System;
|
||||||
using Lidarr.Http;
|
using Lidarr.Http;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NzbDrone.Core.Extras.Metadata;
|
using NzbDrone.Core.Extras.Metadata;
|
||||||
using NzbDrone.SignalR;
|
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Metadata
|
namespace Lidarr.Api.V1.Metadata
|
||||||
{
|
{
|
||||||
|
@ -12,8 +11,8 @@ namespace Lidarr.Api.V1.Metadata
|
||||||
public static readonly MetadataResourceMapper ResourceMapper = new ();
|
public static readonly MetadataResourceMapper ResourceMapper = new ();
|
||||||
public static readonly MetadataBulkResourceMapper BulkResourceMapper = new ();
|
public static readonly MetadataBulkResourceMapper BulkResourceMapper = new ();
|
||||||
|
|
||||||
public MetadataController(IBroadcastSignalRMessage signalRBroadcaster, IMetadataFactory metadataFactory)
|
public MetadataController(IMetadataFactory metadataFactory)
|
||||||
: base(signalRBroadcaster, metadataFactory, "metadata", ResourceMapper, BulkResourceMapper)
|
: base(metadataFactory, "metadata", ResourceMapper, BulkResourceMapper)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@ using System;
|
||||||
using Lidarr.Http;
|
using Lidarr.Http;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NzbDrone.Core.Notifications;
|
using NzbDrone.Core.Notifications;
|
||||||
using NzbDrone.SignalR;
|
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Notifications
|
namespace Lidarr.Api.V1.Notifications
|
||||||
{
|
{
|
||||||
|
@ -12,8 +11,8 @@ namespace Lidarr.Api.V1.Notifications
|
||||||
public static readonly NotificationResourceMapper ResourceMapper = new ();
|
public static readonly NotificationResourceMapper ResourceMapper = new ();
|
||||||
public static readonly NotificationBulkResourceMapper BulkResourceMapper = new ();
|
public static readonly NotificationBulkResourceMapper BulkResourceMapper = new ();
|
||||||
|
|
||||||
public NotificationController(IBroadcastSignalRMessage signalRBroadcaster, NotificationFactory notificationFactory)
|
public NotificationController(NotificationFactory notificationFactory)
|
||||||
: base(signalRBroadcaster, notificationFactory, "notification", ResourceMapper, BulkResourceMapper)
|
: base(notificationFactory, "notification", ResourceMapper, BulkResourceMapper)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,19 +7,12 @@ using Lidarr.Http.REST.Attributes;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Common.Serializer;
|
using NzbDrone.Common.Serializer;
|
||||||
using NzbDrone.Core.Datastore.Events;
|
|
||||||
using NzbDrone.Core.Messaging.Events;
|
|
||||||
using NzbDrone.Core.ThingiProvider;
|
using NzbDrone.Core.ThingiProvider;
|
||||||
using NzbDrone.Core.ThingiProvider.Events;
|
|
||||||
using NzbDrone.Core.Validation;
|
using NzbDrone.Core.Validation;
|
||||||
using NzbDrone.SignalR;
|
|
||||||
|
|
||||||
namespace Lidarr.Api.V1
|
namespace Lidarr.Api.V1
|
||||||
{
|
{
|
||||||
public abstract class ProviderControllerBase<TProviderResource, TBulkProviderResource, TProvider, TProviderDefinition> : RestControllerWithSignalR<TProviderResource, TProviderDefinition>,
|
public abstract class ProviderControllerBase<TProviderResource, TBulkProviderResource, TProvider, TProviderDefinition> : RestController<TProviderResource>
|
||||||
IHandle<ProviderAddedEvent<TProvider>>,
|
|
||||||
IHandle<ProviderUpdatedEvent<TProvider>>,
|
|
||||||
IHandle<ProviderDeletedEvent<TProvider>>
|
|
||||||
where TProviderDefinition : ProviderDefinition, new()
|
where TProviderDefinition : ProviderDefinition, new()
|
||||||
where TProvider : IProvider
|
where TProvider : IProvider
|
||||||
where TProviderResource : ProviderResource<TProviderResource>, new()
|
where TProviderResource : ProviderResource<TProviderResource>, new()
|
||||||
|
@ -29,13 +22,11 @@ namespace Lidarr.Api.V1
|
||||||
private readonly ProviderResourceMapper<TProviderResource, TProviderDefinition> _resourceMapper;
|
private readonly ProviderResourceMapper<TProviderResource, TProviderDefinition> _resourceMapper;
|
||||||
private readonly ProviderBulkResourceMapper<TBulkProviderResource, TProviderDefinition> _bulkResourceMapper;
|
private readonly ProviderBulkResourceMapper<TBulkProviderResource, TProviderDefinition> _bulkResourceMapper;
|
||||||
|
|
||||||
protected ProviderControllerBase(IBroadcastSignalRMessage signalRBroadcaster,
|
protected ProviderControllerBase(IProviderFactory<TProvider,
|
||||||
IProviderFactory<TProvider,
|
|
||||||
TProviderDefinition> providerFactory,
|
TProviderDefinition> providerFactory,
|
||||||
string resource,
|
string resource,
|
||||||
ProviderResourceMapper<TProviderResource, TProviderDefinition> resourceMapper,
|
ProviderResourceMapper<TProviderResource, TProviderDefinition> resourceMapper,
|
||||||
ProviderBulkResourceMapper<TBulkProviderResource, TProviderDefinition> bulkResourceMapper)
|
ProviderBulkResourceMapper<TBulkProviderResource, TProviderDefinition> bulkResourceMapper)
|
||||||
: base(signalRBroadcaster)
|
|
||||||
{
|
{
|
||||||
_providerFactory = providerFactory;
|
_providerFactory = providerFactory;
|
||||||
_resourceMapper = resourceMapper;
|
_resourceMapper = resourceMapper;
|
||||||
|
@ -270,24 +261,6 @@ namespace Lidarr.Api.V1
|
||||||
return Content(data.ToJson(), "application/json");
|
return Content(data.ToJson(), "application/json");
|
||||||
}
|
}
|
||||||
|
|
||||||
[NonAction]
|
|
||||||
public virtual void Handle(ProviderAddedEvent<TProvider> message)
|
|
||||||
{
|
|
||||||
BroadcastResourceChange(ModelAction.Created, message.Definition.Id);
|
|
||||||
}
|
|
||||||
|
|
||||||
[NonAction]
|
|
||||||
public virtual void Handle(ProviderUpdatedEvent<TProvider> message)
|
|
||||||
{
|
|
||||||
BroadcastResourceChange(ModelAction.Updated, message.Definition.Id);
|
|
||||||
}
|
|
||||||
|
|
||||||
[NonAction]
|
|
||||||
public virtual void Handle(ProviderDeletedEvent<TProvider> message)
|
|
||||||
{
|
|
||||||
BroadcastResourceChange(ModelAction.Deleted, message.ProviderId);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void Validate(TProviderDefinition definition, bool includeWarnings)
|
protected virtual void Validate(TProviderDefinition definition, bool includeWarnings)
|
||||||
{
|
{
|
||||||
var validationResult = definition.Settings.Validate();
|
var validationResult = definition.Settings.Validate();
|
||||||
|
|
|
@ -302,7 +302,7 @@ namespace Lidarr.Api.V1.Queue
|
||||||
|
|
||||||
if (blocklist)
|
if (blocklist)
|
||||||
{
|
{
|
||||||
_failedDownloadService.MarkAsFailed(trackedDownload, skipRedownload);
|
_failedDownloadService.MarkAsFailed(trackedDownload.DownloadItem.DownloadId, skipRedownload);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!removeFromClient && !blocklist && !changeCategory)
|
if (!removeFromClient && !blocklist && !changeCategory)
|
||||||
|
|
|
@ -4,7 +4,6 @@ using Lidarr.Http;
|
||||||
using Lidarr.Http.REST;
|
using Lidarr.Http.REST;
|
||||||
using Lidarr.Http.REST.Attributes;
|
using Lidarr.Http.REST.Attributes;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NzbDrone.Common.Extensions;
|
|
||||||
using NzbDrone.Core.RemotePathMappings;
|
using NzbDrone.Core.RemotePathMappings;
|
||||||
using NzbDrone.Core.Validation.Paths;
|
using NzbDrone.Core.Validation.Paths;
|
||||||
|
|
||||||
|
@ -28,22 +27,11 @@ namespace Lidarr.Api.V1.RemotePathMappings
|
||||||
SharedValidator.RuleFor(c => c.RemotePath)
|
SharedValidator.RuleFor(c => c.RemotePath)
|
||||||
.NotEmpty();
|
.NotEmpty();
|
||||||
|
|
||||||
SharedValidator.RuleFor(c => c.RemotePath)
|
|
||||||
.Must(remotePath => remotePath.IsNotNullOrWhiteSpace() && !remotePath.StartsWith(" "))
|
|
||||||
.WithMessage("Remote Path '{PropertyValue}' must not start with a space");
|
|
||||||
|
|
||||||
SharedValidator.RuleFor(c => c.RemotePath)
|
|
||||||
.Must(remotePath => remotePath.IsNotNullOrWhiteSpace() && !remotePath.EndsWith(" "))
|
|
||||||
.WithMessage("Remote Path '{PropertyValue}' must not end with a space");
|
|
||||||
|
|
||||||
SharedValidator.RuleFor(c => c.LocalPath)
|
SharedValidator.RuleFor(c => c.LocalPath)
|
||||||
.Cascade(CascadeMode.Stop)
|
.Cascade(CascadeMode.Stop)
|
||||||
.IsValidPath()
|
.IsValidPath()
|
||||||
.SetValidator(mappedNetworkDriveValidator)
|
.SetValidator(mappedNetworkDriveValidator)
|
||||||
.SetValidator(pathExistsValidator)
|
.SetValidator(pathExistsValidator);
|
||||||
.SetValidator(new SystemFolderValidator())
|
|
||||||
.NotEqual("/")
|
|
||||||
.WithMessage("Cannot be set to '/'");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override RemotePathMappingResource GetResourceById(int id)
|
public override RemotePathMappingResource GetResourceById(int id)
|
||||||
|
@ -53,7 +41,7 @@ namespace Lidarr.Api.V1.RemotePathMappings
|
||||||
|
|
||||||
[RestPostById]
|
[RestPostById]
|
||||||
[Consumes("application/json")]
|
[Consumes("application/json")]
|
||||||
public ActionResult<RemotePathMappingResource> CreateMapping([FromBody] RemotePathMappingResource resource)
|
public ActionResult<RemotePathMappingResource> CreateMapping(RemotePathMappingResource resource)
|
||||||
{
|
{
|
||||||
var model = resource.ToModel();
|
var model = resource.ToModel();
|
||||||
|
|
||||||
|
@ -74,7 +62,7 @@ namespace Lidarr.Api.V1.RemotePathMappings
|
||||||
}
|
}
|
||||||
|
|
||||||
[RestPutById]
|
[RestPutById]
|
||||||
public ActionResult<RemotePathMappingResource> UpdateMapping([FromBody] RemotePathMappingResource resource)
|
public ActionResult<RemotePathMappingResource> UpdateMapping(RemotePathMappingResource resource)
|
||||||
{
|
{
|
||||||
var mapping = resource.ToModel();
|
var mapping = resource.ToModel();
|
||||||
|
|
||||||
|
|
|
@ -92,7 +92,7 @@ namespace Lidarr.Api.V1.System.Backup
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("restore/upload")]
|
[HttpPost("restore/upload")]
|
||||||
[RequestFormLimits(MultipartBodyLengthLimit = 5000000000)]
|
[RequestFormLimits(MultipartBodyLengthLimit = 1000000000)]
|
||||||
public object UploadAndRestore()
|
public object UploadAndRestore()
|
||||||
{
|
{
|
||||||
var files = Request.Form.Files;
|
var files = Request.Form.Files;
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using FluentValidation;
|
|
||||||
using Lidarr.Http;
|
using Lidarr.Http;
|
||||||
using Lidarr.Http.REST;
|
using Lidarr.Http.REST;
|
||||||
using Lidarr.Http.REST.Attributes;
|
using Lidarr.Http.REST.Attributes;
|
||||||
|
@ -24,8 +23,6 @@ namespace Lidarr.Api.V1.Tags
|
||||||
: base(signalRBroadcaster)
|
: base(signalRBroadcaster)
|
||||||
{
|
{
|
||||||
_tagService = tagService;
|
_tagService = tagService;
|
||||||
|
|
||||||
SharedValidator.RuleFor(c => c.Label).NotEmpty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override TagResource GetResourceById(int id)
|
public override TagResource GetResourceById(int id)
|
||||||
|
|
|
@ -9808,8 +9808,7 @@
|
||||||
"nullable": true
|
"nullable": true
|
||||||
},
|
},
|
||||||
"wikiUrl": {
|
"wikiUrl": {
|
||||||
"type": "string",
|
"$ref": "#/components/schemas/HttpUri"
|
||||||
"nullable": true
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false
|
||||||
|
@ -10063,6 +10062,48 @@
|
||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false
|
||||||
},
|
},
|
||||||
|
"HttpUri": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"fullUri": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": true,
|
||||||
|
"readOnly": true
|
||||||
|
},
|
||||||
|
"scheme": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": true,
|
||||||
|
"readOnly": true
|
||||||
|
},
|
||||||
|
"host": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": true,
|
||||||
|
"readOnly": true
|
||||||
|
},
|
||||||
|
"port": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32",
|
||||||
|
"nullable": true,
|
||||||
|
"readOnly": true
|
||||||
|
},
|
||||||
|
"path": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": true,
|
||||||
|
"readOnly": true
|
||||||
|
},
|
||||||
|
"query": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": true,
|
||||||
|
"readOnly": true
|
||||||
|
},
|
||||||
|
"fragment": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": true,
|
||||||
|
"readOnly": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
"ImportListBulkResource": {
|
"ImportListBulkResource": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
@ -12881,7 +12922,6 @@
|
||||||
"downloading",
|
"downloading",
|
||||||
"downloadFailed",
|
"downloadFailed",
|
||||||
"downloadFailedPending",
|
"downloadFailedPending",
|
||||||
"importBlocked",
|
|
||||||
"importPending",
|
"importPending",
|
||||||
"importing",
|
"importing",
|
||||||
"importFailed",
|
"importFailed",
|
||||||
|
|
|
@ -1,14 +1,9 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using System.Security.Cryptography;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Xml;
|
|
||||||
using Microsoft.AspNetCore.Authentication;
|
using Microsoft.AspNetCore.Authentication;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NLog;
|
|
||||||
using NzbDrone.Common.EnvironmentInfo;
|
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Core.Authentication;
|
using NzbDrone.Core.Authentication;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
|
@ -21,15 +16,11 @@ namespace Lidarr.Http.Authentication
|
||||||
{
|
{
|
||||||
private readonly IAuthenticationService _authService;
|
private readonly IAuthenticationService _authService;
|
||||||
private readonly IConfigFileProvider _configFileProvider;
|
private readonly IConfigFileProvider _configFileProvider;
|
||||||
private readonly IAppFolderInfo _appFolderInfo;
|
|
||||||
private readonly Logger _logger;
|
|
||||||
|
|
||||||
public AuthenticationController(IAuthenticationService authService, IConfigFileProvider configFileProvider, IAppFolderInfo appFolderInfo, Logger logger)
|
public AuthenticationController(IAuthenticationService authService, IConfigFileProvider configFileProvider)
|
||||||
{
|
{
|
||||||
_authService = authService;
|
_authService = authService;
|
||||||
_configFileProvider = configFileProvider;
|
_configFileProvider = configFileProvider;
|
||||||
_appFolderInfo = appFolderInfo;
|
|
||||||
_logger = logger;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("login")]
|
[HttpPost("login")]
|
||||||
|
@ -54,23 +45,7 @@ namespace Lidarr.Http.Authentication
|
||||||
IsPersistent = resource.RememberMe == "on"
|
IsPersistent = resource.RememberMe == "on"
|
||||||
};
|
};
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await HttpContext.SignInAsync(AuthenticationType.Forms.ToString(), new ClaimsPrincipal(new ClaimsIdentity(claims, "Cookies", "user", "identifier")), authProperties);
|
await HttpContext.SignInAsync(AuthenticationType.Forms.ToString(), new ClaimsPrincipal(new ClaimsIdentity(claims, "Cookies", "user", "identifier")), authProperties);
|
||||||
}
|
|
||||||
catch (CryptographicException e)
|
|
||||||
{
|
|
||||||
if (e.InnerException is XmlException)
|
|
||||||
{
|
|
||||||
_logger.Error(e, "Failed to authenticate user due to corrupt XML. Please remove all XML files from {0} and restart Lidarr", Path.Combine(_appFolderInfo.AppDataFolder, "asp"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_logger.Error(e, "Failed to authenticate user. {0}", e.Message);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Unauthorized();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (returnUrl.IsNullOrWhiteSpace() || !Url.IsLocalUrl(returnUrl))
|
if (returnUrl.IsNullOrWhiteSpace() || !Url.IsLocalUrl(returnUrl))
|
||||||
{
|
{
|
||||||
|
|
|
@ -77,7 +77,7 @@ namespace Lidarr.Http.Authentication
|
||||||
|
|
||||||
private void LogSuccess(HttpRequest context, string username)
|
private void LogSuccess(HttpRequest context, string username)
|
||||||
{
|
{
|
||||||
_authLogger.Debug("Auth-Success ip {0} username '{1}'", context.GetRemoteIP(), username);
|
_authLogger.Info("Auth-Success ip {0} username '{1}'", context.GetRemoteIP(), username);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LogLogout(HttpRequest context, string username)
|
private void LogLogout(HttpRequest context, string username)
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="FluentValidation" Version="9.5.4" />
|
<PackageReference Include="FluentValidation" Version="9.5.4" />
|
||||||
<PackageReference Include="ImpromptuInterface" Version="7.0.1" />
|
<PackageReference Include="ImpromptuInterface" Version="7.0.1" />
|
||||||
<PackageReference Include="NLog" Version="5.4.0" />
|
<PackageReference Include="NLog" Version="5.3.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\NzbDrone.Core\Lidarr.Core.csproj" />
|
<ProjectReference Include="..\NzbDrone.Core\Lidarr.Core.csproj" />
|
||||||
|
|
|
@ -40,16 +40,15 @@ namespace NzbDrone.Automation.Test
|
||||||
var service = ChromeDriverService.CreateDefaultService();
|
var service = ChromeDriverService.CreateDefaultService();
|
||||||
|
|
||||||
// Timeout as windows automation tests seem to take alot longer to get going
|
// Timeout as windows automation tests seem to take alot longer to get going
|
||||||
driver = new ChromeDriver(service, options, TimeSpan.FromMinutes(3));
|
driver = new ChromeDriver(service, options, new TimeSpan(0, 3, 0));
|
||||||
|
|
||||||
driver.Manage().Window.Size = new System.Drawing.Size(1920, 1080);
|
driver.Manage().Window.Size = new System.Drawing.Size(1920, 1080);
|
||||||
driver.Manage().Window.FullScreen();
|
|
||||||
|
|
||||||
_runner = new NzbDroneRunner(LogManager.GetCurrentClassLogger(), null);
|
_runner = new NzbDroneRunner(LogManager.GetCurrentClassLogger(), null);
|
||||||
_runner.KillAll();
|
_runner.KillAll();
|
||||||
_runner.Start(true);
|
_runner.Start(true);
|
||||||
|
|
||||||
driver.Navigate().GoToUrl("http://localhost:8686");
|
driver.Url = "http://localhost:8686";
|
||||||
|
|
||||||
var page = new PageBase(driver);
|
var page = new PageBase(driver);
|
||||||
page.WaitForNoSpinner();
|
page.WaitForNoSpinner();
|
||||||
|
@ -69,7 +68,7 @@ namespace NzbDrone.Automation.Test
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var image = (driver as ITakesScreenshot).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)
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Selenium.Support" Version="3.141.0" />
|
<PackageReference Include="Selenium.Support" Version="3.141.0" />
|
||||||
<PackageReference Include="Selenium.WebDriver.ChromeDriver" Version="134.0.6998.16500" />
|
<PackageReference Include="Selenium.WebDriver.ChromeDriver" Version="111.0.5563.6400" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\NzbDrone.Test.Common\Lidarr.Test.Common.csproj" />
|
<ProjectReference Include="..\NzbDrone.Test.Common\Lidarr.Test.Common.csproj" />
|
||||||
|
|
|
@ -1,17 +1,19 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using OpenQA.Selenium;
|
using OpenQA.Selenium;
|
||||||
|
using OpenQA.Selenium.Remote;
|
||||||
using OpenQA.Selenium.Support.UI;
|
using OpenQA.Selenium.Support.UI;
|
||||||
|
|
||||||
namespace NzbDrone.Automation.Test.PageModel
|
namespace NzbDrone.Automation.Test.PageModel
|
||||||
{
|
{
|
||||||
public class PageBase
|
public class PageBase
|
||||||
{
|
{
|
||||||
private readonly IWebDriver _driver;
|
private readonly RemoteWebDriver _driver;
|
||||||
|
|
||||||
public PageBase(IWebDriver driver)
|
public PageBase(RemoteWebDriver driver)
|
||||||
{
|
{
|
||||||
_driver = driver;
|
_driver = driver;
|
||||||
|
driver.Manage().Window.Maximize();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IWebElement FindByClass(string className, int timeout = 5)
|
public IWebElement FindByClass(string className, int timeout = 5)
|
||||||
|
|
|
@ -3,7 +3,6 @@ using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.IO.Abstractions;
|
using System.IO.Abstractions;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
|
||||||
using NLog;
|
using NLog;
|
||||||
using NzbDrone.Common.EnsureThat;
|
using NzbDrone.Common.EnsureThat;
|
||||||
using NzbDrone.Common.EnvironmentInfo;
|
using NzbDrone.Common.EnvironmentInfo;
|
||||||
|
@ -307,26 +306,9 @@ namespace NzbDrone.Common.Disk
|
||||||
{
|
{
|
||||||
Ensure.That(path, () => path).IsValidPath(PathValidationType.CurrentOs);
|
Ensure.That(path, () => path).IsValidPath(PathValidationType.CurrentOs);
|
||||||
|
|
||||||
var files = GetFiles(path, recursive).ToList();
|
var files = GetFiles(path, recursive);
|
||||||
|
|
||||||
files.ForEach(RemoveReadOnly);
|
files.ToList().ForEach(RemoveReadOnly);
|
||||||
|
|
||||||
var attempts = 0;
|
|
||||||
|
|
||||||
while (attempts < 3 && files.Any())
|
|
||||||
{
|
|
||||||
EmptyFolder(path);
|
|
||||||
|
|
||||||
if (GetFiles(path, recursive).Any())
|
|
||||||
{
|
|
||||||
// Wait for IO operations to complete after emptying the folder since they aren't always
|
|
||||||
// instantly removed and it can lead to false positives that files are still present.
|
|
||||||
Thread.Sleep(3000);
|
|
||||||
}
|
|
||||||
|
|
||||||
attempts++;
|
|
||||||
files = GetFiles(path, recursive).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
_fileSystem.Directory.Delete(path, recursive);
|
_fileSystem.Directory.Delete(path, recursive);
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,7 +141,7 @@ namespace NzbDrone.Common.Http.Dispatchers
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException ex) when (cts.IsCancellationRequested)
|
catch (OperationCanceledException ex) when (cts.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
throw new WebException("Http request timed out", ex, WebExceptionStatus.Timeout, null);
|
throw new WebException("Http request timed out", ex.InnerException, WebExceptionStatus.Timeout, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
using System.Text;
|
|
||||||
using NLog;
|
|
||||||
using NLog.Layouts.ClefJsonLayout;
|
|
||||||
using NzbDrone.Common.EnvironmentInfo;
|
|
||||||
|
|
||||||
namespace NzbDrone.Common.Instrumentation;
|
|
||||||
|
|
||||||
public class CleansingClefLogLayout : CompactJsonLayout
|
|
||||||
{
|
|
||||||
protected override void RenderFormattedMessage(LogEventInfo logEvent, StringBuilder target)
|
|
||||||
{
|
|
||||||
base.RenderFormattedMessage(logEvent, target);
|
|
||||||
|
|
||||||
if (RuntimeInfo.IsProduction)
|
|
||||||
{
|
|
||||||
var result = CleanseLogMessage.Cleanse(target.ToString());
|
|
||||||
target.Clear();
|
|
||||||
target.Append(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
using System.Text;
|
|
||||||
using NLog;
|
|
||||||
using NLog.Layouts;
|
|
||||||
using NzbDrone.Common.EnvironmentInfo;
|
|
||||||
|
|
||||||
namespace NzbDrone.Common.Instrumentation;
|
|
||||||
|
|
||||||
public class CleansingConsoleLogLayout : SimpleLayout
|
|
||||||
{
|
|
||||||
public CleansingConsoleLogLayout(string format)
|
|
||||||
: base(format)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void RenderFormattedMessage(LogEventInfo logEvent, StringBuilder target)
|
|
||||||
{
|
|
||||||
base.RenderFormattedMessage(logEvent, target);
|
|
||||||
|
|
||||||
if (RuntimeInfo.IsProduction)
|
|
||||||
{
|
|
||||||
var result = CleanseLogMessage.Cleanse(target.ToString());
|
|
||||||
target.Clear();
|
|
||||||
target.Append(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,7 +4,7 @@ using NLog.Targets;
|
||||||
|
|
||||||
namespace NzbDrone.Common.Instrumentation
|
namespace NzbDrone.Common.Instrumentation
|
||||||
{
|
{
|
||||||
public class CleansingFileTarget : FileTarget
|
public class NzbDroneFileTarget : FileTarget
|
||||||
{
|
{
|
||||||
protected override void RenderFormattedMessage(LogEventInfo logEvent, StringBuilder target)
|
protected override void RenderFormattedMessage(LogEventInfo logEvent, StringBuilder target)
|
||||||
{
|
{
|
|
@ -3,6 +3,7 @@ using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using NLog;
|
using NLog;
|
||||||
using NLog.Config;
|
using NLog.Config;
|
||||||
|
using NLog.Layouts.ClefJsonLayout;
|
||||||
using NLog.Targets;
|
using NLog.Targets;
|
||||||
using NzbDrone.Common.EnvironmentInfo;
|
using NzbDrone.Common.EnvironmentInfo;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
|
@ -12,11 +13,9 @@ namespace NzbDrone.Common.Instrumentation
|
||||||
{
|
{
|
||||||
public static class NzbDroneLogger
|
public static class NzbDroneLogger
|
||||||
{
|
{
|
||||||
private const string FileLogLayout = @"${date:format=yyyy-MM-dd HH\:mm\:ss.f}|${level}|${logger}|${message}${onexception:inner=${newline}${newline}[v${assembly-version}] ${exception:format=ToString}${newline}${exception:format=Data}${newline}}";
|
private const string FILE_LOG_LAYOUT = @"${date:format=yyyy-MM-dd HH\:mm\:ss.f}|${level}|${logger}|${message}${onexception:inner=${newline}${newline}[v${assembly-version}] ${exception:format=ToString}${newline}${exception:format=Data}${newline}}";
|
||||||
private const string ConsoleFormat = "[${level}] ${logger}: ${message} ${onexception:inner=${newline}${newline}[v${assembly-version}] ${exception:format=ToString}${newline}${exception:format=Data}${newline}}";
|
public const string ConsoleLogLayout = "[${level}] ${logger}: ${message} ${onexception:inner=${newline}${newline}[v${assembly-version}] ${exception:format=ToString}${newline}${exception:format=Data}${newline}}";
|
||||||
|
public static CompactJsonLayout ClefLogLayout = new CompactJsonLayout();
|
||||||
private static readonly CleansingConsoleLogLayout CleansingConsoleLayout = new (ConsoleFormat);
|
|
||||||
private static readonly CleansingClefLogLayout ClefLogLayout = new ();
|
|
||||||
|
|
||||||
private static bool _isConfigured;
|
private static bool _isConfigured;
|
||||||
|
|
||||||
|
@ -119,7 +118,11 @@ namespace NzbDrone.Common.Instrumentation
|
||||||
? formatEnumValue
|
? formatEnumValue
|
||||||
: ConsoleLogFormat.Standard;
|
: ConsoleLogFormat.Standard;
|
||||||
|
|
||||||
ConfigureConsoleLayout(coloredConsoleTarget, logFormat);
|
coloredConsoleTarget.Layout = logFormat switch
|
||||||
|
{
|
||||||
|
ConsoleLogFormat.Clef => ClefLogLayout,
|
||||||
|
_ => ConsoleLogLayout
|
||||||
|
};
|
||||||
|
|
||||||
var loggingRule = new LoggingRule("*", level, coloredConsoleTarget);
|
var loggingRule = new LoggingRule("*", level, coloredConsoleTarget);
|
||||||
|
|
||||||
|
@ -136,7 +139,7 @@ namespace NzbDrone.Common.Instrumentation
|
||||||
|
|
||||||
private static void RegisterAppFile(IAppFolderInfo appFolderInfo, string name, string fileName, int maxArchiveFiles, LogLevel minLogLevel)
|
private static void RegisterAppFile(IAppFolderInfo appFolderInfo, string name, string fileName, int maxArchiveFiles, LogLevel minLogLevel)
|
||||||
{
|
{
|
||||||
var fileTarget = new CleansingFileTarget();
|
var fileTarget = new NzbDroneFileTarget();
|
||||||
|
|
||||||
fileTarget.Name = name;
|
fileTarget.Name = name;
|
||||||
fileTarget.FileName = Path.Combine(appFolderInfo.GetLogFolder(), fileName);
|
fileTarget.FileName = Path.Combine(appFolderInfo.GetLogFolder(), fileName);
|
||||||
|
@ -149,7 +152,7 @@ namespace NzbDrone.Common.Instrumentation
|
||||||
fileTarget.MaxArchiveFiles = maxArchiveFiles;
|
fileTarget.MaxArchiveFiles = maxArchiveFiles;
|
||||||
fileTarget.EnableFileDelete = true;
|
fileTarget.EnableFileDelete = true;
|
||||||
fileTarget.ArchiveNumbering = ArchiveNumberingMode.Rolling;
|
fileTarget.ArchiveNumbering = ArchiveNumberingMode.Rolling;
|
||||||
fileTarget.Layout = FileLogLayout;
|
fileTarget.Layout = FILE_LOG_LAYOUT;
|
||||||
|
|
||||||
var loggingRule = new LoggingRule("*", minLogLevel, fileTarget);
|
var loggingRule = new LoggingRule("*", minLogLevel, fileTarget);
|
||||||
|
|
||||||
|
@ -168,7 +171,7 @@ namespace NzbDrone.Common.Instrumentation
|
||||||
fileTarget.ConcurrentWrites = false;
|
fileTarget.ConcurrentWrites = false;
|
||||||
fileTarget.ConcurrentWriteAttemptDelay = 50;
|
fileTarget.ConcurrentWriteAttemptDelay = 50;
|
||||||
fileTarget.ConcurrentWriteAttempts = 100;
|
fileTarget.ConcurrentWriteAttempts = 100;
|
||||||
fileTarget.Layout = FileLogLayout;
|
fileTarget.Layout = FILE_LOG_LAYOUT;
|
||||||
|
|
||||||
var loggingRule = new LoggingRule("*", LogLevel.Trace, fileTarget);
|
var loggingRule = new LoggingRule("*", LogLevel.Trace, fileTarget);
|
||||||
|
|
||||||
|
@ -213,15 +216,6 @@ namespace NzbDrone.Common.Instrumentation
|
||||||
{
|
{
|
||||||
return GetLogger(obj.GetType());
|
return GetLogger(obj.GetType());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ConfigureConsoleLayout(ColoredConsoleTarget target, ConsoleLogFormat format)
|
|
||||||
{
|
|
||||||
target.Layout = format switch
|
|
||||||
{
|
|
||||||
ConsoleLogFormat.Clef => NzbDroneLogger.ClefLogLayout,
|
|
||||||
_ => NzbDroneLogger.CleansingConsoleLayout
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ConsoleLogFormat
|
public enum ConsoleLogFormat
|
||||||
|
|
|
@ -6,17 +6,17 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="DryIoc.dll" Version="5.4.3" />
|
<PackageReference Include="DryIoc.dll" Version="5.4.3" />
|
||||||
<PackageReference Include="IPAddressRange" Version="6.2.0" />
|
<PackageReference Include="IPAddressRange" Version="6.1.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.1" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.1" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<PackageReference Include="NLog" Version="5.4.0" />
|
<PackageReference Include="NLog" Version="5.3.4" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.2" />
|
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.2" />
|
||||||
<PackageReference Include="NLog.Layouts.ClefJsonLayout" Version="1.0.3" />
|
<PackageReference Include="NLog.Layouts.ClefJsonLayout" Version="1.0.2" />
|
||||||
<PackageReference Include="Sentry" Version="4.0.2" />
|
<PackageReference Include="Sentry" Version="4.0.2" />
|
||||||
<PackageReference Include="SharpZipLib" Version="1.4.2" />
|
<PackageReference Include="SharpZipLib" Version="1.4.2" />
|
||||||
<PackageReference Include="System.IO.Abstractions" Version="17.0.24" />
|
<PackageReference Include="System.IO.Abstractions" Version="17.0.24" />
|
||||||
<PackageReference Include="System.Text.Json" Version="6.0.10" />
|
<PackageReference Include="System.Text.Json" Version="6.0.10" />
|
||||||
<PackageReference Include="System.ValueTuple" Version="4.6.1" />
|
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
|
||||||
<PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.115.5-18" />
|
<PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.115.5-18" />
|
||||||
<PackageReference Include="System.Runtime.Loader" Version="4.3.0" />
|
<PackageReference Include="System.Runtime.Loader" Version="4.3.0" />
|
||||||
<PackageReference Include="System.Configuration.ConfigurationManager" Version="6.0.1" />
|
<PackageReference Include="System.Configuration.ConfigurationManager" Version="6.0.1" />
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using NzbDrone.Common.EnvironmentInfo;
|
using NzbDrone.Common.EnvironmentInfo;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
|
@ -7,7 +6,7 @@ namespace NzbDrone.Common
|
||||||
{
|
{
|
||||||
public class PathEqualityComparer : IEqualityComparer<string>
|
public class PathEqualityComparer : IEqualityComparer<string>
|
||||||
{
|
{
|
||||||
public static readonly PathEqualityComparer Instance = new ();
|
public static readonly PathEqualityComparer Instance = new PathEqualityComparer();
|
||||||
|
|
||||||
private PathEqualityComparer()
|
private PathEqualityComparer()
|
||||||
{
|
{
|
||||||
|
@ -19,8 +18,6 @@ namespace NzbDrone.Common
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetHashCode(string obj)
|
public int GetHashCode(string obj)
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
if (OsInfo.IsWindows)
|
if (OsInfo.IsWindows)
|
||||||
{
|
{
|
||||||
|
@ -29,10 +26,5 @@ namespace NzbDrone.Common
|
||||||
|
|
||||||
return obj.CleanFilePath().Normalize().GetHashCode();
|
return obj.CleanFilePath().Normalize().GetHashCode();
|
||||||
}
|
}
|
||||||
catch (ArgumentException ex)
|
|
||||||
{
|
|
||||||
throw new ArgumentException($"Invalid path: {obj}", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ using System.ComponentModel;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
|
||||||
using NLog;
|
using NLog;
|
||||||
using NzbDrone.Common.EnvironmentInfo;
|
using NzbDrone.Common.EnvironmentInfo;
|
||||||
using NzbDrone.Common.Model;
|
using NzbDrone.Common.Model;
|
||||||
|
@ -118,9 +117,7 @@ namespace NzbDrone.Common.Processes
|
||||||
UseShellExecute = false,
|
UseShellExecute = false,
|
||||||
RedirectStandardError = true,
|
RedirectStandardError = true,
|
||||||
RedirectStandardOutput = true,
|
RedirectStandardOutput = true,
|
||||||
RedirectStandardInput = true,
|
RedirectStandardInput = true
|
||||||
StandardOutputEncoding = Encoding.UTF8,
|
|
||||||
StandardErrorEncoding = Encoding.UTF8
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (environmentVariables != null)
|
if (environmentVariables != null)
|
||||||
|
|
|
@ -103,7 +103,6 @@ namespace NzbDrone.Core.Test.DiskSpace
|
||||||
[TestCase("/var/lib/docker")]
|
[TestCase("/var/lib/docker")]
|
||||||
[TestCase("/some/place/docker/aufs")]
|
[TestCase("/some/place/docker/aufs")]
|
||||||
[TestCase("/etc/network")]
|
[TestCase("/etc/network")]
|
||||||
[TestCase("/Volumes/.timemachine/ABC123456-A1BC-12A3B45678C9/2025-05-13-181401.backup")]
|
|
||||||
public void should_not_check_diskspace_for_irrelevant_mounts(string path)
|
public void should_not_check_diskspace_for_irrelevant_mounts(string path)
|
||||||
{
|
{
|
||||||
var mount = new Mock<IMount>();
|
var mount = new Mock<IMount>();
|
||||||
|
|
|
@ -183,8 +183,6 @@ namespace NzbDrone.Core.Test.Download.CompletedDownloadServiceTests
|
||||||
{
|
{
|
||||||
GivenArtistMatch();
|
GivenArtistMatch();
|
||||||
|
|
||||||
var tracks = Builder<Track>.CreateListOfSize(3).BuildList();
|
|
||||||
|
|
||||||
_trackedDownload.RemoteAlbum.Albums = new List<Album>
|
_trackedDownload.RemoteAlbum.Albums = new List<Album>
|
||||||
{
|
{
|
||||||
CreateAlbum(1, 3)
|
CreateAlbum(1, 3)
|
||||||
|
@ -194,9 +192,9 @@ namespace NzbDrone.Core.Test.Download.CompletedDownloadServiceTests
|
||||||
.Setup(v => v.ProcessPath(It.IsAny<string>(), It.IsAny<ImportMode>(), It.IsAny<Artist>(), It.IsAny<DownloadClientItem>()))
|
.Setup(v => v.ProcessPath(It.IsAny<string>(), It.IsAny<ImportMode>(), It.IsAny<Artist>(), It.IsAny<DownloadClientItem>()))
|
||||||
.Returns(new List<ImportResult>
|
.Returns(new List<ImportResult>
|
||||||
{
|
{
|
||||||
new ImportResult(new ImportDecision<LocalTrack>(new LocalTrack { Path = @"C:\TestPath\Droned.S01E01.mkv".AsOsAgnostic(), Tracks = new List<Track> { tracks[0] } })),
|
new ImportResult(new ImportDecision<LocalTrack>(new LocalTrack { Path = @"C:\TestPath\Droned.S01E01.mkv".AsOsAgnostic() })),
|
||||||
new ImportResult(new ImportDecision<LocalTrack>(new LocalTrack { Path = @"C:\TestPath\Droned.S01E01.mkv".AsOsAgnostic(), Tracks = new List<Track> { tracks[1] } })),
|
new ImportResult(new ImportDecision<LocalTrack>(new LocalTrack { Path = @"C:\TestPath\Droned.S01E01.mkv".AsOsAgnostic() })),
|
||||||
new ImportResult(new ImportDecision<LocalTrack>(new LocalTrack { Path = @"C:\TestPath\Droned.S01E01.mkv".AsOsAgnostic(), Tracks = new List<Track> { tracks[2] } })),
|
new ImportResult(new ImportDecision<LocalTrack>(new LocalTrack { Path = @"C:\TestPath\Droned.S01E01.mkv".AsOsAgnostic() })),
|
||||||
new ImportResult(new ImportDecision<LocalTrack>(new LocalTrack { Path = @"C:\TestPath\Droned.S01E01.mkv".AsOsAgnostic() }), "Test Failure")
|
new ImportResult(new ImportDecision<LocalTrack>(new LocalTrack { Path = @"C:\TestPath\Droned.S01E01.mkv".AsOsAgnostic() }), "Test Failure")
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -292,9 +290,6 @@ namespace NzbDrone.Core.Test.Download.CompletedDownloadServiceTests
|
||||||
[Test]
|
[Test]
|
||||||
public void should_mark_as_imported_if_all_tracks_were_imported()
|
public void should_mark_as_imported_if_all_tracks_were_imported()
|
||||||
{
|
{
|
||||||
var track1 = new Track { Id = 1 };
|
|
||||||
var track2 = new Track { Id = 2 };
|
|
||||||
|
|
||||||
_trackedDownload.RemoteAlbum.Albums = new List<Album>
|
_trackedDownload.RemoteAlbum.Albums = new List<Album>
|
||||||
{
|
{
|
||||||
CreateAlbum(1, 2)
|
CreateAlbum(1, 2)
|
||||||
|
@ -306,11 +301,11 @@ namespace NzbDrone.Core.Test.Download.CompletedDownloadServiceTests
|
||||||
{
|
{
|
||||||
new ImportResult(
|
new ImportResult(
|
||||||
new ImportDecision<LocalTrack>(
|
new ImportDecision<LocalTrack>(
|
||||||
new LocalTrack { Path = @"C:\TestPath\Droned.S01E01.mkv".AsOsAgnostic(), Tracks = new List<Track> { track1 } })),
|
new LocalTrack { Path = @"C:\TestPath\Droned.S01E01.mkv".AsOsAgnostic() })),
|
||||||
|
|
||||||
new ImportResult(
|
new ImportResult(
|
||||||
new ImportDecision<LocalTrack>(
|
new ImportDecision<LocalTrack>(
|
||||||
new LocalTrack { Path = @"C:\TestPath\Droned.S01E02.mkv".AsOsAgnostic(), Tracks = new List<Track> { track2 } }))
|
new LocalTrack { Path = @"C:\TestPath\Droned.S01E02.mkv".AsOsAgnostic() }))
|
||||||
});
|
});
|
||||||
|
|
||||||
Subject.Import(_trackedDownload);
|
Subject.Import(_trackedDownload);
|
||||||
|
@ -372,13 +367,11 @@ namespace NzbDrone.Core.Test.Download.CompletedDownloadServiceTests
|
||||||
{
|
{
|
||||||
GivenABadlyNamedDownload();
|
GivenABadlyNamedDownload();
|
||||||
|
|
||||||
var track1 = new Track { Id = 1 };
|
|
||||||
|
|
||||||
Mocker.GetMock<IDownloadedTracksImportService>()
|
Mocker.GetMock<IDownloadedTracksImportService>()
|
||||||
.Setup(v => v.ProcessPath(It.IsAny<string>(), It.IsAny<ImportMode>(), It.IsAny<Artist>(), It.IsAny<DownloadClientItem>()))
|
.Setup(v => v.ProcessPath(It.IsAny<string>(), It.IsAny<ImportMode>(), It.IsAny<Artist>(), It.IsAny<DownloadClientItem>()))
|
||||||
.Returns(new List<ImportResult>
|
.Returns(new List<ImportResult>
|
||||||
{
|
{
|
||||||
new ImportResult(new ImportDecision<LocalTrack>(new LocalTrack { Path = @"C:\TestPath\Droned.S01E01.mkv".AsOsAgnostic(), Tracks = new List<Track> { track1 } }))
|
new ImportResult(new ImportDecision<LocalTrack>(new LocalTrack { Path = @"C:\TestPath\Droned.S01E01.mkv".AsOsAgnostic() }))
|
||||||
});
|
});
|
||||||
|
|
||||||
Mocker.GetMock<IArtistService>()
|
Mocker.GetMock<IArtistService>()
|
||||||
|
|
|
@ -80,7 +80,7 @@ namespace NzbDrone.Core.Test.ImportListTests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
[Ignore("Pending mapping fixes", Until = "2025-10-20 00:00:00Z")]
|
[Ignore("Pending mapping fixes", Until = "2025-04-20 00:00:00Z")]
|
||||||
public void map_artist_should_work()
|
public void map_artist_should_work()
|
||||||
{
|
{
|
||||||
UseRealHttp();
|
UseRealHttp();
|
||||||
|
@ -159,7 +159,7 @@ namespace NzbDrone.Core.Test.ImportListTests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
[Ignore("Pending mapping fixes", Until = "2025-10-20 00:00:00Z")]
|
[Ignore("Pending mapping fixes", Until = "2025-04-20 00:00:00Z")]
|
||||||
public void map_album_should_work()
|
public void map_album_should_work()
|
||||||
{
|
{
|
||||||
UseRealHttp();
|
UseRealHttp();
|
||||||
|
|
|
@ -14,7 +14,6 @@ using NzbDrone.Core.Test.Framework;
|
||||||
namespace NzbDrone.Core.Test.MetadataSource.SkyHook
|
namespace NzbDrone.Core.Test.MetadataSource.SkyHook
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
[Ignore("Waiting for metadata to be back again", Until = "2025-09-01 00:00:00Z")]
|
|
||||||
public class SkyHookProxyFixture : CoreTest<SkyHookProxy>
|
public class SkyHookProxyFixture : CoreTest<SkyHookProxy>
|
||||||
{
|
{
|
||||||
private MetadataProfile _metadataProfile;
|
private MetadataProfile _metadataProfile;
|
||||||
|
|
|
@ -12,7 +12,6 @@ using NzbDrone.Test.Common;
|
||||||
namespace NzbDrone.Core.Test.MetadataSource.SkyHook
|
namespace NzbDrone.Core.Test.MetadataSource.SkyHook
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
[Ignore("Waiting for metadata to be back again", Until = "2025-09-01 00:00:00Z")]
|
|
||||||
public class SkyHookProxySearchFixture : CoreTest<SkyHookProxy>
|
public class SkyHookProxySearchFixture : CoreTest<SkyHookProxy>
|
||||||
{
|
{
|
||||||
[SetUp]
|
[SetUp]
|
||||||
|
|
|
@ -64,7 +64,7 @@ namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase("Florence + the Machine", "Florence + the Machine")]
|
[TestCase("Florence + the Machine", "Florence + the Machine")]
|
||||||
[TestCase("Beyoncé X10", "Beyonce X10")]
|
[TestCase("Beyoncé X10", "Beyoncé X10")]
|
||||||
[TestCase("Girlfriends' Guide to Divorce", "Girlfriends Guide to Divorce")]
|
[TestCase("Girlfriends' Guide to Divorce", "Girlfriends Guide to Divorce")]
|
||||||
[TestCase("Rule #23: Never Lie to the Kids", "Rule #23 Never Lie to the Kids")]
|
[TestCase("Rule #23: Never Lie to the Kids", "Rule #23 Never Lie to the Kids")]
|
||||||
[TestCase("Anne Hathaway/Florence + The Machine", "Anne Hathaway Florence + The Machine")]
|
[TestCase("Anne Hathaway/Florence + The Machine", "Anne Hathaway Florence + The Machine")]
|
||||||
|
@ -81,7 +81,6 @@ namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests
|
||||||
[TestCase("[a] title", "a title")]
|
[TestCase("[a] title", "a title")]
|
||||||
[TestCase("backslash \\ backlash", "backslash backlash")]
|
[TestCase("backslash \\ backlash", "backslash backlash")]
|
||||||
[TestCase("I'm the Boss", "Im the Boss")]
|
[TestCase("I'm the Boss", "Im the Boss")]
|
||||||
[TestCase("Joker: Folie à deux", "Joker Folie a deux")]
|
|
||||||
public void should_get_expected_title_back(string name, string expected)
|
public void should_get_expected_title_back(string name, string expected)
|
||||||
{
|
{
|
||||||
_artist.Name = name;
|
_artist.Name = name;
|
||||||
|
|
|
@ -129,9 +129,6 @@ namespace NzbDrone.Core.Test.ParserTests
|
||||||
[TestCase("Green Day - Father Of All [FLAC (M4A) 24-bit Lossless]", null, 0, 0)]
|
[TestCase("Green Day - Father Of All [FLAC (M4A) 24-bit Lossless]", null, 0, 0)]
|
||||||
[TestCase("Green_Day-Father_Of_All_FLAC_M4A_24_bit_Lossless", null, 0, 0)]
|
[TestCase("Green_Day-Father_Of_All_FLAC_M4A_24_bit_Lossless", null, 0, 0)]
|
||||||
[TestCase("Green.Day-Father.Of.All.FLAC.M4A.24.bit.Lossless", null, 0, 0)]
|
[TestCase("Green.Day-Father.Of.All.FLAC.M4A.24.bit.Lossless", null, 0, 0)]
|
||||||
[TestCase("Linkin Park - Studio Collection 2000-2012 (2013) [WEB FLAC24-44.1]", null, 0, 0)]
|
|
||||||
[TestCase("Linkin Park - Studio Collection 2000-2012 (2013) [WEB FLAC24bit]", null, 0, 0)]
|
|
||||||
[TestCase("Linkin Park - Studio Collection 2000-2012 (2013) [WEB FLAC24-bit]", null, 0, 0)]
|
|
||||||
public void should_parse_flac_24bit_quality(string title, string desc, int bitrate, int sampleSize)
|
public void should_parse_flac_24bit_quality(string title, string desc, int bitrate, int sampleSize)
|
||||||
{
|
{
|
||||||
ParseAndVerifyQuality(title, desc, bitrate, Quality.FLAC_24, sampleSize);
|
ParseAndVerifyQuality(title, desc, bitrate, Quality.FLAC_24, sampleSize);
|
||||||
|
|
|
@ -185,9 +185,7 @@ namespace NzbDrone.Core.Blocklisting
|
||||||
Indexer = message.Data.GetValueOrDefault("indexer"),
|
Indexer = message.Data.GetValueOrDefault("indexer"),
|
||||||
Protocol = (DownloadProtocol)Convert.ToInt32(message.Data.GetValueOrDefault("protocol")),
|
Protocol = (DownloadProtocol)Convert.ToInt32(message.Data.GetValueOrDefault("protocol")),
|
||||||
Message = message.Message,
|
Message = message.Message,
|
||||||
TorrentInfoHash = message.TrackedDownload?.Protocol == DownloadProtocol.Torrent
|
TorrentInfoHash = message.Data.GetValueOrDefault("torrentInfoHash")
|
||||||
? message.TrackedDownload.DownloadItem.DownloadId
|
|
||||||
: message.Data.GetValueOrDefault("torrentInfoHash", null)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (Enum.TryParse(message.Data.GetValueOrDefault("indexerFlags"), true, out IndexerFlags flags))
|
if (Enum.TryParse(message.Data.GetValueOrDefault("indexerFlags"), true, out IndexerFlags flags))
|
||||||
|
|
|
@ -263,21 +263,7 @@ namespace NzbDrone.Core.Configuration
|
||||||
}
|
}
|
||||||
|
|
||||||
public string UiFolder => BuildInfo.IsDebug ? Path.Combine("..", "UI") : "UI";
|
public string UiFolder => BuildInfo.IsDebug ? Path.Combine("..", "UI") : "UI";
|
||||||
|
public string InstanceName => _appOptions.InstanceName ?? GetValue("InstanceName", BuildInfo.AppName);
|
||||||
public string InstanceName
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
var instanceName = _appOptions.InstanceName ?? GetValue("InstanceName", BuildInfo.AppName);
|
|
||||||
|
|
||||||
if (instanceName.Contains(BuildInfo.AppName, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
return instanceName;
|
|
||||||
}
|
|
||||||
|
|
||||||
return BuildInfo.AppName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool UpdateAutomatically => _updateOptions.Automatically ?? GetValueBoolean("UpdateAutomatically", OsInfo.IsWindows, false);
|
public bool UpdateAutomatically => _updateOptions.Automatically ?? GetValueBoolean("UpdateAutomatically", OsInfo.IsWindows, false);
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,6 @@ namespace NzbDrone.Core.CustomFormats
|
||||||
{
|
{
|
||||||
RuleFor(c => c.Min).GreaterThanOrEqualTo(0);
|
RuleFor(c => c.Min).GreaterThanOrEqualTo(0);
|
||||||
RuleFor(c => c.Max).GreaterThan(c => c.Min);
|
RuleFor(c => c.Max).GreaterThan(c => c.Min);
|
||||||
RuleFor(c => c.Max).LessThanOrEqualTo(double.MaxValue);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -252,7 +252,7 @@ namespace NzbDrone.Core.Datastore
|
||||||
|
|
||||||
protected void Delete(SqlBuilder builder)
|
protected void Delete(SqlBuilder builder)
|
||||||
{
|
{
|
||||||
var sql = builder.AddDeleteTemplate(typeof(TModel));
|
var sql = builder.AddDeleteTemplate(typeof(TModel)).LogQuery();
|
||||||
|
|
||||||
using (var conn = _database.OpenConnection())
|
using (var conn = _database.OpenConnection())
|
||||||
{
|
{
|
||||||
|
|
|
@ -20,7 +20,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SpecificationPriority Priority => SpecificationPriority.Disk;
|
public SpecificationPriority Priority => SpecificationPriority.Default;
|
||||||
public RejectionType Type => RejectionType.Permanent;
|
public RejectionType Type => RejectionType.Permanent;
|
||||||
|
|
||||||
public Decision IsSatisfiedBy(RemoteAlbum subject, SearchCriteriaBase searchCriteria)
|
public Decision IsSatisfiedBy(RemoteAlbum subject, SearchCriteriaBase searchCriteria)
|
||||||
|
|
|
@ -21,7 +21,7 @@ namespace NzbDrone.Core.DiskSpace
|
||||||
private readonly IRootFolderService _rootFolderService;
|
private readonly IRootFolderService _rootFolderService;
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
|
|
||||||
private static readonly Regex _regexSpecialDrive = new Regex(@"^/var/lib/(docker|rancher|kubelet)(/|$)|^/(boot|etc)(/|$)|/docker(/var)?/aufs(/|$)|/\.timemachine", RegexOptions.Compiled);
|
private static readonly Regex _regexSpecialDrive = new Regex("^/var/lib/(docker|rancher|kubelet)(/|$)|^/(boot|etc)(/|$)|/docker(/var)?/aufs(/|$)", RegexOptions.Compiled);
|
||||||
|
|
||||||
public DiskSpaceService(IDiskProvider diskProvider,
|
public DiskSpaceService(IDiskProvider diskProvider,
|
||||||
IRootFolderService rootFolderService,
|
IRootFolderService rootFolderService,
|
||||||
|
@ -38,10 +38,7 @@ namespace NzbDrone.Core.DiskSpace
|
||||||
|
|
||||||
var optionalRootFolders = GetFixedDisksRootPaths().Except(importantRootFolders).Distinct().ToList();
|
var optionalRootFolders = GetFixedDisksRootPaths().Except(importantRootFolders).Distinct().ToList();
|
||||||
|
|
||||||
var diskSpace = GetDiskSpace(importantRootFolders)
|
var diskSpace = GetDiskSpace(importantRootFolders).Concat(GetDiskSpace(optionalRootFolders, true)).ToList();
|
||||||
.Concat(GetDiskSpace(optionalRootFolders, true))
|
|
||||||
.OrderBy(d => d.Path, StringComparer.OrdinalIgnoreCase)
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
return diskSpace;
|
return diskSpace;
|
||||||
}
|
}
|
||||||
|
@ -57,7 +54,7 @@ namespace NzbDrone.Core.DiskSpace
|
||||||
private IEnumerable<string> GetFixedDisksRootPaths()
|
private IEnumerable<string> GetFixedDisksRootPaths()
|
||||||
{
|
{
|
||||||
return _diskProvider.GetMounts()
|
return _diskProvider.GetMounts()
|
||||||
.Where(d => d.DriveType is DriveType.Fixed or DriveType.Network)
|
.Where(d => d.DriveType == DriveType.Fixed)
|
||||||
.Where(d => !_regexSpecialDrive.IsMatch(d.RootDirectory))
|
.Where(d => !_regexSpecialDrive.IsMatch(d.RootDirectory))
|
||||||
.Select(d => d.RootDirectory);
|
.Select(d => d.RootDirectory);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,11 +25,6 @@ namespace NzbDrone.Core.Download.Aggregation
|
||||||
|
|
||||||
public RemoteAlbum Augment(RemoteAlbum remoteAlbum)
|
public RemoteAlbum Augment(RemoteAlbum remoteAlbum)
|
||||||
{
|
{
|
||||||
if (remoteAlbum == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var augmenter in _augmenters)
|
foreach (var augmenter in _augmenters)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|
|
@ -9,7 +9,6 @@ using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Common.Http;
|
using NzbDrone.Common.Http;
|
||||||
using NzbDrone.Core.Blocklisting;
|
using NzbDrone.Core.Blocklisting;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
using NzbDrone.Core.Localization;
|
|
||||||
using NzbDrone.Core.MediaFiles.TorrentInfo;
|
using NzbDrone.Core.MediaFiles.TorrentInfo;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
using NzbDrone.Core.RemotePathMappings;
|
using NzbDrone.Core.RemotePathMappings;
|
||||||
|
@ -29,10 +28,9 @@ namespace NzbDrone.Core.Download.Clients.Aria2
|
||||||
IConfigService configService,
|
IConfigService configService,
|
||||||
IDiskProvider diskProvider,
|
IDiskProvider diskProvider,
|
||||||
IRemotePathMappingService remotePathMappingService,
|
IRemotePathMappingService remotePathMappingService,
|
||||||
ILocalizationService localizationService,
|
|
||||||
IBlocklistService blocklistService,
|
IBlocklistService blocklistService,
|
||||||
Logger logger)
|
Logger logger)
|
||||||
: base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, localizationService, blocklistService, logger)
|
: base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, blocklistService, logger)
|
||||||
{
|
{
|
||||||
_proxy = proxy;
|
_proxy = proxy;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Common.Http;
|
using NzbDrone.Common.Http;
|
||||||
using NzbDrone.Core.Blocklisting;
|
using NzbDrone.Core.Blocklisting;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
using NzbDrone.Core.Localization;
|
|
||||||
using NzbDrone.Core.MediaFiles.TorrentInfo;
|
using NzbDrone.Core.MediaFiles.TorrentInfo;
|
||||||
using NzbDrone.Core.Organizer;
|
using NzbDrone.Core.Organizer;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
@ -31,10 +30,9 @@ namespace NzbDrone.Core.Download.Clients.Blackhole
|
||||||
IConfigService configService,
|
IConfigService configService,
|
||||||
IDiskProvider diskProvider,
|
IDiskProvider diskProvider,
|
||||||
IRemotePathMappingService remotePathMappingService,
|
IRemotePathMappingService remotePathMappingService,
|
||||||
ILocalizationService localizationService,
|
|
||||||
IBlocklistService blocklistService,
|
IBlocklistService blocklistService,
|
||||||
Logger logger)
|
Logger logger)
|
||||||
: base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, localizationService, blocklistService, logger)
|
: base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, blocklistService, logger)
|
||||||
{
|
{
|
||||||
_scanWatchFolder = scanWatchFolder;
|
_scanWatchFolder = scanWatchFolder;
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@ using NzbDrone.Common.Disk;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Common.Http;
|
using NzbDrone.Common.Http;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
using NzbDrone.Core.Localization;
|
|
||||||
using NzbDrone.Core.Organizer;
|
using NzbDrone.Core.Organizer;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
using NzbDrone.Core.RemotePathMappings;
|
using NzbDrone.Core.RemotePathMappings;
|
||||||
|
@ -26,9 +25,8 @@ namespace NzbDrone.Core.Download.Clients.Blackhole
|
||||||
IDiskProvider diskProvider,
|
IDiskProvider diskProvider,
|
||||||
IRemotePathMappingService remotePathMappingService,
|
IRemotePathMappingService remotePathMappingService,
|
||||||
IValidateNzbs nzbValidationService,
|
IValidateNzbs nzbValidationService,
|
||||||
ILocalizationService localizationService,
|
|
||||||
Logger logger)
|
Logger logger)
|
||||||
: base(httpClient, configService, diskProvider, remotePathMappingService, nzbValidationService, localizationService, logger)
|
: base(httpClient, configService, diskProvider, remotePathMappingService, nzbValidationService, logger)
|
||||||
{
|
{
|
||||||
_scanWatchFolder = scanWatchFolder;
|
_scanWatchFolder = scanWatchFolder;
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,6 @@ using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Common.Http;
|
using NzbDrone.Common.Http;
|
||||||
using NzbDrone.Core.Blocklisting;
|
using NzbDrone.Core.Blocklisting;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
using NzbDrone.Core.Localization;
|
|
||||||
using NzbDrone.Core.MediaFiles.TorrentInfo;
|
using NzbDrone.Core.MediaFiles.TorrentInfo;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
using NzbDrone.Core.RemotePathMappings;
|
using NzbDrone.Core.RemotePathMappings;
|
||||||
|
@ -28,10 +27,9 @@ namespace NzbDrone.Core.Download.Clients.Deluge
|
||||||
IConfigService configService,
|
IConfigService configService,
|
||||||
IDiskProvider diskProvider,
|
IDiskProvider diskProvider,
|
||||||
IRemotePathMappingService remotePathMappingService,
|
IRemotePathMappingService remotePathMappingService,
|
||||||
ILocalizationService localizationService,
|
|
||||||
IBlocklistService blocklistService,
|
IBlocklistService blocklistService,
|
||||||
Logger logger)
|
Logger logger)
|
||||||
: base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, localizationService, blocklistService, logger)
|
: base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, blocklistService, logger)
|
||||||
{
|
{
|
||||||
_proxy = proxy;
|
_proxy = proxy;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,6 @@ using NzbDrone.Common.Http;
|
||||||
using NzbDrone.Core.Blocklisting;
|
using NzbDrone.Core.Blocklisting;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
using NzbDrone.Core.Download.Clients.DownloadStation.Proxies;
|
using NzbDrone.Core.Download.Clients.DownloadStation.Proxies;
|
||||||
using NzbDrone.Core.Localization;
|
|
||||||
using NzbDrone.Core.MediaFiles.TorrentInfo;
|
using NzbDrone.Core.MediaFiles.TorrentInfo;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
using NzbDrone.Core.RemotePathMappings;
|
using NzbDrone.Core.RemotePathMappings;
|
||||||
|
@ -38,10 +37,9 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
|
||||||
IConfigService configService,
|
IConfigService configService,
|
||||||
IDiskProvider diskProvider,
|
IDiskProvider diskProvider,
|
||||||
IRemotePathMappingService remotePathMappingService,
|
IRemotePathMappingService remotePathMappingService,
|
||||||
ILocalizationService localizationService,
|
|
||||||
IBlocklistService blocklistService,
|
IBlocklistService blocklistService,
|
||||||
Logger logger)
|
Logger logger)
|
||||||
: base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, localizationService, blocklistService, logger)
|
: base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, blocklistService, logger)
|
||||||
{
|
{
|
||||||
_dsInfoProxy = dsInfoProxy;
|
_dsInfoProxy = dsInfoProxy;
|
||||||
_dsTaskProxySelector = dsTaskProxySelector;
|
_dsTaskProxySelector = dsTaskProxySelector;
|
||||||
|
|
|
@ -9,7 +9,6 @@ using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Common.Http;
|
using NzbDrone.Common.Http;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
using NzbDrone.Core.Download.Clients.DownloadStation.Proxies;
|
using NzbDrone.Core.Download.Clients.DownloadStation.Proxies;
|
||||||
using NzbDrone.Core.Localization;
|
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
using NzbDrone.Core.RemotePathMappings;
|
using NzbDrone.Core.RemotePathMappings;
|
||||||
using NzbDrone.Core.ThingiProvider;
|
using NzbDrone.Core.ThingiProvider;
|
||||||
|
@ -35,9 +34,8 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
|
||||||
IDiskProvider diskProvider,
|
IDiskProvider diskProvider,
|
||||||
IRemotePathMappingService remotePathMappingService,
|
IRemotePathMappingService remotePathMappingService,
|
||||||
IValidateNzbs nzbValidationService,
|
IValidateNzbs nzbValidationService,
|
||||||
ILocalizationService localizationService,
|
|
||||||
Logger logger)
|
Logger logger)
|
||||||
: base(httpClient, configService, diskProvider, remotePathMappingService, nzbValidationService, localizationService, logger)
|
: base(httpClient, configService, diskProvider, remotePathMappingService, nzbValidationService, logger)
|
||||||
{
|
{
|
||||||
_dsInfoProxy = dsInfoProxy;
|
_dsInfoProxy = dsInfoProxy;
|
||||||
_dsTaskProxySelector = dsTaskProxySelector;
|
_dsTaskProxySelector = dsTaskProxySelector;
|
||||||
|
|
|
@ -9,7 +9,6 @@ using NzbDrone.Common.Http;
|
||||||
using NzbDrone.Core.Blocklisting;
|
using NzbDrone.Core.Blocklisting;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
using NzbDrone.Core.Download.Clients.Flood.Models;
|
using NzbDrone.Core.Download.Clients.Flood.Models;
|
||||||
using NzbDrone.Core.Localization;
|
|
||||||
using NzbDrone.Core.MediaFiles.TorrentInfo;
|
using NzbDrone.Core.MediaFiles.TorrentInfo;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
using NzbDrone.Core.RemotePathMappings;
|
using NzbDrone.Core.RemotePathMappings;
|
||||||
|
@ -29,10 +28,9 @@ namespace NzbDrone.Core.Download.Clients.Flood
|
||||||
IConfigService configService,
|
IConfigService configService,
|
||||||
IDiskProvider diskProvider,
|
IDiskProvider diskProvider,
|
||||||
IRemotePathMappingService remotePathMappingService,
|
IRemotePathMappingService remotePathMappingService,
|
||||||
ILocalizationService localizationService,
|
|
||||||
IBlocklistService blocklistService,
|
IBlocklistService blocklistService,
|
||||||
Logger logger)
|
Logger logger)
|
||||||
: base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, localizationService, blocklistService, logger)
|
: base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, blocklistService, logger)
|
||||||
{
|
{
|
||||||
_proxy = proxy;
|
_proxy = proxy;
|
||||||
_downloadSeedConfigProvider = downloadSeedConfigProvider;
|
_downloadSeedConfigProvider = downloadSeedConfigProvider;
|
||||||
|
|
|
@ -9,7 +9,6 @@ using NzbDrone.Common.Http;
|
||||||
using NzbDrone.Core.Blocklisting;
|
using NzbDrone.Core.Blocklisting;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
using NzbDrone.Core.Download.Clients.FreeboxDownload.Responses;
|
using NzbDrone.Core.Download.Clients.FreeboxDownload.Responses;
|
||||||
using NzbDrone.Core.Localization;
|
|
||||||
using NzbDrone.Core.MediaFiles.TorrentInfo;
|
using NzbDrone.Core.MediaFiles.TorrentInfo;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
using NzbDrone.Core.RemotePathMappings;
|
using NzbDrone.Core.RemotePathMappings;
|
||||||
|
@ -26,10 +25,9 @@ namespace NzbDrone.Core.Download.Clients.FreeboxDownload
|
||||||
IConfigService configService,
|
IConfigService configService,
|
||||||
IDiskProvider diskProvider,
|
IDiskProvider diskProvider,
|
||||||
IRemotePathMappingService remotePathMappingService,
|
IRemotePathMappingService remotePathMappingService,
|
||||||
ILocalizationService localizationService,
|
|
||||||
IBlocklistService blocklistService,
|
IBlocklistService blocklistService,
|
||||||
Logger logger)
|
Logger logger)
|
||||||
: base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, localizationService, blocklistService, logger)
|
: base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, blocklistService, logger)
|
||||||
{
|
{
|
||||||
_proxy = proxy;
|
_proxy = proxy;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@ using NzbDrone.Common.Http;
|
||||||
using NzbDrone.Core.Blocklisting;
|
using NzbDrone.Core.Blocklisting;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
using NzbDrone.Core.Download.Clients.Hadouken.Models;
|
using NzbDrone.Core.Download.Clients.Hadouken.Models;
|
||||||
using NzbDrone.Core.Localization;
|
|
||||||
using NzbDrone.Core.MediaFiles.TorrentInfo;
|
using NzbDrone.Core.MediaFiles.TorrentInfo;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
using NzbDrone.Core.RemotePathMappings;
|
using NzbDrone.Core.RemotePathMappings;
|
||||||
|
@ -26,10 +25,9 @@ namespace NzbDrone.Core.Download.Clients.Hadouken
|
||||||
IConfigService configService,
|
IConfigService configService,
|
||||||
IDiskProvider diskProvider,
|
IDiskProvider diskProvider,
|
||||||
IRemotePathMappingService remotePathMappingService,
|
IRemotePathMappingService remotePathMappingService,
|
||||||
ILocalizationService localizationService,
|
|
||||||
IBlocklistService blocklistService,
|
IBlocklistService blocklistService,
|
||||||
Logger logger)
|
Logger logger)
|
||||||
: base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, localizationService, blocklistService, logger)
|
: base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, blocklistService, logger)
|
||||||
{
|
{
|
||||||
_proxy = proxy;
|
_proxy = proxy;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@ using NzbDrone.Common.Disk;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Common.Http;
|
using NzbDrone.Common.Http;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
using NzbDrone.Core.Localization;
|
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
using NzbDrone.Core.RemotePathMappings;
|
using NzbDrone.Core.RemotePathMappings;
|
||||||
using NzbDrone.Core.Validation;
|
using NzbDrone.Core.Validation;
|
||||||
|
@ -25,9 +24,8 @@ namespace NzbDrone.Core.Download.Clients.NzbVortex
|
||||||
IDiskProvider diskProvider,
|
IDiskProvider diskProvider,
|
||||||
IRemotePathMappingService remotePathMappingService,
|
IRemotePathMappingService remotePathMappingService,
|
||||||
IValidateNzbs nzbValidationService,
|
IValidateNzbs nzbValidationService,
|
||||||
ILocalizationService localizationService,
|
|
||||||
Logger logger)
|
Logger logger)
|
||||||
: base(httpClient, configService, diskProvider, remotePathMappingService, nzbValidationService, localizationService, logger)
|
: base(httpClient, configService, diskProvider, remotePathMappingService, nzbValidationService, logger)
|
||||||
{
|
{
|
||||||
_proxy = proxy;
|
_proxy = proxy;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@ using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Common.Http;
|
using NzbDrone.Common.Http;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
using NzbDrone.Core.Exceptions;
|
using NzbDrone.Core.Exceptions;
|
||||||
using NzbDrone.Core.Localization;
|
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
using NzbDrone.Core.RemotePathMappings;
|
using NzbDrone.Core.RemotePathMappings;
|
||||||
using NzbDrone.Core.Validation;
|
using NzbDrone.Core.Validation;
|
||||||
|
@ -29,9 +28,8 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
|
||||||
IDiskProvider diskProvider,
|
IDiskProvider diskProvider,
|
||||||
IRemotePathMappingService remotePathMappingService,
|
IRemotePathMappingService remotePathMappingService,
|
||||||
IValidateNzbs nzbValidationService,
|
IValidateNzbs nzbValidationService,
|
||||||
ILocalizationService localizationService,
|
|
||||||
Logger logger)
|
Logger logger)
|
||||||
: base(httpClient, configService, diskProvider, remotePathMappingService, nzbValidationService, localizationService, logger)
|
: base(httpClient, configService, diskProvider, remotePathMappingService, nzbValidationService, logger)
|
||||||
{
|
{
|
||||||
_proxy = proxy;
|
_proxy = proxy;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Common.Http;
|
using NzbDrone.Common.Http;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
using NzbDrone.Core.Indexers;
|
using NzbDrone.Core.Indexers;
|
||||||
using NzbDrone.Core.Localization;
|
|
||||||
using NzbDrone.Core.Organizer;
|
using NzbDrone.Core.Organizer;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
using NzbDrone.Core.RemotePathMappings;
|
using NzbDrone.Core.RemotePathMappings;
|
||||||
|
@ -24,9 +23,8 @@ namespace NzbDrone.Core.Download.Clients.Pneumatic
|
||||||
IConfigService configService,
|
IConfigService configService,
|
||||||
IDiskProvider diskProvider,
|
IDiskProvider diskProvider,
|
||||||
IRemotePathMappingService remotePathMappingService,
|
IRemotePathMappingService remotePathMappingService,
|
||||||
ILocalizationService localizationService,
|
|
||||||
Logger logger)
|
Logger logger)
|
||||||
: base(configService, diskProvider, remotePathMappingService, localizationService, logger)
|
: base(configService, diskProvider, remotePathMappingService, logger)
|
||||||
{
|
{
|
||||||
_httpClient = httpClient;
|
_httpClient = httpClient;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@ using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Common.Http;
|
using NzbDrone.Common.Http;
|
||||||
using NzbDrone.Core.Blocklisting;
|
using NzbDrone.Core.Blocklisting;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
using NzbDrone.Core.Localization;
|
|
||||||
using NzbDrone.Core.MediaFiles.TorrentInfo;
|
using NzbDrone.Core.MediaFiles.TorrentInfo;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
using NzbDrone.Core.RemotePathMappings;
|
using NzbDrone.Core.RemotePathMappings;
|
||||||
|
@ -36,10 +35,9 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
|
||||||
IDiskProvider diskProvider,
|
IDiskProvider diskProvider,
|
||||||
IRemotePathMappingService remotePathMappingService,
|
IRemotePathMappingService remotePathMappingService,
|
||||||
ICacheManager cacheManager,
|
ICacheManager cacheManager,
|
||||||
ILocalizationService localizationService,
|
|
||||||
IBlocklistService blocklistService,
|
IBlocklistService blocklistService,
|
||||||
Logger logger)
|
Logger logger)
|
||||||
: base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, localizationService, blocklistService, logger)
|
: base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, blocklistService, logger)
|
||||||
{
|
{
|
||||||
_proxySelector = proxySelector;
|
_proxySelector = proxySelector;
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,6 @@ using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Common.Http;
|
using NzbDrone.Common.Http;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
using NzbDrone.Core.Exceptions;
|
using NzbDrone.Core.Exceptions;
|
||||||
using NzbDrone.Core.Localization;
|
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
using NzbDrone.Core.RemotePathMappings;
|
using NzbDrone.Core.RemotePathMappings;
|
||||||
using NzbDrone.Core.Validation;
|
using NzbDrone.Core.Validation;
|
||||||
|
@ -27,9 +26,8 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
|
||||||
IDiskProvider diskProvider,
|
IDiskProvider diskProvider,
|
||||||
IRemotePathMappingService remotePathMappingService,
|
IRemotePathMappingService remotePathMappingService,
|
||||||
IValidateNzbs nzbValidationService,
|
IValidateNzbs nzbValidationService,
|
||||||
ILocalizationService localizationService,
|
|
||||||
Logger logger)
|
Logger logger)
|
||||||
: base(httpClient, configService, diskProvider, remotePathMappingService, nzbValidationService, localizationService, logger)
|
: base(httpClient, configService, diskProvider, remotePathMappingService, nzbValidationService, logger)
|
||||||
{
|
{
|
||||||
_proxy = proxy;
|
_proxy = proxy;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@ using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Common.Http;
|
using NzbDrone.Common.Http;
|
||||||
using NzbDrone.Core.Blocklisting;
|
using NzbDrone.Core.Blocklisting;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
using NzbDrone.Core.Localization;
|
|
||||||
using NzbDrone.Core.MediaFiles.TorrentInfo;
|
using NzbDrone.Core.MediaFiles.TorrentInfo;
|
||||||
using NzbDrone.Core.RemotePathMappings;
|
using NzbDrone.Core.RemotePathMappings;
|
||||||
|
|
||||||
|
@ -25,10 +24,9 @@ namespace NzbDrone.Core.Download.Clients.Transmission
|
||||||
IConfigService configService,
|
IConfigService configService,
|
||||||
IDiskProvider diskProvider,
|
IDiskProvider diskProvider,
|
||||||
IRemotePathMappingService remotePathMappingService,
|
IRemotePathMappingService remotePathMappingService,
|
||||||
ILocalizationService localizationService,
|
|
||||||
IBlocklistService blocklistService,
|
IBlocklistService blocklistService,
|
||||||
Logger logger)
|
Logger logger)
|
||||||
: base(proxy, torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, localizationService, blocklistService, logger)
|
: base(proxy, torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, blocklistService, logger)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,6 @@ using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Common.Http;
|
using NzbDrone.Common.Http;
|
||||||
using NzbDrone.Core.Blocklisting;
|
using NzbDrone.Core.Blocklisting;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
using NzbDrone.Core.Localization;
|
|
||||||
using NzbDrone.Core.MediaFiles.TorrentInfo;
|
using NzbDrone.Core.MediaFiles.TorrentInfo;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
using NzbDrone.Core.RemotePathMappings;
|
using NzbDrone.Core.RemotePathMappings;
|
||||||
|
@ -29,10 +28,9 @@ namespace NzbDrone.Core.Download.Clients.Transmission
|
||||||
IConfigService configService,
|
IConfigService configService,
|
||||||
IDiskProvider diskProvider,
|
IDiskProvider diskProvider,
|
||||||
IRemotePathMappingService remotePathMappingService,
|
IRemotePathMappingService remotePathMappingService,
|
||||||
ILocalizationService localizationService,
|
|
||||||
IBlocklistService blocklistService,
|
IBlocklistService blocklistService,
|
||||||
Logger logger)
|
Logger logger)
|
||||||
: base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, localizationService, blocklistService, logger)
|
: base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, blocklistService, logger)
|
||||||
{
|
{
|
||||||
_proxy = proxy;
|
_proxy = proxy;
|
||||||
}
|
}
|
||||||
|
@ -103,11 +101,7 @@ namespace NzbDrone.Core.Download.Clients.Transmission
|
||||||
if (!torrent.ErrorString.IsNullOrWhiteSpace())
|
if (!torrent.ErrorString.IsNullOrWhiteSpace())
|
||||||
{
|
{
|
||||||
item.Status = DownloadItemStatus.Warning;
|
item.Status = DownloadItemStatus.Warning;
|
||||||
item.Message = _localizationService.GetLocalizedString("DownloadClientItemErrorMessage", new Dictionary<string, object>
|
item.Message = torrent.ErrorString;
|
||||||
{
|
|
||||||
{ "clientName", Name },
|
|
||||||
{ "message", torrent.ErrorString }
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
else if (torrent.TotalSize == 0)
|
else if (torrent.TotalSize == 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,7 +5,6 @@ using NzbDrone.Common.Http;
|
||||||
using NzbDrone.Core.Blocklisting;
|
using NzbDrone.Core.Blocklisting;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
using NzbDrone.Core.Download.Clients.Transmission;
|
using NzbDrone.Core.Download.Clients.Transmission;
|
||||||
using NzbDrone.Core.Localization;
|
|
||||||
using NzbDrone.Core.MediaFiles.TorrentInfo;
|
using NzbDrone.Core.MediaFiles.TorrentInfo;
|
||||||
using NzbDrone.Core.RemotePathMappings;
|
using NzbDrone.Core.RemotePathMappings;
|
||||||
|
|
||||||
|
@ -24,10 +23,9 @@ namespace NzbDrone.Core.Download.Clients.Vuze
|
||||||
IConfigService configService,
|
IConfigService configService,
|
||||||
IDiskProvider diskProvider,
|
IDiskProvider diskProvider,
|
||||||
IRemotePathMappingService remotePathMappingService,
|
IRemotePathMappingService remotePathMappingService,
|
||||||
ILocalizationService localizationService,
|
|
||||||
IBlocklistService blocklistService,
|
IBlocklistService blocklistService,
|
||||||
Logger logger)
|
Logger logger)
|
||||||
: base(proxy, torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, localizationService, blocklistService, logger)
|
: base(proxy, torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, blocklistService, logger)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,6 @@ using NzbDrone.Core.Blocklisting;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
using NzbDrone.Core.Download.Clients.rTorrent;
|
using NzbDrone.Core.Download.Clients.rTorrent;
|
||||||
using NzbDrone.Core.Exceptions;
|
using NzbDrone.Core.Exceptions;
|
||||||
using NzbDrone.Core.Localization;
|
|
||||||
using NzbDrone.Core.MediaFiles.TorrentInfo;
|
using NzbDrone.Core.MediaFiles.TorrentInfo;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
using NzbDrone.Core.RemotePathMappings;
|
using NzbDrone.Core.RemotePathMappings;
|
||||||
|
@ -36,10 +35,9 @@ namespace NzbDrone.Core.Download.Clients.RTorrent
|
||||||
IRemotePathMappingService remotePathMappingService,
|
IRemotePathMappingService remotePathMappingService,
|
||||||
IDownloadSeedConfigProvider downloadSeedConfigProvider,
|
IDownloadSeedConfigProvider downloadSeedConfigProvider,
|
||||||
IRTorrentDirectoryValidator rTorrentDirectoryValidator,
|
IRTorrentDirectoryValidator rTorrentDirectoryValidator,
|
||||||
ILocalizationService localizationService,
|
|
||||||
IBlocklistService blocklistService,
|
IBlocklistService blocklistService,
|
||||||
Logger logger)
|
Logger logger)
|
||||||
: base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, localizationService, blocklistService, logger)
|
: base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, blocklistService, logger)
|
||||||
{
|
{
|
||||||
_proxy = proxy;
|
_proxy = proxy;
|
||||||
_rTorrentDirectoryValidator = rTorrentDirectoryValidator;
|
_rTorrentDirectoryValidator = rTorrentDirectoryValidator;
|
||||||
|
|
|
@ -10,7 +10,6 @@ using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Common.Http;
|
using NzbDrone.Common.Http;
|
||||||
using NzbDrone.Core.Blocklisting;
|
using NzbDrone.Core.Blocklisting;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
using NzbDrone.Core.Localization;
|
|
||||||
using NzbDrone.Core.MediaFiles.TorrentInfo;
|
using NzbDrone.Core.MediaFiles.TorrentInfo;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
using NzbDrone.Core.RemotePathMappings;
|
using NzbDrone.Core.RemotePathMappings;
|
||||||
|
@ -30,10 +29,9 @@ namespace NzbDrone.Core.Download.Clients.UTorrent
|
||||||
IConfigService configService,
|
IConfigService configService,
|
||||||
IDiskProvider diskProvider,
|
IDiskProvider diskProvider,
|
||||||
IRemotePathMappingService remotePathMappingService,
|
IRemotePathMappingService remotePathMappingService,
|
||||||
ILocalizationService localizationService,
|
|
||||||
IBlocklistService blocklistService,
|
IBlocklistService blocklistService,
|
||||||
Logger logger)
|
Logger logger)
|
||||||
: base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, localizationService, blocklistService, logger)
|
: base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, blocklistService, logger)
|
||||||
{
|
{
|
||||||
_proxy = proxy;
|
_proxy = proxy;
|
||||||
|
|
||||||
|
|
|
@ -63,8 +63,8 @@ namespace NzbDrone.Core.Download
|
||||||
|
|
||||||
SetImportItem(trackedDownload);
|
SetImportItem(trackedDownload);
|
||||||
|
|
||||||
// Only process tracked downloads that are still downloading or have been blocked for importing due to an issue with matching
|
// Only process tracked downloads that are still downloading
|
||||||
if (trackedDownload.State != TrackedDownloadState.Downloading && trackedDownload.State != TrackedDownloadState.ImportBlocked)
|
if (trackedDownload.State != TrackedDownloadState.Downloading)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -93,9 +93,7 @@ namespace NzbDrone.Core.Download
|
||||||
|
|
||||||
if (artist == null)
|
if (artist == null)
|
||||||
{
|
{
|
||||||
trackedDownload.Warn("Artist name mismatch, automatic import is not possible. Check the download troubleshooting entry on the wiki for common causes.");
|
trackedDownload.Warn("Artist name mismatch, automatic import is not possible.");
|
||||||
SetStateToImportBlocked(trackedDownload);
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -115,8 +113,6 @@ namespace NzbDrone.Core.Download
|
||||||
if (trackedDownload.RemoteAlbum == null)
|
if (trackedDownload.RemoteAlbum == null)
|
||||||
{
|
{
|
||||||
trackedDownload.Warn("Unable to parse download, automatic import is not possible.");
|
trackedDownload.Warn("Unable to parse download, automatic import is not possible.");
|
||||||
SetStateToImportBlocked(trackedDownload);
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,11 +149,14 @@ namespace NzbDrone.Core.Download
|
||||||
|
|
||||||
var statusMessages = new List<TrackedDownloadStatusMessage>
|
var statusMessages = new List<TrackedDownloadStatusMessage>
|
||||||
{
|
{
|
||||||
new TrackedDownloadStatusMessage("One or more tracks expected in this release were not imported or missing from the release", new List<string>())
|
new TrackedDownloadStatusMessage("One or more albums expected in this release were not imported or missing", new List<string>())
|
||||||
};
|
};
|
||||||
|
|
||||||
if (importResults.Any(c => c.Result != ImportResultType.Imported))
|
if (importResults.Any(c => c.Result != ImportResultType.Imported))
|
||||||
{
|
{
|
||||||
|
// Mark as failed to prevent further attempts at processing
|
||||||
|
trackedDownload.State = TrackedDownloadState.ImportFailed;
|
||||||
|
|
||||||
statusMessages.AddRange(
|
statusMessages.AddRange(
|
||||||
importResults
|
importResults
|
||||||
.Where(v => v.Result != ImportResultType.Imported && v.ImportDecision.Item != null)
|
.Where(v => v.Result != ImportResultType.Imported && v.ImportDecision.Item != null)
|
||||||
|
@ -166,34 +165,22 @@ namespace NzbDrone.Core.Download
|
||||||
new TrackedDownloadStatusMessage(Path.GetFileName(v.ImportDecision.Item.Path),
|
new TrackedDownloadStatusMessage(Path.GetFileName(v.ImportDecision.Item.Path),
|
||||||
v.Errors)));
|
v.Errors)));
|
||||||
|
|
||||||
// Mark as failed to prevent further attempts at processing
|
|
||||||
trackedDownload.State = TrackedDownloadState.ImportFailed;
|
|
||||||
|
|
||||||
if (statusMessages.Any())
|
if (statusMessages.Any())
|
||||||
{
|
{
|
||||||
trackedDownload.Warn(statusMessages.ToArray());
|
trackedDownload.Warn(statusMessages.ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Publish event to notify album was imported incomplete
|
// Publish event to notify Album was imported incompelte
|
||||||
_eventAggregator.PublishEvent(new AlbumImportIncompleteEvent(trackedDownload));
|
_eventAggregator.PublishEvent(new AlbumImportIncompleteEvent(trackedDownload));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (statusMessages.Any())
|
|
||||||
{
|
|
||||||
trackedDownload.Warn(statusMessages.ToArray());
|
|
||||||
SetStateToImportBlocked(trackedDownload);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool VerifyImport(TrackedDownload trackedDownload, List<ImportResult> importResults)
|
public bool VerifyImport(TrackedDownload trackedDownload, List<ImportResult> importResults)
|
||||||
{
|
{
|
||||||
var allTracksImported =
|
var allTracksImported = importResults.All(c => c.Result == ImportResultType.Imported) ||
|
||||||
(importResults.Any() && importResults.All(c => c.Result == ImportResultType.Imported)) ||
|
importResults.Count(c => c.Result == ImportResultType.Imported) >=
|
||||||
importResults.Where(c => c.Result == ImportResultType.Imported)
|
Math.Max(1, trackedDownload.RemoteAlbum.Albums.Sum(x => x.AlbumReleases.Value.Where(y => y.Monitored).Sum(z => z.TrackCount)));
|
||||||
.SelectMany(c => c.ImportDecision.Item.Tracks)
|
|
||||||
.Count() >= Math.Max(1, trackedDownload.RemoteAlbum.Albums.Sum(x => x.AlbumReleases.Value.Where(y => y.Monitored).Sum(z => z.TrackCount)));
|
|
||||||
|
|
||||||
if (allTracksImported)
|
if (allTracksImported)
|
||||||
{
|
{
|
||||||
|
@ -204,10 +191,6 @@ namespace NzbDrone.Core.Download
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var historyItems = _historyService.FindByDownloadId(trackedDownload.DownloadItem.DownloadId)
|
|
||||||
.OrderByDescending(h => h.Date)
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
// Double check if all episodes were imported by checking the history if at least one
|
// Double check if all episodes were imported by checking the history if at least one
|
||||||
// file was imported. This will allow the decision engine to reject already imported
|
// file was imported. This will allow the decision engine to reject already imported
|
||||||
// episode files and still mark the download complete when all files are imported.
|
// episode files and still mark the download complete when all files are imported.
|
||||||
|
@ -216,14 +199,19 @@ namespace NzbDrone.Core.Download
|
||||||
// and an episode is removed, but later comes back with a different ID then Sonarr will treat it as incomplete.
|
// and an episode is removed, but later comes back with a different ID then Sonarr will treat it as incomplete.
|
||||||
// Since imports should be relatively fast and these types of data changes are infrequent this should be quite
|
// Since imports should be relatively fast and these types of data changes are infrequent this should be quite
|
||||||
// safe, but commenting for future benefit.
|
// safe, but commenting for future benefit.
|
||||||
var atLeastOneTrackImported = importResults.Any(c => c.Result == ImportResultType.Imported);
|
var atLeastOneEpisodeImported = importResults.Any(c => c.Result == ImportResultType.Imported);
|
||||||
|
|
||||||
|
var historyItems = _historyService.FindByDownloadId(trackedDownload.DownloadItem.DownloadId)
|
||||||
|
.OrderByDescending(h => h.Date)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
var allTracksImportedInHistory = _trackedDownloadAlreadyImported.IsImported(trackedDownload, historyItems);
|
var allTracksImportedInHistory = _trackedDownloadAlreadyImported.IsImported(trackedDownload, historyItems);
|
||||||
|
|
||||||
if (allTracksImportedInHistory)
|
if (allTracksImportedInHistory)
|
||||||
{
|
{
|
||||||
// Log different error messages depending on the circumstances, but treat both as fully imported, because that's the reality.
|
// Log different error messages depending on the circumstances, but treat both as fully imported, because that's the reality.
|
||||||
// The second message shouldn't be logged in most cases, but continued reporting would indicate an ongoing issue.
|
// The second message shouldn't be logged in most cases, but continued reporting would indicate an ongoing issue.
|
||||||
if (atLeastOneTrackImported)
|
if (atLeastOneEpisodeImported)
|
||||||
{
|
{
|
||||||
_logger.Debug("All albums were imported in history for {0}", trackedDownload.DownloadItem.Title);
|
_logger.Debug("All albums were imported in history for {0}", trackedDownload.DownloadItem.Title);
|
||||||
}
|
}
|
||||||
|
@ -245,15 +233,10 @@ namespace NzbDrone.Core.Download
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.Debug("Not all albums have been imported for the release '{0}'", trackedDownload.DownloadItem.Title);
|
_logger.Debug("Not all albums have been imported for {0}", trackedDownload.DownloadItem.Title);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetStateToImportBlocked(TrackedDownload trackedDownload)
|
|
||||||
{
|
|
||||||
trackedDownload.State = TrackedDownloadState.ImportBlocked;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetImportItem(TrackedDownload trackedDownload)
|
private void SetImportItem(TrackedDownload trackedDownload)
|
||||||
{
|
{
|
||||||
trackedDownload.ImportItem = _provideImportItemService.ProvideImportItem(trackedDownload.DownloadItem, trackedDownload.ImportItem);
|
trackedDownload.ImportItem = _provideImportItemService.ProvideImportItem(trackedDownload.DownloadItem, trackedDownload.ImportItem);
|
||||||
|
|
|
@ -8,7 +8,6 @@ using NzbDrone.Common.Disk;
|
||||||
using NzbDrone.Common.Http;
|
using NzbDrone.Common.Http;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
using NzbDrone.Core.Indexers;
|
using NzbDrone.Core.Indexers;
|
||||||
using NzbDrone.Core.Localization;
|
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
using NzbDrone.Core.RemotePathMappings;
|
using NzbDrone.Core.RemotePathMappings;
|
||||||
using NzbDrone.Core.ThingiProvider;
|
using NzbDrone.Core.ThingiProvider;
|
||||||
|
@ -24,7 +23,6 @@ namespace NzbDrone.Core.Download
|
||||||
protected readonly IConfigService _configService;
|
protected readonly IConfigService _configService;
|
||||||
protected readonly IDiskProvider _diskProvider;
|
protected readonly IDiskProvider _diskProvider;
|
||||||
protected readonly IRemotePathMappingService _remotePathMappingService;
|
protected readonly IRemotePathMappingService _remotePathMappingService;
|
||||||
protected readonly ILocalizationService _localizationService;
|
|
||||||
protected readonly Logger _logger;
|
protected readonly Logger _logger;
|
||||||
|
|
||||||
protected ResiliencePipeline<HttpResponse> RetryStrategy => new ResiliencePipelineBuilder<HttpResponse>()
|
protected ResiliencePipeline<HttpResponse> RetryStrategy => new ResiliencePipelineBuilder<HttpResponse>()
|
||||||
|
@ -79,13 +77,11 @@ namespace NzbDrone.Core.Download
|
||||||
protected DownloadClientBase(IConfigService configService,
|
protected DownloadClientBase(IConfigService configService,
|
||||||
IDiskProvider diskProvider,
|
IDiskProvider diskProvider,
|
||||||
IRemotePathMappingService remotePathMappingService,
|
IRemotePathMappingService remotePathMappingService,
|
||||||
ILocalizationService localizationService,
|
|
||||||
Logger logger)
|
Logger logger)
|
||||||
{
|
{
|
||||||
_configService = configService;
|
_configService = configService;
|
||||||
_diskProvider = diskProvider;
|
_diskProvider = diskProvider;
|
||||||
_remotePathMappingService = remotePathMappingService;
|
_remotePathMappingService = remotePathMappingService;
|
||||||
_localizationService = localizationService;
|
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ namespace NzbDrone.Core.Download
|
||||||
public interface IFailedDownloadService
|
public interface IFailedDownloadService
|
||||||
{
|
{
|
||||||
void MarkAsFailed(int historyId, bool skipRedownload = false);
|
void MarkAsFailed(int historyId, bool skipRedownload = false);
|
||||||
void MarkAsFailed(TrackedDownload trackedDownload, bool skipRedownload = false);
|
void MarkAsFailed(string downloadId, bool skipRedownload = false);
|
||||||
void Check(TrackedDownload trackedDownload);
|
void Check(TrackedDownload trackedDownload);
|
||||||
void ProcessFailed(TrackedDownload trackedDownload);
|
void ProcessFailed(TrackedDownload trackedDownload);
|
||||||
}
|
}
|
||||||
|
@ -20,12 +20,15 @@ namespace NzbDrone.Core.Download
|
||||||
public class FailedDownloadService : IFailedDownloadService
|
public class FailedDownloadService : IFailedDownloadService
|
||||||
{
|
{
|
||||||
private readonly IHistoryService _historyService;
|
private readonly IHistoryService _historyService;
|
||||||
|
private readonly ITrackedDownloadService _trackedDownloadService;
|
||||||
private readonly IEventAggregator _eventAggregator;
|
private readonly IEventAggregator _eventAggregator;
|
||||||
|
|
||||||
public FailedDownloadService(IHistoryService historyService,
|
public FailedDownloadService(IHistoryService historyService,
|
||||||
|
ITrackedDownloadService trackedDownloadService,
|
||||||
IEventAggregator eventAggregator)
|
IEventAggregator eventAggregator)
|
||||||
{
|
{
|
||||||
_historyService = historyService;
|
_historyService = historyService;
|
||||||
|
_trackedDownloadService = trackedDownloadService;
|
||||||
_eventAggregator = eventAggregator;
|
_eventAggregator = eventAggregator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,10 +37,9 @@ namespace NzbDrone.Core.Download
|
||||||
var history = _historyService.Get(historyId);
|
var history = _historyService.Get(historyId);
|
||||||
|
|
||||||
var downloadId = history.DownloadId;
|
var downloadId = history.DownloadId;
|
||||||
|
|
||||||
if (downloadId.IsNullOrWhiteSpace())
|
if (downloadId.IsNullOrWhiteSpace())
|
||||||
{
|
{
|
||||||
PublishDownloadFailedEvent(history, new List<int> { history.AlbumId }, "Manually marked as failed", skipRedownload: skipRedownload);
|
PublishDownloadFailedEvent(new List<EntityHistory> { history }, "Manually marked as failed", skipRedownload: skipRedownload);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -51,26 +53,28 @@ namespace NzbDrone.Core.Download
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add any other history items for the download ID then filter out any duplicate history items.
|
// Add any other history items for the download ID then filter out any duplicate history items.
|
||||||
grabbedHistory.AddRange(GetGrabbedHistory(downloadId));
|
grabbedHistory.AddRange(_historyService.Find(downloadId, EntityHistoryEventType.Grabbed));
|
||||||
grabbedHistory = grabbedHistory.DistinctBy(h => h.Id).ToList();
|
grabbedHistory = grabbedHistory.DistinctBy(h => h.Id).ToList();
|
||||||
|
|
||||||
PublishDownloadFailedEvent(history, GetAlbumIds(grabbedHistory), "Manually marked as failed");
|
PublishDownloadFailedEvent(grabbedHistory, "Manually marked as failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void MarkAsFailed(TrackedDownload trackedDownload, bool skipRedownload = false)
|
public void MarkAsFailed(string downloadId, bool skipRedownload = false)
|
||||||
{
|
{
|
||||||
var history = GetGrabbedHistory(trackedDownload.DownloadItem.DownloadId);
|
var history = _historyService.Find(downloadId, EntityHistoryEventType.Grabbed);
|
||||||
|
|
||||||
if (history.Any())
|
if (history.Any())
|
||||||
{
|
{
|
||||||
PublishDownloadFailedEvent(history.First(), GetAlbumIds(history), "Manually marked as failed", trackedDownload, skipRedownload: skipRedownload);
|
var trackedDownload = _trackedDownloadService.Find(downloadId);
|
||||||
|
|
||||||
|
PublishDownloadFailedEvent(history, "Manually marked as failed", trackedDownload, skipRedownload: skipRedownload);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Check(TrackedDownload trackedDownload)
|
public void Check(TrackedDownload trackedDownload)
|
||||||
{
|
{
|
||||||
// Only process tracked downloads that are still downloading or import is blocked (if they fail after attempting to be processed)
|
// Only process tracked downloads that are still downloading
|
||||||
if (trackedDownload.State != TrackedDownloadState.Downloading && trackedDownload.State != TrackedDownloadState.ImportBlocked)
|
if (trackedDownload.State != TrackedDownloadState.Downloading)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -78,7 +82,9 @@ namespace NzbDrone.Core.Download
|
||||||
if (trackedDownload.DownloadItem.IsEncrypted ||
|
if (trackedDownload.DownloadItem.IsEncrypted ||
|
||||||
trackedDownload.DownloadItem.Status == DownloadItemStatus.Failed)
|
trackedDownload.DownloadItem.Status == DownloadItemStatus.Failed)
|
||||||
{
|
{
|
||||||
var grabbedItems = GetGrabbedHistory(trackedDownload.DownloadItem.DownloadId);
|
var grabbedItems = _historyService
|
||||||
|
.Find(trackedDownload.DownloadItem.DownloadId, EntityHistoryEventType.Grabbed)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
if (grabbedItems.Empty())
|
if (grabbedItems.Empty())
|
||||||
{
|
{
|
||||||
|
@ -97,7 +103,9 @@ namespace NzbDrone.Core.Download
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var grabbedItems = GetGrabbedHistory(trackedDownload.DownloadItem.DownloadId);
|
var grabbedItems = _historyService
|
||||||
|
.Find(trackedDownload.DownloadItem.DownloadId, EntityHistoryEventType.Grabbed)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
if (grabbedItems.Empty())
|
if (grabbedItems.Empty())
|
||||||
{
|
{
|
||||||
|
@ -116,17 +124,18 @@ namespace NzbDrone.Core.Download
|
||||||
}
|
}
|
||||||
|
|
||||||
trackedDownload.State = TrackedDownloadState.DownloadFailed;
|
trackedDownload.State = TrackedDownloadState.DownloadFailed;
|
||||||
PublishDownloadFailedEvent(grabbedItems.First(), GetAlbumIds(grabbedItems), failure, trackedDownload);
|
PublishDownloadFailedEvent(grabbedItems, failure, trackedDownload);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PublishDownloadFailedEvent(EntityHistory historyItem, List<int> albumIds, string message, TrackedDownload trackedDownload = null, bool skipRedownload = false)
|
private void PublishDownloadFailedEvent(List<EntityHistory> historyItems, string message, TrackedDownload trackedDownload = null, bool skipRedownload = false)
|
||||||
{
|
{
|
||||||
|
var historyItem = historyItems.Last();
|
||||||
Enum.TryParse(historyItem.Data.GetValueOrDefault(EntityHistory.RELEASE_SOURCE, ReleaseSourceType.Unknown.ToString()), out ReleaseSourceType releaseSource);
|
Enum.TryParse(historyItem.Data.GetValueOrDefault(EntityHistory.RELEASE_SOURCE, ReleaseSourceType.Unknown.ToString()), out ReleaseSourceType releaseSource);
|
||||||
|
|
||||||
var downloadFailedEvent = new DownloadFailedEvent
|
var downloadFailedEvent = new DownloadFailedEvent
|
||||||
{
|
{
|
||||||
ArtistId = historyItem.ArtistId,
|
ArtistId = historyItem.ArtistId,
|
||||||
AlbumIds = albumIds,
|
AlbumIds = historyItems.Select(h => h.AlbumId).Distinct().ToList(),
|
||||||
Quality = historyItem.Quality,
|
Quality = historyItem.Quality,
|
||||||
SourceTitle = historyItem.SourceTitle,
|
SourceTitle = historyItem.SourceTitle,
|
||||||
DownloadClient = historyItem.Data.GetValueOrDefault(EntityHistory.DOWNLOAD_CLIENT),
|
DownloadClient = historyItem.Data.GetValueOrDefault(EntityHistory.DOWNLOAD_CLIENT),
|
||||||
|
@ -135,23 +144,10 @@ namespace NzbDrone.Core.Download
|
||||||
Data = historyItem.Data,
|
Data = historyItem.Data,
|
||||||
TrackedDownload = trackedDownload,
|
TrackedDownload = trackedDownload,
|
||||||
SkipRedownload = skipRedownload,
|
SkipRedownload = skipRedownload,
|
||||||
ReleaseSource = releaseSource,
|
ReleaseSource = releaseSource
|
||||||
};
|
};
|
||||||
|
|
||||||
_eventAggregator.PublishEvent(downloadFailedEvent);
|
_eventAggregator.PublishEvent(downloadFailedEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<int> GetAlbumIds(List<EntityHistory> historyItems)
|
|
||||||
{
|
|
||||||
return historyItems.Select(h => h.AlbumId).Distinct().ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<EntityHistory> GetGrabbedHistory(string downloadId)
|
|
||||||
{
|
|
||||||
// Sort by date so items are always in the same order
|
|
||||||
return _historyService.Find(downloadId, EntityHistoryEventType.Grabbed)
|
|
||||||
.OrderByDescending(h => h.Date)
|
|
||||||
.ToList();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
using System;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
|
@ -15,13 +14,10 @@ namespace NzbDrone.Core.Download
|
||||||
public class NzbValidationService : IValidateNzbs
|
public class NzbValidationService : IValidateNzbs
|
||||||
{
|
{
|
||||||
public void Validate(string filename, byte[] fileContent)
|
public void Validate(string filename, byte[] fileContent)
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
var reader = new StreamReader(new MemoryStream(fileContent));
|
var reader = new StreamReader(new MemoryStream(fileContent));
|
||||||
|
|
||||||
using (var xmlTextReader = XmlReader.Create(reader,
|
using (var xmlTextReader = XmlReader.Create(reader, new XmlReaderSettings { DtdProcessing = DtdProcessing.Ignore, IgnoreComments = true }))
|
||||||
new XmlReaderSettings { DtdProcessing = DtdProcessing.Ignore, IgnoreComments = true }))
|
|
||||||
{
|
{
|
||||||
var xDoc = XDocument.Load(xmlTextReader);
|
var xDoc = XDocument.Load(xmlTextReader);
|
||||||
var nzb = xDoc.Root;
|
var nzb = xDoc.Root;
|
||||||
|
@ -41,8 +37,7 @@ namespace NzbDrone.Core.Download
|
||||||
|
|
||||||
if (!nzb.Name.LocalName.Equals("nzb"))
|
if (!nzb.Name.LocalName.Equals("nzb"))
|
||||||
{
|
{
|
||||||
throw new InvalidNzbException(
|
throw new InvalidNzbException("Invalid NZB: Unexpected root element. Expected 'nzb' found '{0}' [{1}]", nzb.Name.LocalName, filename);
|
||||||
"Invalid NZB: Unexpected root element. Expected 'nzb' found '{0}' [{1}]", nzb.Name.LocalName, filename);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var ns = nzb.Name.Namespace;
|
var ns = nzb.Name.Namespace;
|
||||||
|
@ -54,15 +49,5 @@ namespace NzbDrone.Core.Download
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (InvalidNzbException)
|
|
||||||
{
|
|
||||||
// Throw the original exception
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
throw new InvalidNzbException("Invalid NZB: Unable to parse [{0}]", ex, filename);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@ using NzbDrone.Core.Blocklisting;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
using NzbDrone.Core.Exceptions;
|
using NzbDrone.Core.Exceptions;
|
||||||
using NzbDrone.Core.Indexers;
|
using NzbDrone.Core.Indexers;
|
||||||
using NzbDrone.Core.Localization;
|
|
||||||
using NzbDrone.Core.MediaFiles.TorrentInfo;
|
using NzbDrone.Core.MediaFiles.TorrentInfo;
|
||||||
using NzbDrone.Core.Organizer;
|
using NzbDrone.Core.Organizer;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
@ -31,10 +30,9 @@ namespace NzbDrone.Core.Download
|
||||||
IConfigService configService,
|
IConfigService configService,
|
||||||
IDiskProvider diskProvider,
|
IDiskProvider diskProvider,
|
||||||
IRemotePathMappingService remotePathMappingService,
|
IRemotePathMappingService remotePathMappingService,
|
||||||
ILocalizationService localizationService,
|
|
||||||
IBlocklistService blocklistService,
|
IBlocklistService blocklistService,
|
||||||
Logger logger)
|
Logger logger)
|
||||||
: base(configService, diskProvider, remotePathMappingService, localizationService, logger)
|
: base(configService, diskProvider, remotePathMappingService, logger)
|
||||||
{
|
{
|
||||||
_httpClient = httpClient;
|
_httpClient = httpClient;
|
||||||
_blocklistService = blocklistService;
|
_blocklistService = blocklistService;
|
||||||
|
@ -172,7 +170,7 @@ namespace NzbDrone.Core.Download
|
||||||
}
|
}
|
||||||
catch (HttpException ex)
|
catch (HttpException ex)
|
||||||
{
|
{
|
||||||
if (ex.Response.StatusCode is HttpStatusCode.NotFound or HttpStatusCode.Gone)
|
if (ex.Response.StatusCode == HttpStatusCode.NotFound)
|
||||||
{
|
{
|
||||||
_logger.Error(ex, "Downloading torrent file for album '{0}' failed since it no longer exists ({1})", remoteAlbum.Release.Title, torrentUrl);
|
_logger.Error(ex, "Downloading torrent file for album '{0}' failed since it no longer exists ({1})", remoteAlbum.Release.Title, torrentUrl);
|
||||||
throw new ReleaseUnavailableException(remoteAlbum.Release, "Downloading torrent failed", ex);
|
throw new ReleaseUnavailableException(remoteAlbum.Release, "Downloading torrent failed", ex);
|
||||||
|
|
|
@ -115,7 +115,7 @@ namespace NzbDrone.Core.Download.TrackedDownloads
|
||||||
{
|
{
|
||||||
var trackedDownload = _trackedDownloadService.TrackDownload((DownloadClientDefinition)downloadClient.Definition, downloadItem);
|
var trackedDownload = _trackedDownloadService.TrackDownload((DownloadClientDefinition)downloadClient.Definition, downloadItem);
|
||||||
|
|
||||||
if (trackedDownload is { State: TrackedDownloadState.Downloading or TrackedDownloadState.ImportBlocked })
|
if (trackedDownload != null && trackedDownload.State == TrackedDownloadState.Downloading)
|
||||||
{
|
{
|
||||||
_failedDownloadService.Check(trackedDownload);
|
_failedDownloadService.Check(trackedDownload);
|
||||||
_completedDownloadService.Check(trackedDownload);
|
_completedDownloadService.Check(trackedDownload);
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue