From 4d745d360013e6be0cc588664f6ba746a0a404d2 Mon Sep 17 00:00:00 2001 From: Devin Buhl Date: Sat, 25 Feb 2017 11:34:07 -0500 Subject: [PATCH] Patch/updates (#887) * Update HDBits internal logic * TMDb List validation * Add Trakt validation, update rest to implement IProviderConfig * Update wording --- .../Indexers/HDBits/HDBitsApi.cs | 2 +- .../Indexers/HDBits/HDBitsParser.cs | 10 ++-- .../CouchPotato/CouchPotatoSettings.cs | 11 +++- src/NzbDrone.Core/NetImport/NetImportBase.cs | 8 +-- .../NetImport/RSSImport/RSSImportSettings.cs | 23 ++++++-- .../NetImport/StevenLu/StevenLuSettings.cs | 24 +++++++- .../NetImport/TMDb/TMDbSettings.cs | 55 ++++++++++++++++--- .../NetImport/Trakt/TraktSettings.cs | 44 +++++++++++++-- 8 files changed, 143 insertions(+), 34 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/HDBits/HDBitsApi.cs b/src/NzbDrone.Core/Indexers/HDBits/HDBitsApi.cs index e6c58a658..bf8b2e784 100644 --- a/src/NzbDrone.Core/Indexers/HDBits/HDBitsApi.cs +++ b/src/NzbDrone.Core/Indexers/HDBits/HDBitsApi.cs @@ -20,7 +20,7 @@ namespace NzbDrone.Core.Indexers.HDBits public int[] Medium { get; set; } - public int Origin { get; set; } + public int? Origin { get; set; } [JsonProperty(PropertyName = "imdb")] public ImdbInfo ImdbInfo { get; set; } diff --git a/src/NzbDrone.Core/Indexers/HDBits/HDBitsParser.cs b/src/NzbDrone.Core/Indexers/HDBits/HDBitsParser.cs index ebf9b4e2d..63be85a7e 100644 --- a/src/NzbDrone.Core/Indexers/HDBits/HDBitsParser.cs +++ b/src/NzbDrone.Core/Indexers/HDBits/HDBitsParser.cs @@ -51,6 +51,8 @@ namespace NzbDrone.Core.Indexers.HDBits foreach (var result in queryResults) { var id = result.Id; + var internalRelease = (result.TypeOrigin == 1 ? true : false); + torrentInfos.Add(new HDBitsInfo() { Guid = string.Format("HDBits-{0}", id), @@ -62,7 +64,7 @@ namespace NzbDrone.Core.Indexers.HDBits Seeders = result.Seeders, Peers = result.Leechers + result.Seeders, PublishDate = result.Added.ToUniversalTime(), - Internal = (result.TypeOrigin == 1 ? true : false) + Internal = internalRelease }); } @@ -75,11 +77,7 @@ namespace NzbDrone.Core.Indexers.HDBits .ToArray(); } - // order by date - return - torrentInfos - .OrderByDescending(o => o.PublishDate) - .ToArray(); + return torrentInfos.ToArray(); } private string GetDownloadUrl(string torrentId) diff --git a/src/NzbDrone.Core/NetImport/CouchPotato/CouchPotatoSettings.cs b/src/NzbDrone.Core/NetImport/CouchPotato/CouchPotatoSettings.cs index 60b0b8c17..5e05621fb 100644 --- a/src/NzbDrone.Core/NetImport/CouchPotato/CouchPotatoSettings.cs +++ b/src/NzbDrone.Core/NetImport/CouchPotato/CouchPotatoSettings.cs @@ -1,5 +1,6 @@ using FluentValidation; using NzbDrone.Core.Annotations; +using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; namespace NzbDrone.Core.NetImport.CouchPotato @@ -15,8 +16,10 @@ namespace NzbDrone.Core.NetImport.CouchPotato } } - public class CouchPotatoSettings : NetImportBaseSettings + public class CouchPotatoSettings : IProviderConfig { + private static readonly CouchPotatoSettingsValidator Validator = new CouchPotatoSettingsValidator(); + public CouchPotatoSettings() { Link = "http://localhost"; @@ -26,7 +29,7 @@ namespace NzbDrone.Core.NetImport.CouchPotato } [FieldDefinition(0, Label = "CouchPotato URL", HelpText = "Link to your CoouchPootato.")] - public new string Link { get; set; } + public string Link { get; set; } [FieldDefinition(1, Label = "CouchPotato Port", HelpText = "Port your CoouchPootato uses.")] public int Port { get; set; } @@ -41,6 +44,10 @@ namespace NzbDrone.Core.NetImport.CouchPotato [FieldDefinition(4, Label = "Only Wanted", HelpText = "Only add wanted movies.", Type = FieldType.Checkbox)] public bool OnlyActive { get; set; } + public NzbDroneValidationResult Validate() + { + return new NzbDroneValidationResult(Validator.Validate(this)); + } } } diff --git a/src/NzbDrone.Core/NetImport/NetImportBase.cs b/src/NzbDrone.Core/NetImport/NetImportBase.cs index f9ff9f825..29174f7c8 100644 --- a/src/NzbDrone.Core/NetImport/NetImportBase.cs +++ b/src/NzbDrone.Core/NetImport/NetImportBase.cs @@ -17,10 +17,11 @@ namespace NzbDrone.Core.NetImport protected readonly Logger _logger; public abstract string Name { get; } - public abstract bool Enabled { get; } public abstract bool EnableAuto { get; } + public abstract IList Fetch(); + public NetImportBase(IConfigService configService, IParsingService parsingService, Logger logger) { _configService = configService; @@ -31,7 +32,6 @@ namespace NzbDrone.Core.NetImport public Type ConfigContract => typeof(TSettings); public virtual ProviderMessage Message => null; - public virtual IEnumerable DefaultDefinitions { get @@ -44,7 +44,7 @@ namespace NzbDrone.Core.NetImport Enabled = config.Validate().IsValid && Enabled, EnableAuto = true, ProfileId = 1, - MinimumAvailability = MovieStatusType.PreDB, + MinimumAvailability = MovieStatusType.Announced, Implementation = GetType().Name, Settings = config }; @@ -57,8 +57,6 @@ namespace NzbDrone.Core.NetImport protected TSettings Settings => (TSettings)Definition.Settings; - public abstract IList Fetch(); - public ValidationResult Test() { var failures = new List(); diff --git a/src/NzbDrone.Core/NetImport/RSSImport/RSSImportSettings.cs b/src/NzbDrone.Core/NetImport/RSSImport/RSSImportSettings.cs index 52ae1b4c6..254b144fc 100644 --- a/src/NzbDrone.Core/NetImport/RSSImport/RSSImportSettings.cs +++ b/src/NzbDrone.Core/NetImport/RSSImport/RSSImportSettings.cs @@ -1,11 +1,21 @@ -using NzbDrone.Core.Annotations; +using FluentValidation; +using NzbDrone.Core.Annotations; +using NzbDrone.Core.ThingiProvider; +using NzbDrone.Core.Validation; namespace NzbDrone.Core.NetImport.RSSImport { + public class RSSImportSettingsValidator : AbstractValidator + { + public RSSImportSettingsValidator() + { + RuleFor(c => c.Link).ValidRootUrl(); + } + } - public class RSSImportSettings : NetImportBaseSettings + public class RSSImportSettings : IProviderConfig { - //private const string helpLink = "https://imdb.com"; + private static readonly RSSImportSettingsValidator Validator = new RSSImportSettingsValidator(); public RSSImportSettings() { @@ -13,6 +23,11 @@ namespace NzbDrone.Core.NetImport.RSSImport } [FieldDefinition(0, Label = "RSS Link", HelpText = "Link to the rss feed of movies.")] - public new string Link { get; set; } + public string Link { get; set; } + + public NzbDroneValidationResult Validate() + { + return new NzbDroneValidationResult(Validator.Validate(this)); + } } } diff --git a/src/NzbDrone.Core/NetImport/StevenLu/StevenLuSettings.cs b/src/NzbDrone.Core/NetImport/StevenLu/StevenLuSettings.cs index 127fe37ca..89fcdd488 100644 --- a/src/NzbDrone.Core/NetImport/StevenLu/StevenLuSettings.cs +++ b/src/NzbDrone.Core/NetImport/StevenLu/StevenLuSettings.cs @@ -1,17 +1,35 @@ -using NzbDrone.Core.Annotations; +using FluentValidation; +using NzbDrone.Core.Annotations; +using NzbDrone.Core.ThingiProvider; +using NzbDrone.Core.Validation; namespace NzbDrone.Core.NetImport.StevenLu { - public class StevenLuSettings : NetImportBaseSettings + public class StevenLuSettingsValidator : AbstractValidator { + public StevenLuSettingsValidator() + { + RuleFor(c => c.Link).ValidRootUrl(); + } + } + + public class StevenLuSettings : IProviderConfig + { + private static readonly StevenLuSettingsValidator Validator = new StevenLuSettingsValidator(); + public StevenLuSettings() { Link = "https://s3.amazonaws.com/popular-movies/movies.json"; } [FieldDefinition(0, Label = "URL", HelpText = "Don't change this unless you know what you are doing.")] - public new string Link { get; set; } + public string Link { get; set; } + + public NzbDroneValidationResult Validate() + { + return new NzbDroneValidationResult(Validator.Validate(this)); + } } diff --git a/src/NzbDrone.Core/NetImport/TMDb/TMDbSettings.cs b/src/NzbDrone.Core/NetImport/TMDb/TMDbSettings.cs index 505af060a..e194b7fd5 100644 --- a/src/NzbDrone.Core/NetImport/TMDb/TMDbSettings.cs +++ b/src/NzbDrone.Core/NetImport/TMDb/TMDbSettings.cs @@ -1,6 +1,9 @@ using FluentValidation; +using NzbDrone.Common.Extensions; using NzbDrone.Core.Annotations; +using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; +using System.Text.RegularExpressions; namespace NzbDrone.Core.NetImport.TMDb { @@ -10,25 +13,61 @@ namespace NzbDrone.Core.NetImport.TMDb public TMDbSettingsValidator() { RuleFor(c => c.Link).ValidRootUrl(); - RuleFor(c => double.Parse(c.MinVoteAverage)).InclusiveBetween(0, 10); - RuleFor(c => c.MinVotes).GreaterThan(0); + + // Greater than 0 + RuleFor(c => c.ListId) + .Matches(@"^[1-9][0-9]*$", RegexOptions.IgnoreCase) + .When(c => c.ListType == (int)TMDbListType.List) + .WithMessage("List Id is required when using TMDb Lists"); + + // Range 0.0 - 10.0 + RuleFor(c => c.MinVoteAverage) + .Matches(@"^(?!0\d)\d*(\.\d{1})?$", RegexOptions.IgnoreCase) + .When(c => c.MinVoteAverage.IsNotNullOrWhiteSpace()) + .WithMessage("Minimum vote average must be between 0 and 10"); + + // Greater than 0 + RuleFor(c => c.MinVotes) + .Matches(@"^[1-9][0-9]*$", RegexOptions.IgnoreCase) + .When(c => c.MinVotes.IsNotNullOrWhiteSpace()) + .WithMessage("Minimum votes must be greater than 0"); + + // Any valid certification + RuleFor(c => c.Ceritification) + .Matches(@"^\bNR\b|\bG\b|\bPG\b|\bPG\-13\b|\bR\b|\bNC\-17\b$", RegexOptions.IgnoreCase) + .When(c => c.Ceritification.IsNotNullOrWhiteSpace()) + .WithMessage("Not a valid cerification"); + + // CSV of numbers + RuleFor(c => c.IncludeGenreIds) + .Matches(@"^\d+([,]\d+)*$", RegexOptions.IgnoreCase) + .When(c => c.IncludeGenreIds.IsNotNullOrWhiteSpace()) + .WithMessage("Genre Ids must be comma separated number ids"); + + // CSV of numbers + RuleFor(c => c.ExcludeGenreIds) + .Matches(@"^\d+([,]\d+)*$", RegexOptions.IgnoreCase) + .When(c => c.ExcludeGenreIds.IsNotNullOrWhiteSpace()) + .WithMessage("Genre Ids must be comma separated number ids"); + } } - public class TMDbSettings : NetImportBaseSettings + public class TMDbSettings : IProviderConfig { private static readonly TMDbSettingsValidator Validator = new TMDbSettingsValidator(); public TMDbSettings() { Link = "https://api.themoviedb.org"; + ListType = (int)TMDbListType.Popular; MinVoteAverage = "5"; - MinVotes = 1; + MinVotes = "1"; LanguageCode = (int)TMDbLanguageCodes.en; } [FieldDefinition(0, Label = "TMDb API URL", HelpText = "Link to to TMDb API URL, do not change unless you know what you are doing.")] - public new string Link { get; set; } + public string Link { get; set; } [FieldDefinition(1, Label = "List Type", Type = FieldType.Select, SelectOptions = typeof(TMDbListType), HelpText = "Type of list your seeking to import from")] public int ListType { get; set; } @@ -40,9 +79,9 @@ namespace NzbDrone.Core.NetImport.TMDb public string MinVoteAverage { get; set; } [FieldDefinition(4, Label = "Minimum Number of Votes", HelpText = "Filter movies by number of votes")] - public int MinVotes { get; set; } + public string MinVotes { get; set; } - [FieldDefinition(5, Label = "Ceritification", HelpText = "Filter movies by a ceritification (NR,G,PG,PG-13,R,NC-17)")] + [FieldDefinition(5, Label = "Ceritification", HelpText = "Filter movies by a single ceritification (NR,G,PG,PG-13,R,NC-17)")] public string Ceritification { get; set; } [FieldDefinition(6, Label = "Include Genre Ids", HelpText = "Filter movies by TMDb Genre Ids (Comma Separated)")] @@ -54,7 +93,7 @@ namespace NzbDrone.Core.NetImport.TMDb [FieldDefinition(8, Label = "Original Language", Type = FieldType.Select, SelectOptions = typeof(TMDbLanguageCodes), HelpText = "Filter by Language")] public int LanguageCode { get; set; } - public new NzbDroneValidationResult Validate() + public NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); } diff --git a/src/NzbDrone.Core/NetImport/Trakt/TraktSettings.cs b/src/NzbDrone.Core/NetImport/Trakt/TraktSettings.cs index 677bbd36d..cc4d29399 100644 --- a/src/NzbDrone.Core/NetImport/Trakt/TraktSettings.cs +++ b/src/NzbDrone.Core/NetImport/Trakt/TraktSettings.cs @@ -1,6 +1,9 @@ using FluentValidation; +using NzbDrone.Common.Extensions; using NzbDrone.Core.Annotations; +using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; +using System.Text.RegularExpressions; namespace NzbDrone.Core.NetImport.Trakt { @@ -10,26 +13,57 @@ namespace NzbDrone.Core.NetImport.Trakt public TraktSettingsValidator() { RuleFor(c => c.Link).ValidRootUrl(); + + // List name required for UserCustomList + RuleFor(c => c.Listname) + .Matches(@"^[A-Za-z0-9\-_]+$", RegexOptions.IgnoreCase) + .When(c => c.ListType == (int)TraktListType.UserCustomList) + .WithMessage("List name is required when using Custom Trakt Lists"); + + // Username required for UserWatchedList/UserWatchList + RuleFor(c => c.Username) + .Matches(@"^[A-Za-z0-9\-_]+$", RegexOptions.IgnoreCase) + .When(c => c.ListType == (int)TraktListType.UserWatchedList || c.ListType == (int)TraktListType.UserWatchList) + .WithMessage("Username is required when using User Trakt Lists"); + + // Loose validation @TODO + RuleFor(c => c.Rating) + .Matches(@"^\d+\-\d+$", RegexOptions.IgnoreCase) + .When(c => c.Rating.IsNotNullOrWhiteSpace()) + .WithMessage("Not a valid rating"); + + // Any valid certification + RuleFor(c => c.Ceritification) + .Matches(@"^\bNR\b|\bG\b|\bPG\b|\bPG\-13\b|\bR\b|\bNC\-17\b$", RegexOptions.IgnoreCase) + .When(c => c.Ceritification.IsNotNullOrWhiteSpace()) + .WithMessage("Not a valid cerification"); + + // Loose validation @TODO + RuleFor(c => c.Years) + .Matches(@"^\d+(\-\d+)?$", RegexOptions.IgnoreCase) + .When(c => c.Years.IsNotNullOrWhiteSpace()) + .WithMessage("Not a valid year or range of years"); } } - public class TraktSettings : NetImportBaseSettings + public class TraktSettings : IProviderConfig { - private static readonly TraktSettingsValidator Validator = new TraktSettingsValidator(); + public TraktSettings() { Link = "https://api.trakt.tv"; + ListType = (int)TraktListType.Popular; Username = ""; Listname = ""; Rating = "0-100"; Ceritification = "NR,G,PG,PG-13,R,NC-17"; Genres = ""; - Years = "2011-2017"; + Years = ""; } [FieldDefinition(0, Label = "Trakt API URL", HelpText = "Link to to Trakt API URL, do not change unless you know what you are doing.")] - public new string Link { get; set; } + public string Link { get; set; } [FieldDefinition(1, Label = "List Type", Type = FieldType.Select, SelectOptions = typeof(TraktListType), HelpText = "Trakt list type")] public int ListType { get; set; } @@ -53,7 +87,7 @@ namespace NzbDrone.Core.NetImport.Trakt public string Years { get; set; } - public new NzbDroneValidationResult Validate() + public NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); }