Compare commits

...

26 commits

Author SHA1 Message Date
Bogdan
91f06801ca
Bump version to 2.13.1 2025-06-15 09:22:00 +03:00
Bogdan
dc61618711 Save Publish Dates as UTC for grabbed albums 2025-06-12 11:35:35 +03:00
Bogdan
fd00a5627c Fixed: Improve error message for queue items from Transmission
(cherry picked from commit 0ae07898ba6f85299e739d38ab1dd900c39e91d2)
2025-06-12 11:32:16 +03:00
Bogdan
66ea1b1dfb Fixed: Avoid requests without categories for FileList
(cherry picked from commit 4728fa29ef578a7ff33cf16a4e6b46689c4be1b4)
2025-06-12 11:10:06 +03:00
Bogdan
72fa05cf41 Fixed: Sending notifications for Custom Script with unparsed artist
(cherry picked from commit 76b1130b6811454fa6b1e80e0b2012c24c4ae8fa)
2025-06-12 11:06:46 +03:00
Bogdan
c51b5c6fba Log when expected track file is missing from disk on upgrade
(cherry picked from commit 1047e71b7d78812f2fa04b150fc6774efc1a6af8)
2025-06-12 11:05:21 +03:00
Bogdan
efebab9ba2 Update default log level message
(cherry picked from commit 817d13e85c89d1f10abab09a8f63272a46f5d0b6)
2025-06-12 11:03:29 +03:00
Mark McDowall
47c32c9963 Improve messaging when NZB contains invalid XML
(cherry picked from commit 728df146ada115a367bf1ce808482a4625e6098d)
2025-06-12 10:56:57 +03:00
Stevie Robinson
9f229bb684 Ensure Custom Format Maximum Size won't overflow
(cherry picked from commit a50d2562649bbe77d0feb9fbfc594d56952e0a5e)
2025-06-12 10:56:14 +03:00
Mark McDowall
f9b2e57696 Increase maximum backup restoration size to 5GB
(cherry picked from commit e38deb34221ebf131adcce9551774898f46b1f7f)
2025-06-12 10:55:49 +03:00
carrossos
4b48edab0a Treat HTTP 410 response for failed download similarly to HTTP 404
(cherry picked from commit 818ae02a7a8f0a8ea0a44e0015e2667d96453332)
2025-06-12 10:55:02 +03:00
Stevie Robinson
e087574de7 New: Ignore volumes containing .timemachine from Disk Space
(cherry picked from commit a853c537db0a6bd499a2277987dc170d2a1f5645)
2025-06-12 10:54:16 +03:00
Bogdan
8877cf99f1 Use the thrown exception in http timeout handling
(cherry picked from commit 14e324ee30694ae017a39fd6f66392dc2d104617)
2025-06-12 10:53:59 +03:00
Stevie Robinson
a56e5b3f9a New: Don't allow remote path to start with space
(cherry picked from commit 5ba3ff598770fdf9e5a53d490c8bcbdd6a59c4cc)

Fixed validation for Remote Path Mapping

(cherry picked from commit bf34b4309402ce529a8c04de70f44b28948761f4)
2025-06-12 10:52:01 +03:00
Stevie Robinson
5bb1949ea2 Fixed: Include network drive types in Disk Space
(cherry picked from commit 9ffcd141a515e99604881a4ef383dadafef31eeb)
2025-06-12 10:47:17 +03:00
Bogdan
979042948d Fixed: Quality sliders on some browsers 2025-06-12 10:47:00 +03:00
Mark McDowall
ebe59b18d9 Sync react-slider props for Quality sliders with upstream
(cherry picked from commit 9dab2ba6e4316879e4db8db47363476a5c4f13b2)
2025-06-12 10:46:53 +03:00
Bogdan
086a451dff Follow redirects for usenet grabs on non-prod builds
(cherry picked from commit 1cdca8ef3e47e19c9264db6b322161b615b20294)
2025-06-12 10:39:37 +03:00
Mark McDowall
1bcb82eed0 Prevent should refresh artists and albums from failing
(cherry picked from commit 3eed84c67938fed308e562e69cf7bcd727063803)
2025-06-12 10:38:23 +03:00
Mark McDowall
ae9b4cec75 New: Update wording when removing a root folder
(cherry picked from commit 51c17fd3122f7b96a4155593d465ba32870d0c91)
2025-06-12 10:35:09 +03:00
Mark McDowall
ed777de015 Fixed: Escape backticks in discord notifications
(cherry picked from commit 70c74fc1769f2094a14faaa103c49d744534be9f)
2025-06-12 10:30:03 +03:00
Bogdan
96f956a5d6 Fix fullscreen automation screenshots 2025-06-10 13:13:38 +03:00
Bogdan
68a8f40746 Fixed translations for the updates page 2025-06-09 23:33:06 +03:00
Bogdan
c518cf63e7
Bump version to 2.13.0 2025-06-09 20:28:15 +03:00
Bogdan
da55b8578a Bump IPAddressRange and SixLabors.ImageSharp 2025-06-09 15:21:12 +03:00
Bogdan
234c29ef49
Bump version to 2.12.4 2025-06-08 10:31:50 +03:00
50 changed files with 271 additions and 130 deletions

View file

@ -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.12.3' majorVersion: '2.13.1'
minorVersion: $[counter('minorVersion', 1076)] minorVersion: $[counter('minorVersion', 1076)]
lidarrVersion: '$(majorVersion).$(minorVersion)' lidarrVersion: '$(majorVersion).$(minorVersion)'
buildName: '$(Build.SourceBranchName).$(lidarrVersion)' buildName: '$(Build.SourceBranchName).$(lidarrVersion)'

View file

@ -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('DeleteRootFolder')} title={translate('RemoveRootFolder')}
message={translate('DeleteRootFolderMessageText', { name })} message={translate('RemoveRootFolderArtistsMessageText', { name })}
confirmLabel={translate('Delete')} confirmLabel={translate('Remove')}
onConfirm={this.onConfirmDeleteRootFolder} onConfirm={this.onConfirmDeleteRootFolder}
onCancel={this.onDeleteRootFolderModalClose} onCancel={this.onDeleteRootFolderModalClose}
/> />

View file

@ -24,7 +24,7 @@
height: 20px; height: 20px;
} }
.bar { .track {
top: 9px; top: 9px;
margin: 0 5px; margin: 0 5px;
height: 3px; height: 3px;
@ -36,7 +36,7 @@
} }
} }
.handle { .thumb {
top: 1px; top: 1px;
z-index: 0 !important; z-index: 0 !important;
width: 18px; width: 18px;

View file

@ -1,8 +1,6 @@
// 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;
@ -10,7 +8,9 @@ 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;

View file

@ -55,6 +55,27 @@ 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
@ -174,6 +195,7 @@ 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}
@ -182,9 +204,9 @@ class QualityDefinition extends Component {
withTracks={true} withTracks={true}
allowCross={false} allowCross={false}
snapDragDisabled={true} snapDragDisabled={true}
className={styles.slider} pearling={true}
trackClassName={styles.bar} renderThumb={this.thumbRenderer}
thumbClassName={styles.handle} renderTrack={this.trackRenderer}
onChange={this.onSliderChange} onChange={this.onSliderChange}
onAfterChange={this.onAfterSliderChange} onAfterChange={this.onAfterSliderChange}
/> />

View file

@ -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,15 +77,16 @@ class LogFiles extends Component {
<PageContentBody> <PageContentBody>
<Alert> <Alert>
<div> <div>
Log files are located in: {location} {translate('LogFilesLocation', {
location
})}
</div> </div>
{ {currentLogView === 'Log Files' ? (
currentLogView === 'Log Files' &&
<div> <div>
The log level defaults to 'Info' and can be changed in <Link to="/settings/general">General Settings</Link> <InlineMarkdown data={translate('TheLogLevelDefault')} />
</div> </div>
} ) : null}
</Alert> </Alert>
{ {

View file

@ -270,7 +270,7 @@ function Updates() {
{generalSettingsError ? ( {generalSettingsError ? (
<Alert kind={kinds.DANGER}> <Alert kind={kinds.DANGER}>
{translate('FailedToUpdateSettings')} {translate('FailedToFetchSettings')}
</Alert> </Alert>
) : null} ) : null}

View file

@ -4,6 +4,7 @@ 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;
@ -27,6 +28,14 @@ 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()

View file

@ -92,7 +92,7 @@ namespace Lidarr.Api.V1.System.Backup
} }
[HttpPost("restore/upload")] [HttpPost("restore/upload")]
[RequestFormLimits(MultipartBodyLengthLimit = 1000000000)] [RequestFormLimits(MultipartBodyLengthLimit = 5000000000)]
public object UploadAndRestore() public object UploadAndRestore()
{ {
var files = Request.Form.Files; var files = Request.Form.Files;

View file

@ -40,15 +40,16 @@ namespace NzbDrone.Automation.Test
var service = ChromeDriverService.CreateDefaultService(); var service = ChromeDriverService.CreateDefaultService();
// Timeout as windows automation tests seem to take alot longer to get going // Timeout as windows automation tests seem to take alot longer to get going
driver = new ChromeDriver(service, options, new TimeSpan(0, 3, 0)); driver = new ChromeDriver(service, options, TimeSpan.FromMinutes(3));
driver.Manage().Window.Size = new System.Drawing.Size(1920, 1080); driver.Manage().Window.Size = new System.Drawing.Size(1920, 1080);
driver.Manage().Window.FullScreen();
_runner = new NzbDroneRunner(LogManager.GetCurrentClassLogger(), null); _runner = new NzbDroneRunner(LogManager.GetCurrentClassLogger(), null);
_runner.KillAll(); _runner.KillAll();
_runner.Start(true); _runner.Start(true);
driver.Url = "http://localhost:8686"; driver.Navigate().GoToUrl("http://localhost:8686");
var page = new PageBase(driver); var page = new PageBase(driver);
page.WaitForNoSpinner(); page.WaitForNoSpinner();
@ -68,7 +69,7 @@ namespace NzbDrone.Automation.Test
{ {
try try
{ {
var image = ((ITakesScreenshot)driver).GetScreenshot(); var image = (driver as ITakesScreenshot).GetScreenshot();
image.SaveAsFile($"./{name}_test_screenshot.png", ScreenshotImageFormat.Png); image.SaveAsFile($"./{name}_test_screenshot.png", ScreenshotImageFormat.Png);
} }
catch (Exception ex) catch (Exception ex)

View file

@ -1,19 +1,17 @@
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 RemoteWebDriver _driver; private readonly IWebDriver _driver;
public PageBase(RemoteWebDriver driver) public PageBase(IWebDriver driver)
{ {
_driver = driver; _driver = driver;
driver.Manage().Window.Maximize();
} }
public IWebElement FindByClass(string className, int timeout = 5) public IWebElement FindByClass(string className, int timeout = 5)

View file

@ -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.InnerException, WebExceptionStatus.Timeout, null); throw new WebException("Http request timed out", ex, WebExceptionStatus.Timeout, null);
} }
} }

View file

@ -6,7 +6,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="DryIoc.dll" Version="5.4.3" /> <PackageReference Include="DryIoc.dll" Version="5.4.3" />
<PackageReference Include="IPAddressRange" Version="6.1.0" /> <PackageReference Include="IPAddressRange" Version="6.2.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.1" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="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.4.0" />

View file

@ -103,6 +103,7 @@ 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>();

View file

@ -11,6 +11,7 @@ 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);
} }
} }

View file

@ -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(/|$)", RegexOptions.Compiled); private static readonly Regex _regexSpecialDrive = new Regex(@"^/var/lib/(docker|rancher|kubelet)(/|$)|^/(boot|etc)(/|$)|/docker(/var)?/aufs(/|$)|/\.timemachine", RegexOptions.Compiled);
public DiskSpaceService(IDiskProvider diskProvider, public DiskSpaceService(IDiskProvider diskProvider,
IRootFolderService rootFolderService, IRootFolderService rootFolderService,
@ -38,7 +38,10 @@ namespace NzbDrone.Core.DiskSpace
var optionalRootFolders = GetFixedDisksRootPaths().Except(importantRootFolders).Distinct().ToList(); var optionalRootFolders = GetFixedDisksRootPaths().Except(importantRootFolders).Distinct().ToList();
var diskSpace = GetDiskSpace(importantRootFolders).Concat(GetDiskSpace(optionalRootFolders, true)).ToList(); var diskSpace = GetDiskSpace(importantRootFolders)
.Concat(GetDiskSpace(optionalRootFolders, true))
.OrderBy(d => d.Path, StringComparer.OrdinalIgnoreCase)
.ToList();
return diskSpace; return diskSpace;
} }
@ -54,7 +57,7 @@ namespace NzbDrone.Core.DiskSpace
private IEnumerable<string> GetFixedDisksRootPaths() private IEnumerable<string> GetFixedDisksRootPaths()
{ {
return _diskProvider.GetMounts() return _diskProvider.GetMounts()
.Where(d => d.DriveType == DriveType.Fixed) .Where(d => d.DriveType is DriveType.Fixed or DriveType.Network)
.Where(d => !_regexSpecialDrive.IsMatch(d.RootDirectory)) .Where(d => !_regexSpecialDrive.IsMatch(d.RootDirectory))
.Select(d => d.RootDirectory); .Select(d => d.RootDirectory);
} }

View file

@ -9,6 +9,7 @@ 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,9 +29,10 @@ 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, blocklistService, logger) : base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, localizationService, blocklistService, logger)
{ {
_proxy = proxy; _proxy = proxy;
} }

View file

@ -9,6 +9,7 @@ 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;
@ -30,9 +31,10 @@ 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, blocklistService, logger) : base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, localizationService, blocklistService, logger)
{ {
_scanWatchFolder = scanWatchFolder; _scanWatchFolder = scanWatchFolder;

View file

@ -7,6 +7,7 @@ using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Organizer; using NzbDrone.Core.Organizer;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.RemotePathMappings; using NzbDrone.Core.RemotePathMappings;
@ -25,8 +26,9 @@ 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, logger) : base(httpClient, configService, diskProvider, remotePathMappingService, nzbValidationService, localizationService, logger)
{ {
_scanWatchFolder = scanWatchFolder; _scanWatchFolder = scanWatchFolder;

View file

@ -9,6 +9,7 @@ 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;
@ -27,9 +28,10 @@ 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, blocklistService, logger) : base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, localizationService, blocklistService, logger)
{ {
_proxy = proxy; _proxy = proxy;
} }

View file

@ -11,6 +11,7 @@ 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;
@ -37,9 +38,10 @@ 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, blocklistService, logger) : base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, localizationService, blocklistService, logger)
{ {
_dsInfoProxy = dsInfoProxy; _dsInfoProxy = dsInfoProxy;
_dsTaskProxySelector = dsTaskProxySelector; _dsTaskProxySelector = dsTaskProxySelector;

View file

@ -9,6 +9,7 @@ using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Download.Clients.DownloadStation.Proxies; using NzbDrone.Core.Download.Clients.DownloadStation.Proxies;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.RemotePathMappings; using NzbDrone.Core.RemotePathMappings;
using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.ThingiProvider;
@ -34,8 +35,9 @@ 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, logger) : base(httpClient, configService, diskProvider, remotePathMappingService, nzbValidationService, localizationService, logger)
{ {
_dsInfoProxy = dsInfoProxy; _dsInfoProxy = dsInfoProxy;
_dsTaskProxySelector = dsTaskProxySelector; _dsTaskProxySelector = dsTaskProxySelector;

View file

@ -9,6 +9,7 @@ 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;
@ -28,9 +29,10 @@ 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, blocklistService, logger) : base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, localizationService, blocklistService, logger)
{ {
_proxy = proxy; _proxy = proxy;
_downloadSeedConfigProvider = downloadSeedConfigProvider; _downloadSeedConfigProvider = downloadSeedConfigProvider;

View file

@ -9,6 +9,7 @@ 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;
@ -25,9 +26,10 @@ 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, blocklistService, logger) : base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, localizationService, blocklistService, logger)
{ {
_proxy = proxy; _proxy = proxy;
} }

View file

@ -8,6 +8,7 @@ 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;
@ -25,9 +26,10 @@ 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, blocklistService, logger) : base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, localizationService, blocklistService, logger)
{ {
_proxy = proxy; _proxy = proxy;
} }

View file

@ -8,6 +8,7 @@ using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.RemotePathMappings; using NzbDrone.Core.RemotePathMappings;
using NzbDrone.Core.Validation; using NzbDrone.Core.Validation;
@ -24,8 +25,9 @@ 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, logger) : base(httpClient, configService, diskProvider, remotePathMappingService, nzbValidationService, localizationService, logger)
{ {
_proxy = proxy; _proxy = proxy;
} }

View file

@ -10,6 +10,7 @@ using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Exceptions; using NzbDrone.Core.Exceptions;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.RemotePathMappings; using NzbDrone.Core.RemotePathMappings;
using NzbDrone.Core.Validation; using NzbDrone.Core.Validation;
@ -28,8 +29,9 @@ 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, logger) : base(httpClient, configService, diskProvider, remotePathMappingService, nzbValidationService, localizationService, logger)
{ {
_proxy = proxy; _proxy = proxy;
} }

View file

@ -9,6 +9,7 @@ using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.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;
@ -23,8 +24,9 @@ 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, logger) : base(configService, diskProvider, remotePathMappingService, localizationService, logger)
{ {
_httpClient = httpClient; _httpClient = httpClient;
} }

View file

@ -10,6 +10,7 @@ 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;
@ -35,9 +36,10 @@ 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, blocklistService, logger) : base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, localizationService, blocklistService, logger)
{ {
_proxySelector = proxySelector; _proxySelector = proxySelector;

View file

@ -10,6 +10,7 @@ using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Exceptions; using NzbDrone.Core.Exceptions;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.RemotePathMappings; using NzbDrone.Core.RemotePathMappings;
using NzbDrone.Core.Validation; using NzbDrone.Core.Validation;
@ -26,8 +27,9 @@ 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, logger) : base(httpClient, configService, diskProvider, remotePathMappingService, nzbValidationService, localizationService, logger)
{ {
_proxy = proxy; _proxy = proxy;
} }

View file

@ -8,6 +8,7 @@ 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;
@ -24,9 +25,10 @@ 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, blocklistService, logger) : base(proxy, torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, localizationService, blocklistService, logger)
{ {
} }

View file

@ -9,6 +9,7 @@ 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,9 +29,10 @@ 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, blocklistService, logger) : base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, localizationService, blocklistService, logger)
{ {
_proxy = proxy; _proxy = proxy;
} }
@ -101,7 +103,11 @@ namespace NzbDrone.Core.Download.Clients.Transmission
if (!torrent.ErrorString.IsNullOrWhiteSpace()) if (!torrent.ErrorString.IsNullOrWhiteSpace())
{ {
item.Status = DownloadItemStatus.Warning; item.Status = DownloadItemStatus.Warning;
item.Message = torrent.ErrorString; item.Message = _localizationService.GetLocalizedString("DownloadClientItemErrorMessage", new Dictionary<string, object>
{
{ "clientName", Name },
{ "message", torrent.ErrorString }
});
} }
else if (torrent.TotalSize == 0) else if (torrent.TotalSize == 0)
{ {

View file

@ -5,6 +5,7 @@ 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;
@ -23,9 +24,10 @@ 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, blocklistService, logger) : base(proxy, torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, localizationService, blocklistService, logger)
{ {
} }

View file

@ -12,6 +12,7 @@ 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;
@ -35,9 +36,10 @@ 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, blocklistService, logger) : base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, localizationService, blocklistService, logger)
{ {
_proxy = proxy; _proxy = proxy;
_rTorrentDirectoryValidator = rTorrentDirectoryValidator; _rTorrentDirectoryValidator = rTorrentDirectoryValidator;

View file

@ -10,6 +10,7 @@ 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,9 +30,10 @@ 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, blocklistService, logger) : base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, localizationService, blocklistService, logger)
{ {
_proxy = proxy; _proxy = proxy;

View file

@ -8,6 +8,7 @@ using NzbDrone.Common.Disk;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers; using NzbDrone.Core.Indexers;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.RemotePathMappings; using NzbDrone.Core.RemotePathMappings;
using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.ThingiProvider;
@ -23,6 +24,7 @@ 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>()
@ -77,11 +79,13 @@ 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;
} }

View file

@ -1,3 +1,4 @@
using System;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Xml; using System.Xml;
@ -14,10 +15,13 @@ 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, new XmlReaderSettings { DtdProcessing = DtdProcessing.Ignore, IgnoreComments = true })) using (var xmlTextReader = XmlReader.Create(reader,
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;
@ -37,7 +41,8 @@ namespace NzbDrone.Core.Download
if (!nzb.Name.LocalName.Equals("nzb")) if (!nzb.Name.LocalName.Equals("nzb"))
{ {
throw new InvalidNzbException("Invalid NZB: Unexpected root element. Expected 'nzb' found '{0}' [{1}]", nzb.Name.LocalName, filename); throw new InvalidNzbException(
"Invalid NZB: Unexpected root element. Expected 'nzb' found '{0}' [{1}]", nzb.Name.LocalName, filename);
} }
var ns = nzb.Name.Namespace; var ns = nzb.Name.Namespace;
@ -49,5 +54,15 @@ 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);
}
}
} }
} }

View file

@ -10,6 +10,7 @@ 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;
@ -30,9 +31,10 @@ 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, logger) : base(configService, diskProvider, remotePathMappingService, localizationService, logger)
{ {
_httpClient = httpClient; _httpClient = httpClient;
_blocklistService = blocklistService; _blocklistService = blocklistService;
@ -170,7 +172,7 @@ namespace NzbDrone.Core.Download
} }
catch (HttpException ex) catch (HttpException ex)
{ {
if (ex.Response.StatusCode == HttpStatusCode.NotFound) if (ex.Response.StatusCode is HttpStatusCode.NotFound or HttpStatusCode.Gone)
{ {
_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);

View file

@ -6,6 +6,7 @@ using NzbDrone.Common.Http;
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.Organizer; using NzbDrone.Core.Organizer;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.RemotePathMappings; using NzbDrone.Core.RemotePathMappings;
@ -24,8 +25,9 @@ namespace NzbDrone.Core.Download
IDiskProvider diskProvider, IDiskProvider diskProvider,
IRemotePathMappingService remotePathMappingService, IRemotePathMappingService remotePathMappingService,
IValidateNzbs nzbValidationService, IValidateNzbs nzbValidationService,
ILocalizationService localizationService,
Logger logger) Logger logger)
: base(configService, diskProvider, remotePathMappingService, logger) : base(configService, diskProvider, remotePathMappingService, localizationService, logger)
{ {
_httpClient = httpClient; _httpClient = httpClient;
_nzbValidationService = nzbValidationService; _nzbValidationService = nzbValidationService;
@ -46,6 +48,7 @@ namespace NzbDrone.Core.Download
{ {
var request = indexer?.GetDownloadRequest(url) ?? new HttpRequest(url); var request = indexer?.GetDownloadRequest(url) ?? new HttpRequest(url);
request.RateLimitKey = remoteAlbum?.Release?.IndexerId.ToString(); request.RateLimitKey = remoteAlbum?.Release?.IndexerId.ToString();
request.AllowAutoRedirect = true;
var response = await RetryStrategy var response = await RetryStrategy
.ExecuteAsync(static async (state, _) => await state._httpClient.GetAsync(state.request), (_httpClient, request)) .ExecuteAsync(static async (state, _) => await state._httpClient.GetAsync(state.request), (_httpClient, request))
@ -57,7 +60,7 @@ namespace NzbDrone.Core.Download
} }
catch (HttpException ex) catch (HttpException ex)
{ {
if (ex.Response.StatusCode == HttpStatusCode.NotFound) if (ex.Response.StatusCode is HttpStatusCode.NotFound or HttpStatusCode.Gone)
{ {
_logger.Error(ex, "Downloading nzb file for album '{0}' failed since it no longer exists ({1})", remoteAlbum.Release.Title, url); _logger.Error(ex, "Downloading nzb file for album '{0}' failed since it no longer exists ({1})", remoteAlbum.Release.Title, url);
throw new ReleaseUnavailableException(remoteAlbum.Release, "Downloading nzb failed", ex); throw new ReleaseUnavailableException(remoteAlbum.Release, "Downloading nzb failed", ex);

View file

@ -157,7 +157,7 @@ namespace NzbDrone.Core.History
history.Data.Add("Age", message.Album.Release.Age.ToString()); history.Data.Add("Age", message.Album.Release.Age.ToString());
history.Data.Add("AgeHours", message.Album.Release.AgeHours.ToString()); history.Data.Add("AgeHours", message.Album.Release.AgeHours.ToString());
history.Data.Add("AgeMinutes", message.Album.Release.AgeMinutes.ToString()); history.Data.Add("AgeMinutes", message.Album.Release.AgeMinutes.ToString());
history.Data.Add("PublishedDate", message.Album.Release.PublishDate.ToString("s") + "Z"); history.Data.Add("PublishedDate", message.Album.Release.PublishDate.ToUniversalTime().ToString("s") + "Z");
history.Data.Add("DownloadClient", message.DownloadClient); history.Data.Add("DownloadClient", message.DownloadClient);
history.Data.Add("Size", message.Album.Release.Size.ToString()); history.Data.Add("Size", message.Album.Release.Size.ToString());
history.Data.Add("DownloadUrl", message.Album.Release.DownloadUrl); history.Data.Add("DownloadUrl", message.Album.Release.DownloadUrl);

View file

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
@ -44,6 +45,11 @@ namespace NzbDrone.Core.Indexers.FileList
private IEnumerable<IndexerRequest> GetRequest(string searchType, IEnumerable<int> categories, string parameters) private IEnumerable<IndexerRequest> GetRequest(string searchType, IEnumerable<int> categories, string parameters)
{ {
if (categories.Empty())
{
yield break;
}
var categoriesQuery = string.Join(",", categories.Distinct()); var categoriesQuery = string.Join(",", categories.Distinct());
var baseUrl = string.Format("{0}/api.php?action={1}&category={2}{3}", Settings.BaseUrl.TrimEnd('/'), searchType, categoriesQuery, parameters); var baseUrl = string.Format("{0}/api.php?action={1}&category={2}{3}", Settings.BaseUrl.TrimEnd('/'), searchType, categoriesQuery, parameters);

View file

@ -13,6 +13,8 @@ namespace NzbDrone.Core.Indexers.FileList
RuleFor(c => c.Username).NotEmpty(); RuleFor(c => c.Username).NotEmpty();
RuleFor(c => c.Passkey).NotEmpty(); RuleFor(c => c.Passkey).NotEmpty();
RuleFor(c => c.Categories).NotEmpty();
RuleFor(c => c.SeedCriteria).SetValidator(_ => new SeedCriteriaSettingsValidator()); RuleFor(c => c.SeedCriteria).SetValidator(_ => new SeedCriteriaSettingsValidator());
} }
} }

View file

@ -27,7 +27,7 @@
<PackageReference Include="TagLibSharp-Lidarr" Version="2.2.0.27" /> <PackageReference Include="TagLibSharp-Lidarr" Version="2.2.0.27" />
<PackageReference Include="Npgsql" Version="7.0.10" /> <PackageReference Include="Npgsql" Version="7.0.10" />
<PackageReference Include="SpotifyAPI.Web" Version="5.1.1" /> <PackageReference Include="SpotifyAPI.Web" Version="5.1.1" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.7" /> <PackageReference Include="SixLabors.ImageSharp" Version="3.1.9" />
<PackageReference Include="MonoTorrent" Version="2.0.7" /> <PackageReference Include="MonoTorrent" Version="2.0.7" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View file

@ -256,6 +256,7 @@
"CreateEmptyArtistFolders": "Create empty artist folders", "CreateEmptyArtistFolders": "Create empty artist folders",
"CreateEmptyArtistFoldersHelpText": "Create missing artist folders during disk scan", "CreateEmptyArtistFoldersHelpText": "Create missing artist folders during disk scan",
"CreateGroup": "Create group", "CreateGroup": "Create group",
"CurrentlyInstalled": "Currently Installed",
"Custom": "Custom", "Custom": "Custom",
"CustomFilter": "Custom Filter", "CustomFilter": "Custom Filter",
"CustomFilters": "Custom Filters", "CustomFilters": "Custom Filters",
@ -334,8 +335,6 @@
"DeleteReleaseProfileMessageText": "Are you sure you want to delete this release profile?", "DeleteReleaseProfileMessageText": "Are you sure you want to delete this release profile?",
"DeleteRemotePathMapping": "Delete Remote Path Mapping", "DeleteRemotePathMapping": "Delete Remote Path Mapping",
"DeleteRemotePathMappingMessageText": "Are you sure you want to delete this remote path mapping?", "DeleteRemotePathMappingMessageText": "Are you sure you want to delete this remote path mapping?",
"DeleteRootFolder": "Delete Root Folder",
"DeleteRootFolderMessageText": "Are you sure you want to delete the root folder '{name}'?",
"DeleteSelected": "Delete Selected", "DeleteSelected": "Delete Selected",
"DeleteSelectedArtists": "Delete Selected Artists", "DeleteSelectedArtists": "Delete Selected Artists",
"DeleteSelectedCustomFormats": "Delete Custom Format(s)", "DeleteSelectedCustomFormats": "Delete Custom Format(s)",
@ -383,6 +382,7 @@
"DownloadClientDelugeSettingsDirectoryCompleted": "Move When Completed Directory", "DownloadClientDelugeSettingsDirectoryCompleted": "Move When Completed Directory",
"DownloadClientDelugeSettingsDirectoryCompletedHelpText": "Optional location to move completed downloads to, leave blank to use the default Deluge location", "DownloadClientDelugeSettingsDirectoryCompletedHelpText": "Optional location to move completed downloads to, leave blank to use the default Deluge location",
"DownloadClientDelugeSettingsDirectoryHelpText": "Optional location to put downloads in, leave blank to use the default Deluge location", "DownloadClientDelugeSettingsDirectoryHelpText": "Optional location to put downloads in, leave blank to use the default Deluge location",
"DownloadClientItemErrorMessage": "{clientName} is reporting an error: {message}",
"DownloadClientPriorityHelpText": "Download Client Priority from 1 (Highest) to 50 (Lowest). Default: 1. Round-Robin is used for clients with the same priority.", "DownloadClientPriorityHelpText": "Download Client Priority from 1 (Highest) to 50 (Lowest). Default: 1. Round-Robin is used for clients with the same priority.",
"DownloadClientQbittorrentSettingsContentLayout": "Content Layout", "DownloadClientQbittorrentSettingsContentLayout": "Content Layout",
"DownloadClientQbittorrentSettingsContentLayoutHelpText": "Whether to use qBittorrent's configured content layout, the original layout from the torrent or always create a subfolder (qBittorrent 4.3.2+)", "DownloadClientQbittorrentSettingsContentLayoutHelpText": "Whether to use qBittorrent's configured content layout, the original layout from the torrent or always create a subfolder (qBittorrent 4.3.2+)",
@ -486,6 +486,8 @@
"ExtraFileExtensionsHelpTextsExamples": "Examples: '.sub, .nfo' or 'sub,nfo'", "ExtraFileExtensionsHelpTextsExamples": "Examples: '.sub, .nfo' or 'sub,nfo'",
"FailedDownloadHandling": "Failed Download Handling", "FailedDownloadHandling": "Failed Download Handling",
"FailedLoadingSearchResults": "Failed to load search results, please try again.", "FailedLoadingSearchResults": "Failed to load search results, please try again.",
"FailedToFetchSettings": "Failed to fetch settings",
"FailedToFetchUpdates": "Failed to fetch updates",
"FailedToLoadQueue": "Failed to load Queue", "FailedToLoadQueue": "Failed to load Queue",
"False": "False", "False": "False",
"FileDateHelpText": "Change file date on import/rescan", "FileDateHelpText": "Change file date on import/rescan",
@ -688,6 +690,7 @@
"LocalPathHelpText": "Path that {appName} should use to access the remote path locally", "LocalPathHelpText": "Path that {appName} should use to access the remote path locally",
"Location": "Location", "Location": "Location",
"LogFiles": "Log Files", "LogFiles": "Log Files",
"LogFilesLocation": "Log files are located in: {location}",
"LogLevel": "Log Level", "LogLevel": "Log Level",
"LogLevelvalueTraceTraceLoggingShouldOnlyBeEnabledTemporarily": "Trace logging should only be enabled temporarily", "LogLevelvalueTraceTraceLoggingShouldOnlyBeEnabledTemporarily": "Trace logging should only be enabled temporarily",
"LogSizeLimit": "Log Size Limit", "LogSizeLimit": "Log Size Limit",
@ -1024,6 +1027,8 @@
"RemoveQueueItemRemovalMethod": "Removal Method", "RemoveQueueItemRemovalMethod": "Removal Method",
"RemoveQueueItemRemovalMethodHelpTextWarning": "'Remove from Download Client' will remove the download and the file(s) from the download client.", "RemoveQueueItemRemovalMethodHelpTextWarning": "'Remove from Download Client' will remove the download and the file(s) from the download client.",
"RemoveQueueItemsRemovalMethodHelpTextWarning": "'Remove from Download Client' will remove the downloads and the files from the download client.", "RemoveQueueItemsRemovalMethodHelpTextWarning": "'Remove from Download Client' will remove the downloads and the files from the download client.",
"RemoveRootFolder": "Remove Root Folder",
"RemoveRootFolderArtistsMessageText": "Are you sure you want to remove the root folder '{name}'? Files and folders will not be deleted from disk, and artists in this root folder will not be removed from {appName}.",
"RemoveSelected": "Remove Selected", "RemoveSelected": "Remove Selected",
"RemoveSelectedItem": "Remove Selected Item", "RemoveSelectedItem": "Remove Selected Item",
"RemoveSelectedItemBlocklistMessageText": "Are you sure you want to remove the selected items from the blocklist?", "RemoveSelectedItemBlocklistMessageText": "Are you sure you want to remove the selected items from the blocklist?",
@ -1218,6 +1223,7 @@
"TestParsing": "Test Parsing", "TestParsing": "Test Parsing",
"TheAlbumsFilesWillBeDeleted": "The album's files will be deleted.", "TheAlbumsFilesWillBeDeleted": "The album's files will be deleted.",
"TheArtistFolderStrongpathstrongAndAllOfItsContentWillBeDeleted": "The artist folder '{0}' and all of its content will be deleted.", "TheArtistFolderStrongpathstrongAndAllOfItsContentWillBeDeleted": "The artist folder '{0}' and all of its content will be deleted.",
"TheLogLevelDefault": "The log level defaults to 'Debug' and can be changed in [General Settings](/settings/general)",
"Theme": "Theme", "Theme": "Theme",
"ThemeHelpText": "Change Application UI Theme, 'Auto' Theme will use your OS Theme to set Light or Dark mode. Inspired by Theme.Park", "ThemeHelpText": "Change Application UI Theme, 'Auto' Theme will use your OS Theme to set Light or Dark mode. Inspired by Theme.Park",
"ThereWasAnErrorLoadingThisItem": "There was an error loading this item", "ThereWasAnErrorLoadingThisItem": "There was an error loading this item",

View file

@ -65,6 +65,10 @@ namespace NzbDrone.Core.MediaFiles
_logger.Debug("Removing existing track file: {0}", file); _logger.Debug("Removing existing track file: {0}", file);
_recycleBinProvider.DeleteFile(trackFilePath, subfolder); _recycleBinProvider.DeleteFile(trackFilePath, subfolder);
} }
else
{
_logger.Warn("Existing track file missing from disk: {0}", trackFilePath);
}
moveFileResult.OldFiles.Add(file); moveFileResult.OldFiles.Add(file);
_mediaFileService.Delete(file, DeleteMediaFileReason.Upgrade); _mediaFileService.Delete(file, DeleteMediaFileReason.Upgrade);

View file

@ -18,6 +18,8 @@ namespace NzbDrone.Core.Music
} }
public bool ShouldRefresh(Album album) public bool ShouldRefresh(Album album)
{
try
{ {
if (album.LastInfoSync < DateTime.UtcNow.AddDays(-60)) if (album.LastInfoSync < DateTime.UtcNow.AddDays(-60))
{ {
@ -40,5 +42,11 @@ namespace NzbDrone.Core.Music
_logger.Trace("Album {0} released long ago and recently refreshed, should not be refreshed.", album.Title); _logger.Trace("Album {0} released long ago and recently refreshed, should not be refreshed.", album.Title);
return false; return false;
} }
catch (Exception e)
{
_logger.Error(e, "Unable to determine if album should refresh, will try to refresh.");
return true;
}
}
} }
} }

View file

@ -21,6 +21,8 @@ namespace NzbDrone.Core.Music
} }
public bool ShouldRefresh(Artist artist) public bool ShouldRefresh(Artist artist)
{
try
{ {
if (artist.LastInfoSync == null) if (artist.LastInfoSync == null)
{ {
@ -57,5 +59,11 @@ namespace NzbDrone.Core.Music
_logger.Trace("Artist {0} ended long ago, should not be refreshed.", artist.Name); _logger.Trace("Artist {0} ended long ago, should not be refreshed.", artist.Name);
return false; return false;
} }
catch (Exception e)
{
_logger.Error(e, "Unable to determine if artist should refresh, will try to refresh.");
return true;
}
}
} }
} }

View file

@ -347,7 +347,7 @@ namespace NzbDrone.Core.Notifications.CustomScript
{ {
if (artist == null) if (artist == null)
{ {
return null; return new List<string>();
} }
return _tagRepository.GetTags(artist.Tags) return _tagRepository.GetTags(artist.Tags)

View file

@ -514,9 +514,9 @@ namespace NzbDrone.Core.Notifications.Discord
{ {
var albumTitles = string.Join(" + ", albums.Select(e => e.Title)); var albumTitles = string.Join(" + ", albums.Select(e => e.Title));
var title = $"{artist.Name} - {albumTitles}"; var title = $"{artist.Name} - {albumTitles}".Replace("`", "\\`");
return title.Length > 256 ? $"{title.AsSpan(0, 253)}..." : title; return title.Length > 256 ? $"{title.AsSpan(0, 253).TrimEnd('\\')}..." : title;
} }
} }
} }

View file

@ -96,6 +96,11 @@ namespace NzbDrone.Core.RemotePathMappings
throw new ArgumentException("Invalid Host"); throw new ArgumentException("Invalid Host");
} }
if (mapping.RemotePath.StartsWith(" "))
{
throw new ArgumentException("Remote Path must not start with a space");
}
var remotePath = new OsPath(mapping.RemotePath); var remotePath = new OsPath(mapping.RemotePath);
var localPath = new OsPath(mapping.LocalPath); var localPath = new OsPath(mapping.LocalPath);