From 2d86e44c63a3cb588663415ff110a805befee4ab Mon Sep 17 00:00:00 2001 From: Kevin Richter Date: Sun, 5 Nov 2017 18:17:05 +0100 Subject: [PATCH] New: Added advanced setting per indexer to override seed ratio limit for supported clients. --- .../Configuration/ISeedConfigProvider.cs | 10 ++++++ .../Configuration/SeedConfigProvider.cs | 33 +++++++++++++++++++ .../Download/Clients/Deluge/Deluge.cs | 14 ++++++-- .../Download/Clients/Deluge/DelugeProxy.cs | 11 ++++--- .../Download/Clients/Deluge/DelugeTorrent.cs | 4 +-- .../DownloadStation/TorrentDownloadStation.cs | 16 ++++++++- .../DownloadStation/UsenetDownloadStation.cs | 2 +- .../Download/Clients/Hadouken/Hadouken.cs | 4 ++- .../Clients/Hadouken/HadoukenProxy.cs | 1 + .../Hadouken/Models/HadoukenTorrent.cs | 1 + .../Clients/QBittorrent/QBittorrent.cs | 1 + .../Clients/Transmission/TransmissionBase.cs | 26 ++++++++------- .../Clients/Transmission/TransmissionProxy.cs | 15 ++++++--- .../Transmission/TransmissionTorrent.cs | 6 ++++ .../Download/Clients/rTorrent/RTorrent.cs | 1 + .../Download/Clients/uTorrent/UTorrent.cs | 10 ++++-- .../Clients/uTorrent/UTorrentProxy.cs | 12 ++++--- .../Download/DownloadClientItem.cs | 1 + src/NzbDrone.Core/Download/DownloadService.cs | 7 ++++ .../Indexers/BitMeTv/BitMeTvSettings.cs | 3 ++ .../BroadcastheNet/BroadcastheNetSettings.cs | 3 ++ .../Indexers/HDBits/HDBitsSettings.cs | 3 ++ .../Indexers/IPTorrents/IPTorrentsSettings.cs | 4 ++- .../Indexers/ITorrentIndexerSettings.cs | 2 ++ .../Indexers/Nyaa/NyaaSettings.cs | 4 +++ .../Indexers/Rarbg/RarbgSettings.cs | 3 ++ .../TorrentRss/TorrentRssIndexerSettings.cs | 3 ++ .../Torrentleech/TorrentleechSettings.cs | 3 ++ .../Indexers/Torznab/TorznabSettings.cs | 3 ++ src/NzbDrone.Core/NzbDrone.Core.csproj | 2 ++ .../Parser/Model/RemoteEpisode.cs | 4 ++- 31 files changed, 175 insertions(+), 37 deletions(-) create mode 100644 src/NzbDrone.Core/Configuration/ISeedConfigProvider.cs create mode 100644 src/NzbDrone.Core/Configuration/SeedConfigProvider.cs diff --git a/src/NzbDrone.Core/Configuration/ISeedConfigProvider.cs b/src/NzbDrone.Core/Configuration/ISeedConfigProvider.cs new file mode 100644 index 000000000..ec91ff21a --- /dev/null +++ b/src/NzbDrone.Core/Configuration/ISeedConfigProvider.cs @@ -0,0 +1,10 @@ +using NzbDrone.Core.Download.Clients; +using NzbDrone.Core.Parser.Model; + +namespace NzbDrone.Core.Configuration +{ + public interface ISeedConfigProvider + { + TorrentSeedConfiguration GetSeedConfiguration(ReleaseInfo release); + } +} diff --git a/src/NzbDrone.Core/Configuration/SeedConfigProvider.cs b/src/NzbDrone.Core/Configuration/SeedConfigProvider.cs new file mode 100644 index 000000000..2398c8201 --- /dev/null +++ b/src/NzbDrone.Core/Configuration/SeedConfigProvider.cs @@ -0,0 +1,33 @@ +using NzbDrone.Core.Download.Clients; +using NzbDrone.Core.Indexers; +using NzbDrone.Core.Parser.Model; + +namespace NzbDrone.Core.Configuration +{ + public class SeedConfigProvider: ISeedConfigProvider + { + private readonly IIndexerFactory _indexerFactory; + + public SeedConfigProvider(IIndexerFactory indexerFactory) + { + _indexerFactory = indexerFactory; + } + + public TorrentSeedConfiguration GetSeedConfiguration(ReleaseInfo release) + { + if (release.DownloadProtocol != DownloadProtocol.Torrent) return null; + + var indexer = _indexerFactory.Get(release.IndexerId); + + if (indexer.Settings is ITorrentIndexerSettings torrentIndexerSettings) + { + return new TorrentSeedConfiguration + { + Ratio = torrentIndexerSettings.SeedRatio + }; + } + + return null; + } + } +} diff --git a/src/NzbDrone.Core/Download/Clients/Deluge/Deluge.cs b/src/NzbDrone.Core/Download/Clients/Deluge/Deluge.cs index 3b52f9570..54848872b 100644 --- a/src/NzbDrone.Core/Download/Clients/Deluge/Deluge.cs +++ b/src/NzbDrone.Core/Download/Clients/Deluge/Deluge.cs @@ -45,6 +45,8 @@ namespace NzbDrone.Core.Download.Clients.Deluge _proxy.SetLabel(actualHash, Settings.TvCategory, Settings); } + _proxy.SetTorrentSeedingConfiguration(actualHash, remoteEpisode.SeedConfiguration, Settings); + var isRecentEpisode = remoteEpisode.IsRecentEpisode(); if (isRecentEpisode && Settings.RecentTvPriority == (int)DelugePriority.First || @@ -65,6 +67,8 @@ namespace NzbDrone.Core.Download.Clients.Deluge throw new DownloadClientException("Deluge failed to add torrent " + filename); } + _proxy.SetTorrentSeedingConfiguration(actualHash, remoteEpisode.SeedConfiguration, Settings); + if (!Settings.TvCategory.IsNullOrWhiteSpace()) { _proxy.SetLabel(actualHash, Settings.TvCategory, Settings); @@ -110,6 +114,7 @@ namespace NzbDrone.Core.Download.Clients.Deluge var outputPath = _remotePathMappingService.RemapRemoteToLocal(Settings.Host, new OsPath(torrent.DownloadPath)); item.OutputPath = outputPath + torrent.Name; item.RemainingSize = torrent.Size - torrent.BytesDownloaded; + item.SeedRatio = torrent.Ratio; try { @@ -145,8 +150,13 @@ namespace NzbDrone.Core.Download.Clients.Deluge item.Status = DownloadItemStatus.Downloading; } - // Here we detect if Deluge is managing the torrent and whether the seed criteria has been met. This allows drone to delete the torrent as appropriate. - item.CanMoveFiles = item.CanBeRemoved = (torrent.IsAutoManaged && torrent.StopAtRatio && torrent.Ratio >= torrent.StopRatio && torrent.State == DelugeTorrentStatus.Paused); + // Here we detect if Deluge is managing the torrent and whether the seed criteria has been met. + // This allows drone to delete the torrent as appropriate. + item.CanMoveFiles = item.CanBeRemoved = + torrent.IsAutoManaged && + torrent.StopAtRatio && + torrent.Ratio >= torrent.StopRatio && + torrent.State == DelugeTorrentStatus.Paused; items.Add(item); } diff --git a/src/NzbDrone.Core/Download/Clients/Deluge/DelugeProxy.cs b/src/NzbDrone.Core/Download/Clients/Deluge/DelugeProxy.cs index 860a8e8ea..e1b4f2845 100644 --- a/src/NzbDrone.Core/Download/Clients/Deluge/DelugeProxy.cs +++ b/src/NzbDrone.Core/Download/Clients/Deluge/DelugeProxy.cs @@ -151,13 +151,16 @@ namespace NzbDrone.Core.Download.Clients.Deluge public void SetTorrentSeedingConfiguration(string hash, TorrentSeedConfiguration seedConfiguration, DelugeSettings settings) { + if (seedConfiguration == null) return; + + var ratioArguments = new Dictionary(); + if (seedConfiguration.Ratio != null) { - var ratioArguments = new Dictionary(); ratioArguments.Add("stop_ratio", seedConfiguration.Ratio.Value); - - ProcessRequest(settings, "core.set_torrent_options", new string[] { hash }, ratioArguments); } + + ProcessRequest(settings, "core.set_torrent_options", new[] { hash }, ratioArguments); } public void AddLabel(string label, DelugeSettings settings) @@ -176,7 +179,7 @@ namespace NzbDrone.Core.Download.Clients.Deluge var requestBuilder = new JsonRpcRequestBuilder(url); requestBuilder.LogResponseContent = true; - + requestBuilder.Resource("json"); requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15); diff --git a/src/NzbDrone.Core/Download/Clients/Deluge/DelugeTorrent.cs b/src/NzbDrone.Core/Download/Clients/Deluge/DelugeTorrent.cs index 5dcdc7549..898c425b4 100644 --- a/src/NzbDrone.Core/Download/Clients/Deluge/DelugeTorrent.cs +++ b/src/NzbDrone.Core/Download/Clients/Deluge/DelugeTorrent.cs @@ -13,7 +13,7 @@ namespace NzbDrone.Core.Download.Clients.Deluge [JsonProperty(PropertyName = "is_finished")] public bool IsFinished { get; set; } - + // Other paths: What is the difference between 'move_completed_path' and 'move_on_completed_path'? /* [JsonProperty(PropertyName = "move_completed_path")] @@ -22,7 +22,7 @@ namespace NzbDrone.Core.Download.Clients.Deluge public String DownloadPathMoveOnCompleted { get; set; } */ - [JsonProperty(PropertyName = "save_path")] + [JsonProperty(PropertyName = "save_path")] public string DownloadPath { get; set; } [JsonProperty(PropertyName = "total_size")] diff --git a/src/NzbDrone.Core/Download/Clients/DownloadStation/TorrentDownloadStation.cs b/src/NzbDrone.Core/Download/Clients/DownloadStation/TorrentDownloadStation.cs index 10c24a10a..9e265165a 100644 --- a/src/NzbDrone.Core/Download/Clients/DownloadStation/TorrentDownloadStation.cs +++ b/src/NzbDrone.Core/Download/Clients/DownloadStation/TorrentDownloadStation.cs @@ -88,6 +88,7 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation TotalSize = torrent.Size, RemainingSize = GetRemainingSize(torrent), RemainingTime = GetRemainingTime(torrent), + SeedRatio = GetSeedRatio(torrent), Status = GetStatus(torrent), Message = GetMessage(torrent), CanMoveFiles = IsCompleted(torrent), @@ -121,7 +122,7 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation { _logger.Debug(e, "Failed to get config from Download Station"); - throw e; + throw; } } @@ -278,6 +279,19 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation return TimeSpan.FromSeconds(remainingSize / downloadSpeed); } + protected double? GetSeedRatio(DownloadStationTask torrent) + { + var couldConvertDownloaded = long.TryParse(torrent.Additional.Transfer["size_downloaded"], out var downloaded); + var couldConvertUploaded = long.TryParse(torrent.Additional.Transfer["size_uploaded"], out var uploaded); + + if (!couldConvertDownloaded || !couldConvertUploaded) + { + return new Nullable(); + } + + return downloaded <= 0 ? 0 : (double) uploaded / downloaded; + } + protected ValidationFailure TestOutputPath() { try diff --git a/src/NzbDrone.Core/Download/Clients/DownloadStation/UsenetDownloadStation.cs b/src/NzbDrone.Core/Download/Clients/DownloadStation/UsenetDownloadStation.cs index f870d4567..632eedcb0 100644 --- a/src/NzbDrone.Core/Download/Clients/DownloadStation/UsenetDownloadStation.cs +++ b/src/NzbDrone.Core/Download/Clients/DownloadStation/UsenetDownloadStation.cs @@ -147,7 +147,7 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation { _logger.Debug(e, "Failed to get config from Download Station"); - throw e; + throw; } } diff --git a/src/NzbDrone.Core/Download/Clients/Hadouken/Hadouken.cs b/src/NzbDrone.Core/Download/Clients/Hadouken/Hadouken.cs index e652cd9e9..1c2d660da 100644 --- a/src/NzbDrone.Core/Download/Clients/Hadouken/Hadouken.cs +++ b/src/NzbDrone.Core/Download/Clients/Hadouken/Hadouken.cs @@ -62,7 +62,9 @@ namespace NzbDrone.Core.Download.Clients.Hadouken RemainingSize = torrent.TotalSize - torrent.DownloadedBytes, RemainingTime = eta, Title = torrent.Name, - TotalSize = torrent.TotalSize + TotalSize = torrent.TotalSize, + SeedRatio = torrent.DownloadedBytes <= 0 ? 0 : + (double) torrent.UploadedBytes / torrent.DownloadedBytes }; if (!string.IsNullOrEmpty(torrent.Error)) diff --git a/src/NzbDrone.Core/Download/Clients/Hadouken/HadoukenProxy.cs b/src/NzbDrone.Core/Download/Clients/Hadouken/HadoukenProxy.cs index 20e60f1fb..e9eb8e651 100644 --- a/src/NzbDrone.Core/Download/Clients/Hadouken/HadoukenProxy.cs +++ b/src/NzbDrone.Core/Download/Clients/Hadouken/HadoukenProxy.cs @@ -138,6 +138,7 @@ namespace NzbDrone.Core.Download.Clients.Hadouken TotalSize = Convert.ToInt64(item[3]), Progress = Convert.ToDouble(item[4]), DownloadedBytes = Convert.ToInt64(item[5]), + UploadedBytes = Convert.ToInt64(item[6]), DownloadRate = Convert.ToInt64(item[9]), Label = Convert.ToString(item[11]), Error = Convert.ToString(item[21]), diff --git a/src/NzbDrone.Core/Download/Clients/Hadouken/Models/HadoukenTorrent.cs b/src/NzbDrone.Core/Download/Clients/Hadouken/Models/HadoukenTorrent.cs index a52180ca2..b84c2b3f5 100644 --- a/src/NzbDrone.Core/Download/Clients/Hadouken/Models/HadoukenTorrent.cs +++ b/src/NzbDrone.Core/Download/Clients/Hadouken/Models/HadoukenTorrent.cs @@ -13,6 +13,7 @@ public bool IsSeeding { get; set; } public long TotalSize { get; set; } public long DownloadedBytes { get; set; } + public long UploadedBytes { get; set; } public long DownloadRate { get; set; } public string Error { get; set; } } diff --git a/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrent.cs b/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrent.cs index 9fb218d75..2e58c9cd9 100644 --- a/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrent.cs +++ b/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrent.cs @@ -108,6 +108,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent item.DownloadClient = Definition.Name; item.RemainingSize = (long)(torrent.Size * (1.0 - torrent.Progress)); item.RemainingTime = GetRemainingTime(torrent); + item.SeedRatio = torrent.Ratio; item.OutputPath = _remotePathMappingService.RemapRemoteToLocal(Settings.Host, new OsPath(torrent.SavePath)); diff --git a/src/NzbDrone.Core/Download/Clients/Transmission/TransmissionBase.cs b/src/NzbDrone.Core/Download/Clients/Transmission/TransmissionBase.cs index 8533f71dc..dd4d8eea4 100644 --- a/src/NzbDrone.Core/Download/Clients/Transmission/TransmissionBase.cs +++ b/src/NzbDrone.Core/Download/Clients/Transmission/TransmissionBase.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Net; using FluentValidation.Results; using NLog; using NzbDrone.Common.Disk; @@ -66,6 +65,9 @@ namespace NzbDrone.Core.Download.Clients.Transmission item.OutputPath = GetOutputPath(outputPath, torrent); item.TotalSize = torrent.TotalSize; item.RemainingSize = torrent.LeftUntilDone; + item.SeedRatio = torrent.DownloadedEver <= 0 ? 0 : + (double) torrent.UploadedEver / torrent.DownloadedEver; + if (torrent.Eta >= 0) { item.RemainingTime = TimeSpan.FromSeconds(torrent.Eta); @@ -96,7 +98,9 @@ namespace NzbDrone.Core.Download.Clients.Transmission item.Status = DownloadItemStatus.Downloading; } - item.CanMoveFiles = item.CanBeRemoved = torrent.Status == TransmissionTorrentStatus.Stopped; + item.CanMoveFiles = item.CanBeRemoved = + torrent.Status == TransmissionTorrentStatus.Stopped && + item.SeedRatio >= torrent.SeedRatioLimit; items.Add(item); } @@ -129,6 +133,7 @@ namespace NzbDrone.Core.Download.Clients.Transmission protected override string AddFromMagnetLink(RemoteEpisode remoteEpisode, string hash, string magnetLink) { _proxy.AddTorrentFromUrl(magnetLink, GetDownloadDirectory(), Settings); + _proxy.SetTorrentSeedingConfiguration(hash, remoteEpisode.SeedConfiguration, Settings); var isRecentEpisode = remoteEpisode.IsRecentEpisode(); @@ -144,6 +149,7 @@ namespace NzbDrone.Core.Download.Clients.Transmission protected override string AddFromTorrentFile(RemoteEpisode remoteEpisode, string hash, string filename, byte[] fileContent) { _proxy.AddTorrentFromData(fileContent, GetDownloadDirectory(), Settings); + _proxy.SetTorrentSeedingConfiguration(hash, remoteEpisode.SeedConfiguration, Settings); var isRecentEpisode = remoteEpisode.IsRecentEpisode(); @@ -174,17 +180,13 @@ namespace NzbDrone.Core.Download.Clients.Transmission { return Settings.TvDirectory; } - else if (Settings.TvCategory.IsNotNullOrWhiteSpace()) - { - var config = _proxy.GetConfig(Settings); - var destDir = (string)config.GetValueOrDefault("download-dir"); - return string.Format("{0}/{1}", destDir.TrimEnd('/'), Settings.TvCategory); - } - else - { - return null; - } + if (!Settings.TvCategory.IsNotNullOrWhiteSpace()) return null; + + var config = _proxy.GetConfig(Settings); + var destDir = (string)config.GetValueOrDefault("download-dir"); + + return $"{destDir.TrimEnd('/')}/{Settings.TvCategory}"; } protected ValidationFailure TestConnection() diff --git a/src/NzbDrone.Core/Download/Clients/Transmission/TransmissionProxy.cs b/src/NzbDrone.Core/Download/Clients/Transmission/TransmissionProxy.cs index 10fc8345a..567001e06 100644 --- a/src/NzbDrone.Core/Download/Clients/Transmission/TransmissionProxy.cs +++ b/src/NzbDrone.Core/Download/Clients/Transmission/TransmissionProxy.cs @@ -37,7 +37,7 @@ namespace NzbDrone.Core.Download.Clients.Transmission _authSessionIDCache = cacheManager.GetCache(GetType(), "authSessionID"); } - + public List GetTorrents(TransmissionSettings settings) { var result = GetTorrentStatus(settings); @@ -77,8 +77,10 @@ namespace NzbDrone.Core.Download.Clients.Transmission public void SetTorrentSeedingConfiguration(string hash, TorrentSeedConfiguration seedConfiguration, TransmissionSettings settings) { + if (seedConfiguration == null) return; + var arguments = new Dictionary(); - arguments.Add("ids", new string[] { hash }); + arguments.Add("ids", new[] { hash }); if (seedConfiguration.Ratio != null) { @@ -167,9 +169,12 @@ namespace NzbDrone.Core.Download.Clients.Transmission "leftUntilDone", "isFinished", "eta", - "errorString" + "errorString", + "uploadedEver", + "downloadedEver", + "seedRatioLimit" }; - + var arguments = new Dictionary(); arguments.Add("fields", fields); @@ -237,7 +242,7 @@ namespace NzbDrone.Core.Download.Clients.Transmission requestBuilder.SetHeader("X-Transmission-Session-Id", sessionId); } - + public TransmissionResponse ProcessRequest(string action, object arguments, TransmissionSettings settings) { try diff --git a/src/NzbDrone.Core/Download/Clients/Transmission/TransmissionTorrent.cs b/src/NzbDrone.Core/Download/Clients/Transmission/TransmissionTorrent.cs index 3845ce0b0..c3369e337 100644 --- a/src/NzbDrone.Core/Download/Clients/Transmission/TransmissionTorrent.cs +++ b/src/NzbDrone.Core/Download/Clients/Transmission/TransmissionTorrent.cs @@ -23,5 +23,11 @@ public int SecondsDownloading { get; set; } public string ErrorString { get; set; } + + public long DownloadedEver { get; set; } + + public long UploadedEver { get; set; } + + public long SeedRatioLimit { get; set; } } } diff --git a/src/NzbDrone.Core/Download/Clients/rTorrent/RTorrent.cs b/src/NzbDrone.Core/Download/Clients/rTorrent/RTorrent.cs index 95fb2db19..535bcd588 100644 --- a/src/NzbDrone.Core/Download/Clients/rTorrent/RTorrent.cs +++ b/src/NzbDrone.Core/Download/Clients/rTorrent/RTorrent.cs @@ -104,6 +104,7 @@ namespace NzbDrone.Core.Download.Clients.RTorrent item.TotalSize = torrent.TotalSize; item.RemainingSize = torrent.RemainingSize; item.Category = torrent.Category; + item.SeedRatio = torrent.Ratio; if (torrent.DownRate > 0) { diff --git a/src/NzbDrone.Core/Download/Clients/uTorrent/UTorrent.cs b/src/NzbDrone.Core/Download/Clients/uTorrent/UTorrent.cs index e02bf646c..40da8f483 100644 --- a/src/NzbDrone.Core/Download/Clients/uTorrent/UTorrent.cs +++ b/src/NzbDrone.Core/Download/Clients/uTorrent/UTorrent.cs @@ -40,6 +40,7 @@ namespace NzbDrone.Core.Download.Clients.UTorrent { _proxy.AddTorrentFromUrl(magnetLink, Settings); _proxy.SetTorrentLabel(hash, Settings.TvCategory, Settings); + _proxy.SetTorrentSeedingConfiguration(hash, remoteEpisode.SeedConfiguration, Settings); var isRecentEpisode = remoteEpisode.IsRecentEpisode(); @@ -58,6 +59,7 @@ namespace NzbDrone.Core.Download.Clients.UTorrent { _proxy.AddTorrentFromFile(filename, fileContent, Settings); _proxy.SetTorrentLabel(hash, Settings.TvCategory, Settings); + _proxy.SetTorrentSeedingConfiguration(hash, remoteEpisode.SeedConfiguration, Settings); var isRecentEpisode = remoteEpisode.IsRecentEpisode(); @@ -94,6 +96,8 @@ namespace NzbDrone.Core.Download.Clients.UTorrent item.Category = torrent.Label; item.DownloadClient = Definition.Name; item.RemainingSize = torrent.Remaining; + item.SeedRatio = torrent.Ratio; + if (torrent.Eta != -1) { item.RemainingTime = TimeSpan.FromSeconds(torrent.Eta); @@ -101,7 +105,7 @@ namespace NzbDrone.Core.Download.Clients.UTorrent var outputPath = _remotePathMappingService.RemapRemoteToLocal(Settings.Host, new OsPath(torrent.RootDownloadPath)); - if (outputPath == null || outputPath.FileName == torrent.Name) + if (outputPath.FileName == torrent.Name) { item.OutputPath = outputPath; } @@ -134,7 +138,9 @@ namespace NzbDrone.Core.Download.Clients.UTorrent } // 'Started' without 'Queued' is when the torrent is 'forced seeding' - item.CanMoveFiles = item.CanBeRemoved = (!torrent.Status.HasFlag(UTorrentTorrentStatus.Queued) && !torrent.Status.HasFlag(UTorrentTorrentStatus.Started)); + item.CanMoveFiles = item.CanBeRemoved = + !torrent.Status.HasFlag(UTorrentTorrentStatus.Queued) && + !torrent.Status.HasFlag(UTorrentTorrentStatus.Started); queueItems.Add(item); } diff --git a/src/NzbDrone.Core/Download/Clients/uTorrent/UTorrentProxy.cs b/src/NzbDrone.Core/Download/Clients/uTorrent/UTorrentProxy.cs index c65e37c28..557ae0e6e 100644 --- a/src/NzbDrone.Core/Download/Clients/uTorrent/UTorrentProxy.cs +++ b/src/NzbDrone.Core/Download/Clients/uTorrent/UTorrentProxy.cs @@ -69,14 +69,14 @@ namespace NzbDrone.Core.Download.Clients.UTorrent return configuration; } - public UTorrentResponse GetTorrents(string cacheID, UTorrentSettings settings) + public UTorrentResponse GetTorrents(string cacheId, UTorrentSettings settings) { var requestBuilder = BuildRequest(settings) .AddQueryParam("list", 1); - if (cacheID.IsNotNullOrWhiteSpace()) + if (cacheId.IsNotNullOrWhiteSpace()) { - requestBuilder.AddQueryParam("cid", cacheID); + requestBuilder.AddQueryParam("cid", cacheId); } var result = ProcessRequest(requestBuilder, settings); @@ -99,17 +99,19 @@ namespace NzbDrone.Core.Download.Clients.UTorrent .Post() .AddQueryParam("action", "add-file") .AddQueryParam("path", string.Empty) - .AddFormUpload("torrent_file", fileName, fileContent, @"application/octet-stream"); + .AddFormUpload("torrent_file", fileName, fileContent); ProcessRequest(requestBuilder, settings); } public void SetTorrentSeedingConfiguration(string hash, TorrentSeedConfiguration seedConfiguration, UTorrentSettings settings) { + if (seedConfiguration == null) return; + var requestBuilder = BuildRequest(settings) .AddQueryParam("action", "setprops") .AddQueryParam("hash", hash); - + requestBuilder.AddQueryParam("s", "seed_override") .AddQueryParam("v", 1); diff --git a/src/NzbDrone.Core/Download/DownloadClientItem.cs b/src/NzbDrone.Core/Download/DownloadClientItem.cs index acd0b0579..3b5922c6a 100644 --- a/src/NzbDrone.Core/Download/DownloadClientItem.cs +++ b/src/NzbDrone.Core/Download/DownloadClientItem.cs @@ -15,6 +15,7 @@ namespace NzbDrone.Core.Download public long TotalSize { get; set; } public long RemainingSize { get; set; } public TimeSpan? RemainingTime { get; set; } + public double? SeedRatio { get; set; } public OsPath OutputPath { get; set; } public string Message { get; set; } diff --git a/src/NzbDrone.Core/Download/DownloadService.cs b/src/NzbDrone.Core/Download/DownloadService.cs index 02f0a8d4e..86d3c324b 100644 --- a/src/NzbDrone.Core/Download/DownloadService.cs +++ b/src/NzbDrone.Core/Download/DownloadService.cs @@ -5,6 +5,7 @@ using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; using NzbDrone.Common.Instrumentation.Extensions; using NzbDrone.Common.TPL; +using NzbDrone.Core.Configuration; using NzbDrone.Core.Download.Clients; using NzbDrone.Core.Exceptions; using NzbDrone.Core.Indexers; @@ -26,6 +27,7 @@ namespace NzbDrone.Core.Download private readonly IIndexerStatusService _indexerStatusService; private readonly IRateLimitService _rateLimitService; private readonly IEventAggregator _eventAggregator; + private readonly ISeedConfigProvider _seedConfigProvider; private readonly Logger _logger; public DownloadService(IProvideDownloadClient downloadClientProvider, @@ -33,6 +35,7 @@ namespace NzbDrone.Core.Download IIndexerStatusService indexerStatusService, IRateLimitService rateLimitService, IEventAggregator eventAggregator, + ISeedConfigProvider seedConfigProvider, Logger logger) { _downloadClientProvider = downloadClientProvider; @@ -40,6 +43,7 @@ namespace NzbDrone.Core.Download _indexerStatusService = indexerStatusService; _rateLimitService = rateLimitService; _eventAggregator = eventAggregator; + _seedConfigProvider = seedConfigProvider; _logger = logger; } @@ -56,6 +60,9 @@ namespace NzbDrone.Core.Download throw new DownloadClientUnavailableException($"{remoteEpisode.Release.DownloadProtocol} Download client isn't configured yet"); } + // Get the seed configuration for this release. + remoteEpisode.SeedConfiguration = _seedConfigProvider.GetSeedConfiguration(remoteEpisode.Release); + // Limit grabs to 2 per second. if (remoteEpisode.Release.DownloadUrl.IsNotNullOrWhiteSpace() && !remoteEpisode.Release.DownloadUrl.StartsWith("magnet:")) { diff --git a/src/NzbDrone.Core/Indexers/BitMeTv/BitMeTvSettings.cs b/src/NzbDrone.Core/Indexers/BitMeTv/BitMeTvSettings.cs index a858192d5..e7d066da8 100644 --- a/src/NzbDrone.Core/Indexers/BitMeTv/BitMeTvSettings.cs +++ b/src/NzbDrone.Core/Indexers/BitMeTv/BitMeTvSettings.cs @@ -47,6 +47,9 @@ namespace NzbDrone.Core.Indexers.BitMeTv [FieldDefinition(4, Type = FieldType.Textbox, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)] public int MinimumSeeders { get; set; } + [FieldDefinition(5, Type = FieldType.Textbox, Label = "Seed Ratio", HelpText = "The ratio a torrent should reach before stopping, empty is download client's default", Advanced = true)] + public double? SeedRatio { get; set; } + public NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); diff --git a/src/NzbDrone.Core/Indexers/BroadcastheNet/BroadcastheNetSettings.cs b/src/NzbDrone.Core/Indexers/BroadcastheNet/BroadcastheNetSettings.cs index 3890fef1f..d259b9273 100644 --- a/src/NzbDrone.Core/Indexers/BroadcastheNet/BroadcastheNetSettings.cs +++ b/src/NzbDrone.Core/Indexers/BroadcastheNet/BroadcastheNetSettings.cs @@ -32,6 +32,9 @@ namespace NzbDrone.Core.Indexers.BroadcastheNet [FieldDefinition(2, Type = FieldType.Textbox, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)] public int MinimumSeeders { get; set; } + [FieldDefinition(3, Type = FieldType.Textbox, Label = "Seed Ratio", HelpText = "The ratio a torrent should reach before stopping, empty is download client's default", Advanced = true)] + public double? SeedRatio { get; set; } + public NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); diff --git a/src/NzbDrone.Core/Indexers/HDBits/HDBitsSettings.cs b/src/NzbDrone.Core/Indexers/HDBits/HDBitsSettings.cs index ed0a51366..1a44e76fc 100644 --- a/src/NzbDrone.Core/Indexers/HDBits/HDBitsSettings.cs +++ b/src/NzbDrone.Core/Indexers/HDBits/HDBitsSettings.cs @@ -35,6 +35,9 @@ namespace NzbDrone.Core.Indexers.HDBits [FieldDefinition(3, Type = FieldType.Textbox, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)] public int MinimumSeeders { get; set; } + [FieldDefinition(4, Type = FieldType.Textbox, Label = "Seed Ratio", HelpText = "The ratio a torrent should reach before stopping, empty is download client's default", Advanced = true)] + public double? SeedRatio { get; set; } + public NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); diff --git a/src/NzbDrone.Core/Indexers/IPTorrents/IPTorrentsSettings.cs b/src/NzbDrone.Core/Indexers/IPTorrents/IPTorrentsSettings.cs index 16d78430b..8fd4f55a6 100644 --- a/src/NzbDrone.Core/Indexers/IPTorrents/IPTorrentsSettings.cs +++ b/src/NzbDrone.Core/Indexers/IPTorrents/IPTorrentsSettings.cs @@ -2,7 +2,6 @@ using FluentValidation; using NzbDrone.Common.Extensions; using NzbDrone.Core.Annotations; -using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.IPTorrents @@ -36,6 +35,9 @@ namespace NzbDrone.Core.Indexers.IPTorrents [FieldDefinition(1, Type = FieldType.Textbox, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)] public int MinimumSeeders { get; set; } + [FieldDefinition(2, Type = FieldType.Textbox, Label = "Seed Ratio", HelpText = "The ratio a torrent should reach before stopping, empty is download client's default", Advanced = true)] + public double? SeedRatio { get; set; } + public NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); diff --git a/src/NzbDrone.Core/Indexers/ITorrentIndexerSettings.cs b/src/NzbDrone.Core/Indexers/ITorrentIndexerSettings.cs index 9ac4fafcb..761a56b5f 100644 --- a/src/NzbDrone.Core/Indexers/ITorrentIndexerSettings.cs +++ b/src/NzbDrone.Core/Indexers/ITorrentIndexerSettings.cs @@ -3,5 +3,7 @@ public interface ITorrentIndexerSettings : IIndexerSettings { int MinimumSeeders { get; set; } + + double? SeedRatio { get; set; } } } diff --git a/src/NzbDrone.Core/Indexers/Nyaa/NyaaSettings.cs b/src/NzbDrone.Core/Indexers/Nyaa/NyaaSettings.cs index 33661c6d4..587b4d15b 100644 --- a/src/NzbDrone.Core/Indexers/Nyaa/NyaaSettings.cs +++ b/src/NzbDrone.Core/Indexers/Nyaa/NyaaSettings.cs @@ -2,6 +2,7 @@ using NzbDrone.Core.Annotations; using NzbDrone.Core.Validation; using System.Text.RegularExpressions; + namespace NzbDrone.Core.Indexers.Nyaa { public class NyaaSettingsValidator : AbstractValidator @@ -33,6 +34,9 @@ namespace NzbDrone.Core.Indexers.Nyaa [FieldDefinition(2, Type = FieldType.Textbox, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)] public int MinimumSeeders { get; set; } + [FieldDefinition(3, Type = FieldType.Textbox, Label = "Seed Ratio", HelpText = "The ratio a torrent should reach before stopping, empty is download client's default", Advanced = true)] + public double? SeedRatio { get; set; } + public NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); diff --git a/src/NzbDrone.Core/Indexers/Rarbg/RarbgSettings.cs b/src/NzbDrone.Core/Indexers/Rarbg/RarbgSettings.cs index 2b4d76020..50f1aa45d 100644 --- a/src/NzbDrone.Core/Indexers/Rarbg/RarbgSettings.cs +++ b/src/NzbDrone.Core/Indexers/Rarbg/RarbgSettings.cs @@ -35,6 +35,9 @@ namespace NzbDrone.Core.Indexers.Rarbg [FieldDefinition(3, Type = FieldType.Textbox, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)] public int MinimumSeeders { get; set; } + [FieldDefinition(4, Type = FieldType.Textbox, Label = "Seed Ratio", HelpText = "The ratio a torrent should reach before stopping, empty is download client's default", Advanced = true)] + public double? SeedRatio { get; set; } + public NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); diff --git a/src/NzbDrone.Core/Indexers/TorrentRss/TorrentRssIndexerSettings.cs b/src/NzbDrone.Core/Indexers/TorrentRss/TorrentRssIndexerSettings.cs index 8c24f9ba4..5ba3282c6 100644 --- a/src/NzbDrone.Core/Indexers/TorrentRss/TorrentRssIndexerSettings.cs +++ b/src/NzbDrone.Core/Indexers/TorrentRss/TorrentRssIndexerSettings.cs @@ -35,6 +35,9 @@ namespace NzbDrone.Core.Indexers.TorrentRss [FieldDefinition(3, Type = FieldType.Textbox, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)] public int MinimumSeeders { get; set; } + [FieldDefinition(4, Type = FieldType.Textbox, Label = "Seed Ratio", HelpText = "The ratio a torrent should reach before stopping, empty is download client's default", Advanced = true)] + public double? SeedRatio { get; set; } + public NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(validator.Validate(this)); diff --git a/src/NzbDrone.Core/Indexers/Torrentleech/TorrentleechSettings.cs b/src/NzbDrone.Core/Indexers/Torrentleech/TorrentleechSettings.cs index f7b06ec59..8f3c5203e 100644 --- a/src/NzbDrone.Core/Indexers/Torrentleech/TorrentleechSettings.cs +++ b/src/NzbDrone.Core/Indexers/Torrentleech/TorrentleechSettings.cs @@ -32,6 +32,9 @@ namespace NzbDrone.Core.Indexers.Torrentleech [FieldDefinition(2, Type = FieldType.Textbox, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)] public int MinimumSeeders { get; set; } + [FieldDefinition(3, Type = FieldType.Textbox, Label = "Seed Ratio", HelpText = "The ratio a torrent should reach before stopping, empty is download client's default", Advanced = true)] + public double? SeedRatio { get; set; } + public NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); diff --git a/src/NzbDrone.Core/Indexers/Torznab/TorznabSettings.cs b/src/NzbDrone.Core/Indexers/Torznab/TorznabSettings.cs index bbbfcfce5..d1dc0ed9f 100644 --- a/src/NzbDrone.Core/Indexers/Torznab/TorznabSettings.cs +++ b/src/NzbDrone.Core/Indexers/Torznab/TorznabSettings.cs @@ -60,6 +60,9 @@ namespace NzbDrone.Core.Indexers.Torznab [FieldDefinition(6, Type = FieldType.Textbox, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)] public int MinimumSeeders { get; set; } + [FieldDefinition(7, Type = FieldType.Textbox, Label = "Seed Ratio", HelpText = "The ratio a torrent should reach before stopping, empty is download client's default", Advanced = true)] + public double? SeedRatio { get; set; } + public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); diff --git a/src/NzbDrone.Core/NzbDrone.Core.csproj b/src/NzbDrone.Core/NzbDrone.Core.csproj index 6f5f1fcf0..c69d1bd27 100644 --- a/src/NzbDrone.Core/NzbDrone.Core.csproj +++ b/src/NzbDrone.Core/NzbDrone.Core.csproj @@ -142,7 +142,9 @@ + + diff --git a/src/NzbDrone.Core/Parser/Model/RemoteEpisode.cs b/src/NzbDrone.Core/Parser/Model/RemoteEpisode.cs index 319606781..3b99f250c 100644 --- a/src/NzbDrone.Core/Parser/Model/RemoteEpisode.cs +++ b/src/NzbDrone.Core/Parser/Model/RemoteEpisode.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using NzbDrone.Core.Download.Clients; using NzbDrone.Core.Tv; namespace NzbDrone.Core.Parser.Model @@ -12,6 +13,7 @@ namespace NzbDrone.Core.Parser.Model public Series Series { get; set; } public List Episodes { get; set; } public bool DownloadAllowed { get; set; } + public TorrentSeedConfiguration SeedConfiguration { get; set; } public bool IsRecentEpisode() { @@ -23,4 +25,4 @@ namespace NzbDrone.Core.Parser.Model return Release.Title; } } -} \ No newline at end of file +}