diff --git a/frontend/src/Components/FieldSet.css b/frontend/src/Components/FieldSet.css index daf3bdf2e..6da64f0e0 100644 --- a/frontend/src/Components/FieldSet.css +++ b/frontend/src/Components/FieldSet.css @@ -16,4 +16,9 @@ color: #3a3f51; font-size: 21px; line-height: inherit; + + &.small { + color: #909293; + font-size: 18px; + } } diff --git a/frontend/src/Components/FieldSet.js b/frontend/src/Components/FieldSet.js index 76e68a934..8243fd00c 100644 --- a/frontend/src/Components/FieldSet.js +++ b/frontend/src/Components/FieldSet.js @@ -1,5 +1,7 @@ +import classNames from 'classnames'; import PropTypes from 'prop-types'; import React, { Component } from 'react'; +import { sizes } from 'Helpers/Props'; import styles from './FieldSet.css'; class FieldSet extends Component { @@ -9,13 +11,14 @@ class FieldSet extends Component { render() { const { + size, legend, children } = this.props; return (
- + {legend} {children} @@ -26,8 +29,13 @@ class FieldSet extends Component { } FieldSet.propTypes = { + size: PropTypes.oneOf(sizes.all).isRequired, legend: PropTypes.oneOfType([PropTypes.node, PropTypes.string]), children: PropTypes.node }; +FieldSet.defaultProps = { + size: sizes.MEDIUM +}; + export default FieldSet; diff --git a/frontend/src/Settings/DownloadClients/DownloadClients/EditDownloadClientModalContent.js b/frontend/src/Settings/DownloadClients/DownloadClients/EditDownloadClientModalContent.js index 8aba1b678..b2238f58e 100644 --- a/frontend/src/Settings/DownloadClients/DownloadClients/EditDownloadClientModalContent.js +++ b/frontend/src/Settings/DownloadClients/DownloadClients/EditDownloadClientModalContent.js @@ -1,6 +1,7 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; import Alert from 'Components/Alert'; +import FieldSet from 'Components/FieldSet'; import Form from 'Components/Form/Form'; import FormGroup from 'Components/Form/FormGroup'; import FormInputGroup from 'Components/Form/FormInputGroup'; @@ -13,7 +14,7 @@ import ModalBody from 'Components/Modal/ModalBody'; import ModalContent from 'Components/Modal/ModalContent'; import ModalFooter from 'Components/Modal/ModalFooter'; import ModalHeader from 'Components/Modal/ModalHeader'; -import { inputTypes, kinds } from 'Helpers/Props'; +import { inputTypes, kinds, sizes } from 'Helpers/Props'; import translate from 'Utilities/String/translate'; import styles from './EditDownloadClientModalContent.css'; @@ -45,7 +46,10 @@ class EditDownloadClientModalContent extends Component { implementationName, name, enable, + protocol, priority, + removeCompletedDownloads, + removeFailedDownloads, fields, message } = item; @@ -136,6 +140,38 @@ class EditDownloadClientModalContent extends Component { /> +
+ + {translate('RemoveCompleted')} + + + + + { + protocol.value !== 'torrent' && + + {translate('RemoveFailed')} + + + + } +
+ } diff --git a/frontend/src/Settings/DownloadClients/Options/DownloadClientOptions.js b/frontend/src/Settings/DownloadClients/Options/DownloadClientOptions.js index 35252c013..5a038e046 100644 --- a/frontend/src/Settings/DownloadClients/Options/DownloadClientOptions.js +++ b/frontend/src/Settings/DownloadClients/Options/DownloadClientOptions.js @@ -1,12 +1,13 @@ import PropTypes from 'prop-types'; import React from 'react'; +import Alert from 'Components/Alert'; import FieldSet from 'Components/FieldSet'; import Form from 'Components/Form/Form'; import FormGroup from 'Components/Form/FormGroup'; import FormInputGroup from 'Components/Form/FormInputGroup'; import FormLabel from 'Components/Form/FormLabel'; import LoadingIndicator from 'Components/Loading/LoadingIndicator'; -import { inputTypes, sizes } from 'Helpers/Props'; +import { inputTypes, kinds, sizes } from 'Helpers/Props'; import translate from 'Utilities/String/translate'; function DownloadClientOptions(props) { @@ -34,35 +35,23 @@ function DownloadClientOptions(props) { } { - hasSettings && !isFetching && !error && + hasSettings && !isFetching && !error && advancedSettings &&
- - {translate('Enable')} - - - - - {translate('Remove')} + {translate('Enable')} @@ -102,23 +91,10 @@ function DownloadClientOptions(props) { {...settings.autoRedownloadFailed} /> - - - {translate('Remove')} - - -
+ + {translate('RemoveDownloadsAlert')} +
} diff --git a/src/NzbDrone.Core.Test/Datastore/Migration/200_cdh_per_downloadclientFixture.cs b/src/NzbDrone.Core.Test/Datastore/Migration/200_cdh_per_downloadclientFixture.cs new file mode 100644 index 000000000..438e26a93 --- /dev/null +++ b/src/NzbDrone.Core.Test/Datastore/Migration/200_cdh_per_downloadclientFixture.cs @@ -0,0 +1,131 @@ +using System.Collections.Generic; +using System.Linq; +using System.Text.Json; +using FluentAssertions; +using NUnit.Framework; +using NzbDrone.Common.Serializer; +using NzbDrone.Core.Datastore.Migration; +using NzbDrone.Core.Download.Clients.RTorrent; +using NzbDrone.Core.Test.Framework; + +namespace NzbDrone.Core.Test.Datastore.Migration +{ + [TestFixture] + public class cdh_per_downloadclientFixture : MigrationTest + { + [Test] + public void should_set_cdh_to_enabled() + { + var db = WithMigrationTestDb(c => + { + c.Insert.IntoTable("DownloadClients").Row(new + { + Enable = 1, + Name = "Deluge", + Implementation = "Deluge", + Priority = 1, + Settings = new DelugeSettings85 + { + Host = "127.0.0.1", + MovieCategory = "abc", + UrlBase = "/my/" + }.ToJson(), + ConfigContract = "DelugeSettings" + }); + }); + + var items = db.Query("SELECT * FROM DownloadClients"); + + items.Should().HaveCount(1); + items.First().RemoveCompletedDownloads.Should().BeFalse(); + items.First().RemoveFailedDownloads.Should().BeTrue(); + } + + [Test] + public void should_set_cdh_to_disabled_when_globally_disabled() + { + var db = WithMigrationTestDb(c => + { + c.Insert.IntoTable("Config").Row(new + { + Key = "removecompleteddownloads", + Value = "True" + }); + + c.Insert.IntoTable("DownloadClients").Row(new + { + Enable = 1, + Name = "Deluge", + Implementation = "Deluge", + Priority = 1, + Settings = new DelugeSettings85 + { + Host = "127.0.0.1", + MovieCategory = "abc", + UrlBase = "/my/" + }.ToJson(), + ConfigContract = "DelugeSettings" + }); + }); + + var items = db.Query("SELECT * FROM DownloadClients"); + + items.Should().HaveCount(1); + items.First().RemoveCompletedDownloads.Should().BeTrue(); + items.First().RemoveFailedDownloads.Should().BeTrue(); + } + + [Test] + public void should_disable_remove_for_existing_rtorrent() + { + var db = WithMigrationTestDb(c => + { + c.Insert.IntoTable("DownloadClients").Row(new + { + Enable = 1, + Name = "RTorrent", + Implementation = "RTorrent", + Priority = 1, + Settings = new RTorrentSettings + { + Host = "127.0.0.1", + MovieCategory = "abc", + UrlBase = "/my/" + }.ToJson(), + ConfigContract = "RTorrentSettings" + }); + }); + + var items = db.Query("SELECT * FROM DownloadClients"); + + items.Should().HaveCount(1); + items.First().RemoveCompletedDownloads.Should().BeFalse(); + items.First().RemoveFailedDownloads.Should().BeTrue(); + } + } + + public class DownloadClientDefinition158 + { + public int Id { get; set; } + public bool Enable { get; set; } + public int Priority { get; set; } + public string Name { get; set; } + public string Implementation { get; set; } + public JsonElement Settings { get; set; } + public string ConfigContract { get; set; } + public bool RemoveCompletedDownloads { get; set; } + public bool RemoveFailedDownloads { get; set; } + } + + public class DelugeSettings85 + { + public string Host { get; set; } + public int Port { get; set; } + public string UrlBase { get; set; } + public string Password { get; set; } + public string MovieCategory { get; set; } + public int RecentTvPriority { get; set; } + public int OlderTvPriority { get; set; } + public bool UseSsl { get; set; } + } +} diff --git a/src/NzbDrone.Core/Configuration/ConfigService.cs b/src/NzbDrone.Core/Configuration/ConfigService.cs index c38203253..8dc2b746e 100644 --- a/src/NzbDrone.Core/Configuration/ConfigService.cs +++ b/src/NzbDrone.Core/Configuration/ConfigService.cs @@ -192,13 +192,6 @@ namespace NzbDrone.Core.Configuration set { SetValue("WhitelistedHardcodedSubs", value); } } - public bool RemoveCompletedDownloads - { - get { return GetValueBoolean("RemoveCompletedDownloads", false); } - - set { SetValue("RemoveCompletedDownloads", value); } - } - public bool AutoRedownloadFailed { get { return GetValueBoolean("AutoRedownloadFailed", true); } @@ -206,13 +199,6 @@ namespace NzbDrone.Core.Configuration set { SetValue("AutoRedownloadFailed", value); } } - public bool RemoveFailedDownloads - { - get { return GetValueBoolean("RemoveFailedDownloads", true); } - - set { SetValue("RemoveFailedDownloads", value); } - } - public bool CreateEmptyMovieFolders { get { return GetValueBoolean("CreateEmptyMovieFolders", false); } diff --git a/src/NzbDrone.Core/Configuration/IConfigService.cs b/src/NzbDrone.Core/Configuration/IConfigService.cs index cb42aa207..dade3eef1 100644 --- a/src/NzbDrone.Core/Configuration/IConfigService.cs +++ b/src/NzbDrone.Core/Configuration/IConfigService.cs @@ -21,10 +21,8 @@ namespace NzbDrone.Core.Configuration //Completed/Failed Download Handling (Download client) bool EnableCompletedDownloadHandling { get; set; } - bool RemoveCompletedDownloads { get; set; } bool AutoRedownloadFailed { get; set; } - bool RemoveFailedDownloads { get; set; } //Media Management bool AutoUnmonitorPreviouslyDownloadedMovies { get; set; } diff --git a/src/NzbDrone.Core/Datastore/Migration/200_cdh_per_downloadclient.cs b/src/NzbDrone.Core/Datastore/Migration/200_cdh_per_downloadclient.cs new file mode 100644 index 000000000..9e931ce70 --- /dev/null +++ b/src/NzbDrone.Core/Datastore/Migration/200_cdh_per_downloadclient.cs @@ -0,0 +1,56 @@ +using System.Data; +using System.Linq; +using FluentMigrator; +using Newtonsoft.Json.Linq; +using NzbDrone.Common.Serializer; +using NzbDrone.Core.Datastore.Migration.Framework; + +namespace NzbDrone.Core.Datastore.Migration +{ + [Migration(200)] + public class cdh_per_downloadclient : NzbDroneMigrationBase + { + protected override void MainDbUpgrade() + { + Alter.Table("DownloadClients") + .AddColumn("RemoveCompletedDownloads").AsBoolean().NotNullable().WithDefaultValue(true) + .AddColumn("RemoveFailedDownloads").AsBoolean().NotNullable().WithDefaultValue(true); + + Execute.WithConnection(MoveRemoveSettings); + } + + private void MoveRemoveSettings(IDbConnection conn, IDbTransaction tran) + { + var removeCompletedDownloads = false; + var removeFailedDownloads = true; + + using (var removeCompletedDownloadsCmd = conn.CreateCommand(tran, "SELECT Value FROM Config WHERE Key = 'removecompleteddownloads'")) + { + if ((removeCompletedDownloadsCmd.ExecuteScalar() as string)?.ToLower() == "true") + { + removeCompletedDownloads = true; + } + } + + using (var removeFailedDownloadsCmd = conn.CreateCommand(tran, "SELECT Value FROM Config WHERE Key = 'removefaileddownloads'")) + { + if ((removeFailedDownloadsCmd.ExecuteScalar() as string)?.ToLower() == "false") + { + removeFailedDownloads = false; + } + } + + using (var updateClientCmd = conn.CreateCommand(tran, $"UPDATE DownloadClients SET RemoveCompletedDownloads = (CASE WHEN Implementation IN (\"RTorrent\", \"Flood\") THEN 0 ELSE ? END), RemoveFailedDownloads = ?")) + { + updateClientCmd.AddParameter(removeCompletedDownloads ? 1 : 0); + updateClientCmd.AddParameter(removeFailedDownloads ? 1 : 0); + updateClientCmd.ExecuteNonQuery(); + } + + using (var removeConfigCmd = conn.CreateCommand(tran, $"DELETE FROM Config WHERE Key IN ('removecompleteddownloads', 'removefaileddownloads')")) + { + removeConfigCmd.ExecuteNonQuery(); + } + } + } +} diff --git a/src/NzbDrone.Core/Datastore/Migration/Framework/MigrationExtension.cs b/src/NzbDrone.Core/Datastore/Migration/Framework/MigrationExtension.cs index 8d936463e..3607ca1d7 100644 --- a/src/NzbDrone.Core/Datastore/Migration/Framework/MigrationExtension.cs +++ b/src/NzbDrone.Core/Datastore/Migration/Framework/MigrationExtension.cs @@ -1,4 +1,5 @@ -using FluentMigrator; +using System.Data; +using FluentMigrator; using FluentMigrator.Builders.Create; using FluentMigrator.Builders.Create.Table; using FluentMigrator.Runner; @@ -16,6 +17,15 @@ namespace NzbDrone.Core.Datastore.Migration.Framework return expressionRoot.Table(name).WithColumn("Id").AsInt32().PrimaryKey().Identity(); } + public static IDbCommand CreateCommand(this IDbConnection conn, IDbTransaction tran, string query) + { + var command = conn.CreateCommand(); + command.Transaction = tran; + command.CommandText = query; + + return command; + } + public static void AddParameter(this System.Data.IDbCommand command, object value) { var parameter = command.CreateParameter(); diff --git a/src/NzbDrone.Core/Download/Clients/Flood/Flood.cs b/src/NzbDrone.Core/Download/Clients/Flood/Flood.cs index 35d541c5a..f7bb77dcf 100644 --- a/src/NzbDrone.Core/Download/Clients/Flood/Flood.cs +++ b/src/NzbDrone.Core/Download/Clients/Flood/Flood.cs @@ -18,8 +18,10 @@ namespace NzbDrone.Core.Download.Clients.Flood public class Flood : TorrentClientBase { private readonly IFloodProxy _proxy; + private readonly IDownloadSeedConfigProvider _downloadSeedConfigProvider; public Flood(IFloodProxy proxy, + IDownloadSeedConfigProvider downloadSeedConfigProvider, ITorrentFileInfoReader torrentFileInfoReader, IHttpClient httpClient, IConfigService configService, @@ -30,6 +32,7 @@ namespace NzbDrone.Core.Download.Clients.Flood : base(torrentFileInfoReader, httpClient, configService, namingConfigService, diskProvider, remotePathMappingService, logger) { _proxy = proxy; + _downloadSeedConfigProvider = downloadSeedConfigProvider; } private static IEnumerable HandleTags(RemoteMovie remoteMovie, FloodSettings settings) @@ -78,8 +81,7 @@ namespace NzbDrone.Core.Download.Clients.Flood } public override string Name => "Flood"; - public override ProviderMessage Message => new ProviderMessage("Radarr is unable to remove torrents that have finished seeding when using Flood", ProviderMessageType.Warning); - + public override ProviderMessage Message => new ProviderMessage("Radarr will handle automatic removal of torrents based on the current seed criteria in Settings -> Indexers", ProviderMessageType.Info); protected override string AddFromTorrentFile(RemoteMovie remoteMovie, string hash, string filename, byte[] fileContent) { _proxy.AddTorrentByFile(Convert.ToBase64String(fileContent), HandleTags(remoteMovie, Settings), Settings); @@ -120,6 +122,8 @@ namespace NzbDrone.Core.Download.Clients.Flood TotalSize = properties.SizeBytes, SeedRatio = properties.Ratio, Message = properties.Message, + CanMoveFiles = false, + CanBeRemoved = false, }; if (properties.Eta > 0) @@ -144,7 +148,28 @@ namespace NzbDrone.Core.Download.Clients.Flood item.Status = DownloadItemStatus.Paused; } - item.CanMoveFiles = item.CanBeRemoved = false; + if (item.Status == DownloadItemStatus.Completed) + { + // Grab cached seedConfig + var seedConfig = _downloadSeedConfigProvider.GetSeedConfiguration(item.DownloadId); + + if (seedConfig != null) + { + if (item.SeedRatio >= seedConfig.Ratio) + { + // Check if seed ratio reached + item.CanMoveFiles = item.CanBeRemoved = true; + } + else if (properties.DateFinished != null && properties.DateFinished > 0) + { + // Check if seed time reached + if ((DateTimeOffset.Now - DateTimeOffset.FromUnixTimeSeconds((long)properties.DateFinished)) >= seedConfig.SeedTime) + { + item.CanMoveFiles = item.CanBeRemoved = true; + } + } + } + } items.Add(item); } diff --git a/src/NzbDrone.Core/Download/Clients/Flood/Types/Torrent.cs b/src/NzbDrone.Core/Download/Clients/Flood/Types/Torrent.cs index 3f3500307..92ac1d1ab 100644 --- a/src/NzbDrone.Core/Download/Clients/Flood/Types/Torrent.cs +++ b/src/NzbDrone.Core/Download/Clients/Flood/Types/Torrent.cs @@ -31,5 +31,9 @@ namespace NzbDrone.Core.Download.Clients.Flood.Types [JsonProperty(PropertyName = "tags")] public List Tags { get; set; } + + // added in Flood 4.5 + [JsonProperty(PropertyName = "dateFinished")] + public long? DateFinished { get; set; } } } diff --git a/src/NzbDrone.Core/Download/DownloadClientDefinition.cs b/src/NzbDrone.Core/Download/DownloadClientDefinition.cs index 1c0dfa927..524ca5e5c 100644 --- a/src/NzbDrone.Core/Download/DownloadClientDefinition.cs +++ b/src/NzbDrone.Core/Download/DownloadClientDefinition.cs @@ -1,4 +1,4 @@ -using NzbDrone.Core.Indexers; +using NzbDrone.Core.Indexers; using NzbDrone.Core.ThingiProvider; namespace NzbDrone.Core.Download @@ -7,5 +7,7 @@ namespace NzbDrone.Core.Download { public DownloadProtocol Protocol { get; set; } public int Priority { get; set; } = 1; + public bool RemoveCompletedDownloads { get; set; } = true; + public bool RemoveFailedDownloads { get; set; } = true; } } diff --git a/src/NzbDrone.Core/Download/DownloadEventHub.cs b/src/NzbDrone.Core/Download/DownloadEventHub.cs index e0359d765..fd9de5125 100644 --- a/src/NzbDrone.Core/Download/DownloadEventHub.cs +++ b/src/NzbDrone.Core/Download/DownloadEventHub.cs @@ -27,38 +27,65 @@ namespace NzbDrone.Core.Download { var trackedDownload = message.TrackedDownload; - if (trackedDownload == null || !trackedDownload.DownloadItem.CanBeRemoved || _configService.RemoveFailedDownloads == false) + if (trackedDownload == null || + message.TrackedDownload.DownloadItem.Removed || + !trackedDownload.DownloadItem.CanBeRemoved) { return; } - RemoveFromDownloadClient(trackedDownload); + var downloadClient = _downloadClientProvider.Get(message.TrackedDownload.DownloadClient); + var definition = downloadClient.Definition as DownloadClientDefinition; + + if (!definition.RemoveFailedDownloads) + { + return; + } + + RemoveFromDownloadClient(trackedDownload, downloadClient); } public void Handle(DownloadCompletedEvent message) { - if (_configService.RemoveCompletedDownloads && - !message.TrackedDownload.DownloadItem.Removed && - message.TrackedDownload.DownloadItem.CanBeRemoved && - message.TrackedDownload.DownloadItem.Status != DownloadItemStatus.Downloading) + var trackedDownload = message.TrackedDownload; + var downloadClient = _downloadClientProvider.Get(trackedDownload.DownloadClient); + var definition = downloadClient.Definition as DownloadClientDefinition; + + MarkItemAsImported(trackedDownload, downloadClient); + + if (trackedDownload.DownloadItem.Removed || + !trackedDownload.DownloadItem.CanBeRemoved || + trackedDownload.DownloadItem.Status == DownloadItemStatus.Downloading) { - RemoveFromDownloadClient(message.TrackedDownload); + return; } - else + + if (!definition.RemoveCompletedDownloads) { - MarkItemAsImported(message.TrackedDownload); + return; } + + RemoveFromDownloadClient(message.TrackedDownload, downloadClient); } public void Handle(DownloadCanBeRemovedEvent message) { - // Already verified that it can be removed, just needs to be removed - RemoveFromDownloadClient(message.TrackedDownload); + var trackedDownload = message.TrackedDownload; + var downloadClient = _downloadClientProvider.Get(trackedDownload.DownloadClient); + var definition = downloadClient.Definition as DownloadClientDefinition; + + if (trackedDownload.DownloadItem.Removed || + !trackedDownload.DownloadItem.CanBeRemoved || + !definition.RemoveCompletedDownloads) + { + return; + } + + RemoveFromDownloadClient(message.TrackedDownload, downloadClient); } - private void RemoveFromDownloadClient(TrackedDownload trackedDownload) + private void RemoveFromDownloadClient(TrackedDownload trackedDownload, IDownloadClient downloadClient) { - var downloadClient = _downloadClientProvider.Get(trackedDownload.DownloadClient); try { _logger.Debug("[{0}] Removing download from {1} history", trackedDownload.DownloadItem.Title, trackedDownload.DownloadItem.DownloadClientInfo.Name); @@ -75,9 +102,8 @@ namespace NzbDrone.Core.Download } } - private void MarkItemAsImported(TrackedDownload trackedDownload) + private void MarkItemAsImported(TrackedDownload trackedDownload, IDownloadClient downloadClient) { - var downloadClient = _downloadClientProvider.Get(trackedDownload.DownloadClient); try { _logger.Debug("[{0}] Marking download as imported from {1}", trackedDownload.DownloadItem.Title, trackedDownload.DownloadItem.DownloadClientInfo.Name); diff --git a/src/NzbDrone.Core/Download/DownloadProcessingService.cs b/src/NzbDrone.Core/Download/DownloadProcessingService.cs index 0b85b7278..1e88e257c 100644 --- a/src/NzbDrone.Core/Download/DownloadProcessingService.cs +++ b/src/NzbDrone.Core/Download/DownloadProcessingService.cs @@ -47,7 +47,6 @@ namespace NzbDrone.Core.Download public void Execute(ProcessMonitoredDownloadsCommand message) { var enableCompletedDownloadHandling = _configService.EnableCompletedDownloadHandling; - var removeCompletedDownloads = _configService.RemoveCompletedDownloads; var trackedDownloads = _trackedDownloadService.GetTrackedDownloads() .Where(t => t.IsTrackable) .ToList(); @@ -72,10 +71,7 @@ namespace NzbDrone.Core.Download } // Imported downloads are no longer trackable so process them after processing trackable downloads - if (removeCompletedDownloads) - { - RemoveCompletedDownloads(); - } + RemoveCompletedDownloads(); _eventAggregator.PublishEvent(new DownloadsProcessedEvent()); } diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index c41194e9f..1724a95ea 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -785,10 +785,13 @@ "RemotePathMappingCheckWrongOSPath": "Remote download client {0} places downloads in {1} but this is not a valid {2} path. Review your remote path mappings and download client settings.", "RemotePathMappings": "Remote Path Mappings", "Remove": "Remove", + "RemoveCompleted": "Remove Completed", "RemoveCompletedDownloadsHelpText": "Remove imported downloads from download client history", "RemovedFromTaskQueue": "Removed from task queue", "RemovedMovieCheckMultipleMessage": "Movies {0} were removed from TMDb", "RemovedMovieCheckSingleMessage": "Movie {0} was removed from TMDb", + "RemoveDownloadsAlert": "The Remove settings were moved to the individual Download Client settings in the table above.", + "RemoveFailed": "Remove Failed", "RemoveFailedDownloadsHelpText": "Remove failed downloads from download client history", "RemoveFilter": "Remove filter", "RemoveFromBlocklist": "Remove from blocklist", diff --git a/src/Radarr.Api.V3/Config/DownloadClientConfigResource.cs b/src/Radarr.Api.V3/Config/DownloadClientConfigResource.cs index ad1ac291f..e572b8b33 100644 --- a/src/Radarr.Api.V3/Config/DownloadClientConfigResource.cs +++ b/src/Radarr.Api.V3/Config/DownloadClientConfigResource.cs @@ -8,11 +8,9 @@ namespace Radarr.Api.V3.Config public string DownloadClientWorkingFolders { get; set; } public bool EnableCompletedDownloadHandling { get; set; } - public bool RemoveCompletedDownloads { get; set; } public int CheckForFinishedDownloadInterval { get; set; } public bool AutoRedownloadFailed { get; set; } - public bool RemoveFailedDownloads { get; set; } } public static class DownloadClientConfigResourceMapper @@ -24,11 +22,9 @@ namespace Radarr.Api.V3.Config DownloadClientWorkingFolders = model.DownloadClientWorkingFolders, EnableCompletedDownloadHandling = model.EnableCompletedDownloadHandling, - RemoveCompletedDownloads = model.RemoveCompletedDownloads, CheckForFinishedDownloadInterval = model.CheckForFinishedDownloadInterval, - AutoRedownloadFailed = model.AutoRedownloadFailed, - RemoveFailedDownloads = model.RemoveFailedDownloads + AutoRedownloadFailed = model.AutoRedownloadFailed }; } } diff --git a/src/Radarr.Api.V3/DownloadClient/DownloadClientResource.cs b/src/Radarr.Api.V3/DownloadClient/DownloadClientResource.cs index d2ebcc5cf..4776e098a 100644 --- a/src/Radarr.Api.V3/DownloadClient/DownloadClientResource.cs +++ b/src/Radarr.Api.V3/DownloadClient/DownloadClientResource.cs @@ -8,6 +8,8 @@ namespace Radarr.Api.V3.DownloadClient public bool Enable { get; set; } public DownloadProtocol Protocol { get; set; } public int Priority { get; set; } + public bool RemoveCompletedDownloads { get; set; } + public bool RemoveFailedDownloads { get; set; } } public class DownloadClientResourceMapper : ProviderResourceMapper @@ -24,6 +26,8 @@ namespace Radarr.Api.V3.DownloadClient resource.Enable = definition.Enable; resource.Protocol = definition.Protocol; resource.Priority = definition.Priority; + resource.RemoveCompletedDownloads = definition.RemoveCompletedDownloads; + resource.RemoveFailedDownloads = definition.RemoveFailedDownloads; return resource; } @@ -40,6 +44,8 @@ namespace Radarr.Api.V3.DownloadClient definition.Enable = resource.Enable; definition.Protocol = resource.Protocol; definition.Priority = resource.Priority; + definition.RemoveCompletedDownloads = resource.RemoveCompletedDownloads; + definition.RemoveFailedDownloads = resource.RemoveFailedDownloads; return definition; }