From a41b5723d4d87c8f8b19438f5bbb776e157f9a61 Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Tue, 14 Mar 2017 20:29:04 -0700 Subject: [PATCH] New: Ability to set minimum seeders on a per indexer basis --- .../Search/TorrentSeedingSpecification.cs | 38 -------------- .../TorrentSeedingSpecification.cs | 51 +++++++++++++++++++ .../Indexers/BitMeTv/BitMeTvSettings.cs | 9 ++-- .../BroadcastheNet/BroadcastheNetSettings.cs | 9 ++-- .../Indexers/HDBits/HDBitsSettings.cs | 7 ++- .../Indexers/IIndexerSettings.cs | 6 +-- .../Indexers/IPTorrents/IPTorrentsSettings.cs | 8 ++- .../Indexers/ITorrentIndexerSettings.cs | 7 +++ src/NzbDrone.Core/Indexers/IndexerDefaults.cs | 7 +++ .../Indexers/Newznab/NewznabSettings.cs | 5 +- .../Indexers/Nyaa/NyaaSettings.cs | 7 ++- .../Indexers/Rarbg/RarbgSettings.cs | 9 ++-- .../TorrentRss/TorrentRssIndexerSettings.cs | 9 ++-- .../Torrentleech/TorrentleechSettings.cs | 9 ++-- .../Indexers/Torznab/TorznabSettings.cs | 13 ++++- src/NzbDrone.Core/NzbDrone.Core.csproj | 4 +- 16 files changed, 130 insertions(+), 68 deletions(-) delete mode 100644 src/NzbDrone.Core/DecisionEngine/Specifications/Search/TorrentSeedingSpecification.cs create mode 100644 src/NzbDrone.Core/DecisionEngine/Specifications/TorrentSeedingSpecification.cs create mode 100644 src/NzbDrone.Core/Indexers/ITorrentIndexerSettings.cs create mode 100644 src/NzbDrone.Core/Indexers/IndexerDefaults.cs diff --git a/src/NzbDrone.Core/DecisionEngine/Specifications/Search/TorrentSeedingSpecification.cs b/src/NzbDrone.Core/DecisionEngine/Specifications/Search/TorrentSeedingSpecification.cs deleted file mode 100644 index 65230ef12..000000000 --- a/src/NzbDrone.Core/DecisionEngine/Specifications/Search/TorrentSeedingSpecification.cs +++ /dev/null @@ -1,38 +0,0 @@ -using NLog; -using NzbDrone.Core.IndexerSearch.Definitions; -using NzbDrone.Core.Parser.Model; - -namespace NzbDrone.Core.DecisionEngine.Specifications.Search -{ - public class TorrentSeedingSpecification : IDecisionEngineSpecification - { - private readonly Logger _logger; - - public TorrentSeedingSpecification(Logger logger) - { - _logger = logger; - } - - public SpecificationPriority Priority => SpecificationPriority.Default; - public RejectionType Type => RejectionType.Permanent; - - - public Decision IsSatisfiedBy(RemoteEpisode remoteEpisode, SearchCriteriaBase searchCriteria) - { - var torrentInfo = remoteEpisode.Release as TorrentInfo; - - if (torrentInfo == null) - { - return Decision.Accept(); - } - - if (torrentInfo.Seeders != null && torrentInfo.Seeders < 1) - { - _logger.Debug("Not enough seeders. ({0})", torrentInfo.Seeders); - return Decision.Reject("Not enough seeders. ({0})", torrentInfo.Seeders); - } - - return Decision.Accept(); - } - } -} diff --git a/src/NzbDrone.Core/DecisionEngine/Specifications/TorrentSeedingSpecification.cs b/src/NzbDrone.Core/DecisionEngine/Specifications/TorrentSeedingSpecification.cs new file mode 100644 index 000000000..f095170c4 --- /dev/null +++ b/src/NzbDrone.Core/DecisionEngine/Specifications/TorrentSeedingSpecification.cs @@ -0,0 +1,51 @@ +using System.Linq; +using NLog; +using NzbDrone.Common.Reflection; +using NzbDrone.Core.Indexers; +using NzbDrone.Core.IndexerSearch.Definitions; +using NzbDrone.Core.Parser.Model; + +namespace NzbDrone.Core.DecisionEngine.Specifications.Search +{ + public class TorrentSeedingSpecification : IDecisionEngineSpecification + { + private readonly IndexerFactory _indexerFactory; + private readonly Logger _logger; + + public TorrentSeedingSpecification(IndexerFactory indexerFactory, Logger logger) + { + _indexerFactory = indexerFactory; + _logger = logger; + } + + public SpecificationPriority Priority => SpecificationPriority.Default; + public RejectionType Type => RejectionType.Permanent; + + + public Decision IsSatisfiedBy(RemoteEpisode remoteEpisode, SearchCriteriaBase searchCriteria) + { + var torrentInfo = remoteEpisode.Release as TorrentInfo; + + if (torrentInfo == null) + { + return Decision.Accept(); + } + + var indexer = _indexerFactory.Get(torrentInfo.IndexerId); + var torrentIndexerSettings = indexer.Settings as ITorrentIndexerSettings; + + if (torrentIndexerSettings != null) + { + var minimumSeeders = torrentIndexerSettings.MinimumSeeders; + + if (torrentInfo.Seeders.HasValue && torrentInfo.Seeders.Value < minimumSeeders) + { + _logger.Debug("Not enough seeders: {0}. Minimum seeders: {1}", torrentInfo.Seeders, minimumSeeders); + return Decision.Reject("Not enough seeders: {0}. Minimum seeders: {1}", torrentInfo.Seeders, minimumSeeders); + } + } + + return Decision.Accept(); + } + } +} diff --git a/src/NzbDrone.Core/Indexers/BitMeTv/BitMeTvSettings.cs b/src/NzbDrone.Core/Indexers/BitMeTv/BitMeTvSettings.cs index 843dac050..a858192d5 100644 --- a/src/NzbDrone.Core/Indexers/BitMeTv/BitMeTvSettings.cs +++ b/src/NzbDrone.Core/Indexers/BitMeTv/BitMeTvSettings.cs @@ -1,7 +1,6 @@ -using System.Text.RegularExpressions; +using System.Text.RegularExpressions; using FluentValidation; using NzbDrone.Core.Annotations; -using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.BitMeTv @@ -23,13 +22,14 @@ public BitMeTvSettingsValidator() } } - public class BitMeTvSettings : IIndexerSettings + public class BitMeTvSettings : ITorrentIndexerSettings { private static readonly BitMeTvSettingsValidator Validator = new BitMeTvSettingsValidator(); public BitMeTvSettings() { BaseUrl = "https://www.bitmetv.org"; + MinimumSeeders = IndexerDefaults.MINIMUM_SEEDERS; } [FieldDefinition(0, Label = "Website URL")] @@ -44,6 +44,9 @@ public BitMeTvSettings() [FieldDefinition(3, Label = "Cookie", HelpText = "BitMeTv uses a login cookie needed to access the rss, you'll have to retrieve it via a browser.")] public string Cookie { get; set; } + [FieldDefinition(4, Type = FieldType.Textbox, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)] + public int MinimumSeeders { 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 1c3f8ae13..3890fef1f 100644 --- a/src/NzbDrone.Core/Indexers/BroadcastheNet/BroadcastheNetSettings.cs +++ b/src/NzbDrone.Core/Indexers/BroadcastheNet/BroadcastheNetSettings.cs @@ -1,6 +1,5 @@ -using FluentValidation; +using FluentValidation; using NzbDrone.Core.Annotations; -using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.BroadcastheNet @@ -14,13 +13,14 @@ public BroadcastheNetSettingsValidator() } } - public class BroadcastheNetSettings : IIndexerSettings + public class BroadcastheNetSettings : ITorrentIndexerSettings { private static readonly BroadcastheNetSettingsValidator Validator = new BroadcastheNetSettingsValidator(); public BroadcastheNetSettings() { BaseUrl = "http://api.broadcasthe.net/"; + MinimumSeeders = IndexerDefaults.MINIMUM_SEEDERS; } [FieldDefinition(0, Label = "API URL", Advanced = true, HelpText = "Do not change this unless you know what you're doing. Since your API key will be sent to that host.")] @@ -29,6 +29,9 @@ public BroadcastheNetSettings() [FieldDefinition(1, Label = "API Key")] public string ApiKey { get; set; } + [FieldDefinition(2, Type = FieldType.Textbox, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)] + public int MinimumSeeders { 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 802b5e7d1..fb2890c9c 100644 --- a/src/NzbDrone.Core/Indexers/HDBits/HDBitsSettings.cs +++ b/src/NzbDrone.Core/Indexers/HDBits/HDBitsSettings.cs @@ -1,6 +1,5 @@ using FluentValidation; using NzbDrone.Core.Annotations; -using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.HDBits @@ -14,13 +13,14 @@ public HDBitsSettingsValidator() } } - public class HDBitsSettings : IIndexerSettings + public class HDBitsSettings : ITorrentIndexerSettings { private static readonly HDBitsSettingsValidator Validator = new HDBitsSettingsValidator(); public HDBitsSettings() { BaseUrl = "https://hdbits.org"; + MinimumSeeders = IndexerDefaults.MINIMUM_SEEDERS; } [FieldDefinition(0, Label = "Username")] @@ -32,6 +32,9 @@ public HDBitsSettings() [FieldDefinition(2, Label = "API URL", Advanced = true, HelpText = "Do not change this unless you know what you're doing. Since your API key will be sent to that host.")] public string BaseUrl { get; set; } + [FieldDefinition(3, Type = FieldType.Textbox, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)] + public int MinimumSeeders { get; set; } + public NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); diff --git a/src/NzbDrone.Core/Indexers/IIndexerSettings.cs b/src/NzbDrone.Core/Indexers/IIndexerSettings.cs index 85731eb23..87e7f03d2 100644 --- a/src/NzbDrone.Core/Indexers/IIndexerSettings.cs +++ b/src/NzbDrone.Core/Indexers/IIndexerSettings.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using NzbDrone.Core.ThingiProvider; +using NzbDrone.Core.ThingiProvider; namespace NzbDrone.Core.Indexers { diff --git a/src/NzbDrone.Core/Indexers/IPTorrents/IPTorrentsSettings.cs b/src/NzbDrone.Core/Indexers/IPTorrents/IPTorrentsSettings.cs index e3e7993d8..16d78430b 100644 --- a/src/NzbDrone.Core/Indexers/IPTorrents/IPTorrentsSettings.cs +++ b/src/NzbDrone.Core/Indexers/IPTorrents/IPTorrentsSettings.cs @@ -1,4 +1,4 @@ -using System.Text.RegularExpressions; +using System.Text.RegularExpressions; using FluentValidation; using NzbDrone.Common.Extensions; using NzbDrone.Core.Annotations; @@ -21,17 +21,21 @@ public IPTorrentsSettingsValidator() } } - public class IPTorrentsSettings : IIndexerSettings + public class IPTorrentsSettings : ITorrentIndexerSettings { private static readonly IPTorrentsSettingsValidator Validator = new IPTorrentsSettingsValidator(); public IPTorrentsSettings() { + MinimumSeeders = IndexerDefaults.MINIMUM_SEEDERS; } [FieldDefinition(0, Label = "Feed URL", HelpText = "The full RSS feed url generated by IPTorrents, using only the categories you selected (HD, SD, x264, etc ...)")] public string BaseUrl { get; set; } + [FieldDefinition(1, Type = FieldType.Textbox, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)] + public int MinimumSeeders { 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 new file mode 100644 index 000000000..9ac4fafcb --- /dev/null +++ b/src/NzbDrone.Core/Indexers/ITorrentIndexerSettings.cs @@ -0,0 +1,7 @@ +namespace NzbDrone.Core.Indexers +{ + public interface ITorrentIndexerSettings : IIndexerSettings + { + int MinimumSeeders { get; set; } + } +} diff --git a/src/NzbDrone.Core/Indexers/IndexerDefaults.cs b/src/NzbDrone.Core/Indexers/IndexerDefaults.cs new file mode 100644 index 000000000..134126fab --- /dev/null +++ b/src/NzbDrone.Core/Indexers/IndexerDefaults.cs @@ -0,0 +1,7 @@ +namespace NzbDrone.Core.Indexers +{ + public static class IndexerDefaults + { + public const int MINIMUM_SEEDERS = 1; + } +} diff --git a/src/NzbDrone.Core/Indexers/Newznab/NewznabSettings.cs b/src/NzbDrone.Core/Indexers/Newznab/NewznabSettings.cs index 9fc988c10..ead8d1e62 100644 --- a/src/NzbDrone.Core/Indexers/Newznab/NewznabSettings.cs +++ b/src/NzbDrone.Core/Indexers/Newznab/NewznabSettings.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; using FluentValidation; @@ -79,6 +79,9 @@ public NewznabSettings() [FieldDefinition(4, Label = "Additional Parameters", HelpText = "Additional Newznab parameters", Advanced = true)] public string AdditionalParameters { get; set; } + // Field 5 is used by TorznabSettings MinimumSeeders + // If you need to add another field here, update TorznabSettings as well and this comment + public virtual NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); diff --git a/src/NzbDrone.Core/Indexers/Nyaa/NyaaSettings.cs b/src/NzbDrone.Core/Indexers/Nyaa/NyaaSettings.cs index 83ef2c60a..105686a9b 100644 --- a/src/NzbDrone.Core/Indexers/Nyaa/NyaaSettings.cs +++ b/src/NzbDrone.Core/Indexers/Nyaa/NyaaSettings.cs @@ -1,6 +1,5 @@ using FluentValidation; using NzbDrone.Core.Annotations; -using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; using System.Text.RegularExpressions; namespace NzbDrone.Core.Indexers.Nyaa @@ -14,7 +13,7 @@ public NyaaSettingsValidator() } } - public class NyaaSettings : IIndexerSettings + public class NyaaSettings : ITorrentIndexerSettings { private static readonly NyaaSettingsValidator Validator = new NyaaSettingsValidator(); @@ -22,6 +21,7 @@ public NyaaSettings() { BaseUrl = "https://www.nyaa.se"; AdditionalParameters = "&cats=1_37&filter=1"; + MinimumSeeders = IndexerDefaults.MINIMUM_SEEDERS; } [FieldDefinition(0, Label = "Website URL")] @@ -30,6 +30,9 @@ public NyaaSettings() [FieldDefinition(1, Label = "Additional Parameters", Advanced = true, HelpText = "Please note if you change the category you will have to add required/restricted rules about the subgroups to avoid foreign language releases.")] public string AdditionalParameters { get; set; } + [FieldDefinition(2, Type = FieldType.Textbox, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)] + public int MinimumSeeders { 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 c4888b307..2b4d76020 100644 --- a/src/NzbDrone.Core/Indexers/Rarbg/RarbgSettings.cs +++ b/src/NzbDrone.Core/Indexers/Rarbg/RarbgSettings.cs @@ -1,6 +1,5 @@ -using FluentValidation; +using FluentValidation; using NzbDrone.Core.Annotations; -using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Rarbg @@ -13,7 +12,7 @@ public RarbgSettingsValidator() } } - public class RarbgSettings : IIndexerSettings + public class RarbgSettings : ITorrentIndexerSettings { private static readonly RarbgSettingsValidator Validator = new RarbgSettingsValidator(); @@ -21,6 +20,7 @@ public RarbgSettings() { BaseUrl = "https://torrentapi.org"; RankedOnly = false; + MinimumSeeders = IndexerDefaults.MINIMUM_SEEDERS; } [FieldDefinition(0, Label = "API URL", HelpText = "URL to Rarbg api, not the website.")] @@ -32,6 +32,9 @@ public RarbgSettings() [FieldDefinition(2, Type = FieldType.Captcha, Label = "CAPTCHA Token", HelpText = "CAPTCHA Clearance token used to handle CloudFlare Anti-DDOS measures on shared-ip VPNs.")] public string CaptchaToken { get; set; } + [FieldDefinition(3, Type = FieldType.Textbox, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)] + public int MinimumSeeders { 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 57606af46..8c24f9ba4 100644 --- a/src/NzbDrone.Core/Indexers/TorrentRss/TorrentRssIndexerSettings.cs +++ b/src/NzbDrone.Core/Indexers/TorrentRss/TorrentRssIndexerSettings.cs @@ -1,6 +1,5 @@ -using FluentValidation; +using FluentValidation; using NzbDrone.Core.Annotations; -using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.TorrentRss @@ -13,7 +12,7 @@ public TorrentRssIndexerSettingsValidator() } } - public class TorrentRssIndexerSettings : IIndexerSettings + public class TorrentRssIndexerSettings : ITorrentIndexerSettings { private static readonly TorrentRssIndexerSettingsValidator validator = new TorrentRssIndexerSettingsValidator(); @@ -21,6 +20,7 @@ public TorrentRssIndexerSettings() { BaseUrl = string.Empty; AllowZeroSize = false; + MinimumSeeders = IndexerDefaults.MINIMUM_SEEDERS; } [FieldDefinition(0, Label = "Full RSS Feed URL")] @@ -32,6 +32,9 @@ public TorrentRssIndexerSettings() [FieldDefinition(2, Type = FieldType.Checkbox, Label = "Allow Zero Size", HelpText="Enabling this will allow you to use feeds that don't specify release size, but be careful, size related checks will not be performed.")] public bool AllowZeroSize { get; set; } + [FieldDefinition(3, Type = FieldType.Textbox, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)] + public int MinimumSeeders { 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 18392c520..f7b06ec59 100644 --- a/src/NzbDrone.Core/Indexers/Torrentleech/TorrentleechSettings.cs +++ b/src/NzbDrone.Core/Indexers/Torrentleech/TorrentleechSettings.cs @@ -1,6 +1,5 @@ -using FluentValidation; +using FluentValidation; using NzbDrone.Core.Annotations; -using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Torrentleech @@ -14,13 +13,14 @@ public TorrentleechSettingsValidator() } } - public class TorrentleechSettings : IIndexerSettings + public class TorrentleechSettings : ITorrentIndexerSettings { private static readonly TorrentleechSettingsValidator Validator = new TorrentleechSettingsValidator(); public TorrentleechSettings() { BaseUrl = "http://rss.torrentleech.org"; + MinimumSeeders = IndexerDefaults.MINIMUM_SEEDERS; } [FieldDefinition(0, Label = "Website URL")] @@ -29,6 +29,9 @@ public TorrentleechSettings() [FieldDefinition(1, Label = "API Key")] public string ApiKey { get; set; } + [FieldDefinition(2, Type = FieldType.Textbox, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)] + public int MinimumSeeders { 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 9a328d6b6..7e847c294 100644 --- a/src/NzbDrone.Core/Indexers/Torznab/TorznabSettings.cs +++ b/src/NzbDrone.Core/Indexers/Torznab/TorznabSettings.cs @@ -1,8 +1,9 @@ -using System.Linq; +using System.Linq; using System.Text.RegularExpressions; using FluentValidation; using FluentValidation.Results; using NzbDrone.Common.Extensions; +using NzbDrone.Core.Annotations; using NzbDrone.Core.Indexers.Newznab; using NzbDrone.Core.Validation; @@ -46,10 +47,18 @@ public TorznabSettingsValidator() } } - public class TorznabSettings : NewznabSettings + public class TorznabSettings : NewznabSettings, ITorrentIndexerSettings { private static readonly TorznabSettingsValidator Validator = new TorznabSettingsValidator(); + public TorznabSettings() + { + MinimumSeeders = IndexerDefaults.MINIMUM_SEEDERS; + } + + [FieldDefinition(5, Type = FieldType.Textbox, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)] + public int MinimumSeeders { 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 a22cd6751..25b4ece55 100644 --- a/src/NzbDrone.Core/NzbDrone.Core.csproj +++ b/src/NzbDrone.Core/NzbDrone.Core.csproj @@ -345,7 +345,7 @@ - + @@ -630,6 +630,7 @@ + @@ -645,6 +646,7 @@ +