diff --git a/src/NzbDrone.Core.Test/Profiles/Releases/PreferredWordService/CalculateFixture.cs b/src/NzbDrone.Core.Test/Profiles/Releases/PreferredWordService/CalculateFixture.cs index 55e7cf476..e39317e40 100644 --- a/src/NzbDrone.Core.Test/Profiles/Releases/PreferredWordService/CalculateFixture.cs +++ b/src/NzbDrone.Core.Test/Profiles/Releases/PreferredWordService/CalculateFixture.cs @@ -55,7 +55,7 @@ namespace NzbDrone.Core.Test.Profiles.Releases.PreferredWordService .Setup(s => s.AllForTags(It.IsAny>())) .Returns(new List()); - Subject.Calculate(_series, _title).Should().Be(0); + Subject.Calculate(_series, _title, 0).Should().Be(0); } [Test] @@ -63,7 +63,7 @@ namespace NzbDrone.Core.Test.Profiles.Releases.PreferredWordService { GivenMatchingTerms(); - Subject.Calculate(_series, _title).Should().Be(0); + Subject.Calculate(_series, _title, 0).Should().Be(0); } [Test] @@ -71,7 +71,7 @@ namespace NzbDrone.Core.Test.Profiles.Releases.PreferredWordService { GivenMatchingTerms("x264"); - Subject.Calculate(_series, _title).Should().Be(5); + Subject.Calculate(_series, _title, 0).Should().Be(5); } [Test] @@ -79,7 +79,7 @@ namespace NzbDrone.Core.Test.Profiles.Releases.PreferredWordService { GivenMatchingTerms("x265"); - Subject.Calculate(_series, _title).Should().Be(-10); + Subject.Calculate(_series, _title, 0).Should().Be(-10); } [Test] @@ -89,7 +89,7 @@ namespace NzbDrone.Core.Test.Profiles.Releases.PreferredWordService GivenMatchingTerms("x264"); - Subject.Calculate(_series, _title).Should().Be(10); + Subject.Calculate(_series, _title, 0).Should().Be(10); } } } diff --git a/src/NzbDrone.Core/DecisionEngine/Specifications/CutoffSpecification.cs b/src/NzbDrone.Core/DecisionEngine/Specifications/CutoffSpecification.cs index 65c8cbe14..64df7ccb5 100644 --- a/src/NzbDrone.Core/DecisionEngine/Specifications/CutoffSpecification.cs +++ b/src/NzbDrone.Core/DecisionEngine/Specifications/CutoffSpecification.cs @@ -41,7 +41,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications languageProfile, file.Quality, file.Language, - _preferredWordServiceCalculator.Calculate(subject.Series, file.GetSceneOrFileName()), + _preferredWordServiceCalculator.Calculate(subject.Series, file.GetSceneOrFileName(), subject.Release.IndexerId), subject.ParsedEpisodeInfo.Quality, subject.PreferredWordScore)) { diff --git a/src/NzbDrone.Core/DecisionEngine/Specifications/QueueSpecification.cs b/src/NzbDrone.Core/DecisionEngine/Specifications/QueueSpecification.cs index e036cbf06..aa3984f59 100644 --- a/src/NzbDrone.Core/DecisionEngine/Specifications/QueueSpecification.cs +++ b/src/NzbDrone.Core/DecisionEngine/Specifications/QueueSpecification.cs @@ -44,7 +44,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications var languageProfile = subject.Series.LanguageProfile.Value; _logger.Debug("Checking if existing release in queue meets cutoff. Queued: {0} - {1}", remoteEpisode.ParsedEpisodeInfo.Quality, remoteEpisode.ParsedEpisodeInfo.Language); - var queuedItemPreferredWordScore = _preferredWordServiceCalculator.Calculate(subject.Series, queueItem.Title); + var queuedItemPreferredWordScore = _preferredWordServiceCalculator.Calculate(subject.Series, queueItem.Title, subject.Release.IndexerId); if (!_upgradableSpecification.CutoffNotMet(qualityProfile, languageProfile, diff --git a/src/NzbDrone.Core/DecisionEngine/Specifications/ReleaseRestrictionsSpecification.cs b/src/NzbDrone.Core/DecisionEngine/Specifications/ReleaseRestrictionsSpecification.cs index 05fa7e40f..8c0125410 100644 --- a/src/NzbDrone.Core/DecisionEngine/Specifications/ReleaseRestrictionsSpecification.cs +++ b/src/NzbDrone.Core/DecisionEngine/Specifications/ReleaseRestrictionsSpecification.cs @@ -31,81 +31,72 @@ namespace NzbDrone.Core.DecisionEngine.Specifications _logger.Debug("Checking if release meets restrictions: {0}", subject); var title = subject.Release.Title; - List restrictions = _releaseProfileService.AllForTags(subject.Series.Tags); + var releaseProfiles = _releaseProfileService.EnabledForTags(subject.Series.Tags, subject.Release.IndexerId); - foreach (ReleaseProfile restriction in restrictions) + var required = releaseProfiles.Where(r => r.Required.IsNotNullOrWhiteSpace()); + var ignored = releaseProfiles.Where(r => r.Ignored.IsNotNullOrWhiteSpace()); + + var keyValueRegex = new Regex(@"\b\w+:\w+\b"); + + foreach (var r in required) { - // TODO: attach Enabled and IndexerId fields to restriction - /*if (!restriction.Enabled || restriction.IndexerId != subject.Release.IndexerId) + var requiredTerms = r.Required.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList(); + + // separate key-value terms and normal terms + var reqKeyValues = requiredTerms.Where(kv => keyValueRegex.IsMatch(kv)).ToList(); + var reqTitleTerms = requiredTerms.Where(t => !keyValueRegex.IsMatch(t)).ToList(); + + // check title terms + var foundTerms = ContainsAny(reqTitleTerms, title); + + // check key-value terms + foreach (var kv in reqKeyValues) { - continue; - }*/ + var key = kv.Split(':')[0]; + var value = kv.Split(':')[1]; - var required = restrictions.Where(r => r.Required.IsNotNullOrWhiteSpace()); - var ignored = restrictions.Where(r => r.Ignored.IsNotNullOrWhiteSpace()); - - var keyValueRegex = new Regex(@"\b\w+:\w+\b"); - - foreach (var r in required) - { - var requiredTerms = r.Required.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList(); - - // separate key-value terms and normal terms - var reqKeyValues = requiredTerms.Where(kv => keyValueRegex.IsMatch(kv)).ToList(); - var reqTitleTerms = requiredTerms.Where(t => !keyValueRegex.IsMatch(t)).ToList(); - - // check title terms - var foundTerms = ContainsAny(reqTitleTerms, title); - - // check key-value terms - foreach (var kv in reqKeyValues) + switch (key) { - var key = kv.Split(':')[0]; - var value = kv.Split(':')[1]; - - switch (key) - { - case "origin": - var origin = subject.Release.Origin; - if (origin.IsNotNullOrWhiteSpace()) + case "origin": + var origin = subject.Release.Origin; + if (origin.IsNotNullOrWhiteSpace()) + { + if (string.Equals(origin, value, StringComparison.InvariantCultureIgnoreCase)) { - if (string.Equals(origin, value, StringComparison.InvariantCultureIgnoreCase)) - { - foundTerms.Add(kv); - } + foundTerms.Add(kv); } - else - { - _logger.Debug("{0} not found in release", key); - } - break; - default: - _logger.Debug("{0} is not a supported key", key); - break; - } + } + else + { + _logger.Debug("{0} not found in release", key); + } + break; + default: + _logger.Debug("{0} is not a supported key", key); + break; + } - } - - if (foundTerms.Empty()) - { - var terms = string.Join(", ", requiredTerms); - _logger.Debug("[{0}] does not contain one of the required terms: {1}", title, terms); - return Decision.Reject("Does not contain one of the required terms: {0}", terms); - } } - - foreach (var r in ignored) + if (foundTerms.Empty()) { - var ignoredTerms = r.Ignored.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList(); + var terms = string.Join(", ", requiredTerms); + _logger.Debug("[{0}] does not contain one of the required terms: {1}", title, terms); + return Decision.Reject("Does not contain one of the required terms: {0}", terms); + } + } - var foundTerms = ContainsAny(ignoredTerms, title); - if (foundTerms.Any()) - { - var terms = string.Join(", ", foundTerms); - _logger.Debug("[{0}] contains these ignored terms: {1}", title, terms); - return Decision.Reject("Contains these ignored terms: {0}", terms); - } + + foreach (var r in ignored) + { + var ignoredTerms = r.Ignored.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList(); + + var foundTerms = ContainsAny(ignoredTerms, title); + if (foundTerms.Any()) + { + var terms = string.Join(", ", foundTerms); + _logger.Debug("[{0}] contains these ignored terms: {1}", title, terms); + return Decision.Reject("Contains these ignored terms: {0}", terms); } } _logger.Debug("[{0}] No restrictions apply, allowing", subject); diff --git a/src/NzbDrone.Core/DecisionEngine/Specifications/RssSync/DelaySpecification.cs b/src/NzbDrone.Core/DecisionEngine/Specifications/RssSync/DelaySpecification.cs index 846b65510..d60b355f5 100644 --- a/src/NzbDrone.Core/DecisionEngine/Specifications/RssSync/DelaySpecification.cs +++ b/src/NzbDrone.Core/DecisionEngine/Specifications/RssSync/DelaySpecification.cs @@ -66,7 +66,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync languageProfile, file.Quality, file.Language, - _preferredWordServiceCalculator.Calculate(subject.Series, file.GetSceneOrFileName()), + _preferredWordServiceCalculator.Calculate(subject.Series, file.GetSceneOrFileName(), subject.Release.IndexerId), subject.ParsedEpisodeInfo.Quality, subject.ParsedEpisodeInfo.Language, subject.PreferredWordScore); diff --git a/src/NzbDrone.Core/DecisionEngine/Specifications/RssSync/HistorySpecification.cs b/src/NzbDrone.Core/DecisionEngine/Specifications/RssSync/HistorySpecification.cs index 9b3129d36..1e8b6da5e 100644 --- a/src/NzbDrone.Core/DecisionEngine/Specifications/RssSync/HistorySpecification.cs +++ b/src/NzbDrone.Core/DecisionEngine/Specifications/RssSync/HistorySpecification.cs @@ -55,7 +55,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync // The series will be the same as the one in history since it's the same episode. // Instead of fetching the series from the DB reuse the known series. - var preferredWordScore = _preferredWordServiceCalculator.Calculate(subject.Series, mostRecent.SourceTitle); + var preferredWordScore = _preferredWordServiceCalculator.Calculate(subject.Series, mostRecent.SourceTitle, subject.Release.IndexerId); var cutoffUnmet = _upgradableSpecification.CutoffNotMet( subject.Series.QualityProfile, diff --git a/src/NzbDrone.Core/DecisionEngine/Specifications/UpgradeDiskSpecification.cs b/src/NzbDrone.Core/DecisionEngine/Specifications/UpgradeDiskSpecification.cs index caf4fbfdb..ba5ed7e15 100644 --- a/src/NzbDrone.Core/DecisionEngine/Specifications/UpgradeDiskSpecification.cs +++ b/src/NzbDrone.Core/DecisionEngine/Specifications/UpgradeDiskSpecification.cs @@ -38,7 +38,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications subject.Series.LanguageProfile, file.Quality, file.Language, - _preferredWordServiceCalculator.Calculate(subject.Series, file.GetSceneOrFileName()), + _preferredWordServiceCalculator.Calculate(subject.Series, file.GetSceneOrFileName(), subject.Release.IndexerId), subject.ParsedEpisodeInfo.Quality, subject.ParsedEpisodeInfo.Language, subject.PreferredWordScore)) diff --git a/src/NzbDrone.Core/Download/Aggregation/Aggregators/AggregatePreferredWordScore.cs b/src/NzbDrone.Core/Download/Aggregation/Aggregators/AggregatePreferredWordScore.cs index 6227ca1e6..5d0a58dd1 100644 --- a/src/NzbDrone.Core/Download/Aggregation/Aggregators/AggregatePreferredWordScore.cs +++ b/src/NzbDrone.Core/Download/Aggregation/Aggregators/AggregatePreferredWordScore.cs @@ -14,7 +14,7 @@ namespace NzbDrone.Core.Download.Aggregation.Aggregators public RemoteEpisode Aggregate(RemoteEpisode remoteEpisode) { - remoteEpisode.PreferredWordScore = _preferredWordServiceCalculator.Calculate(remoteEpisode.Series, remoteEpisode.Release.Title); + remoteEpisode.PreferredWordScore = _preferredWordServiceCalculator.Calculate(remoteEpisode.Series, remoteEpisode.Release.Title, remoteEpisode.Release.IndexerId); return remoteEpisode; } diff --git a/src/NzbDrone.Core/Profiles/Releases/PreferredWordService.cs b/src/NzbDrone.Core/Profiles/Releases/PreferredWordService.cs index 18ca1c9e5..bee590510 100644 --- a/src/NzbDrone.Core/Profiles/Releases/PreferredWordService.cs +++ b/src/NzbDrone.Core/Profiles/Releases/PreferredWordService.cs @@ -8,7 +8,7 @@ namespace NzbDrone.Core.Profiles.Releases { public interface IPreferredWordService { - int Calculate(Series series, string title); + int Calculate(Series series, string title, int indexerId); List GetMatchingPreferredWords(Series series, string title); } @@ -25,11 +25,11 @@ namespace NzbDrone.Core.Profiles.Releases _logger = logger; } - public int Calculate(Series series, string title) + public int Calculate(Series series, string title, int indexerId) { _logger.Trace("Calculating preferred word score for '{0}'", title); - var releaseProfiles = _releaseProfileService.AllForTags(series.Tags); + var releaseProfiles = _releaseProfileService.EnabledForTags(series.Tags, indexerId); var matchingPairs = new List>(); foreach (var releaseProfile in releaseProfiles) @@ -54,7 +54,7 @@ namespace NzbDrone.Core.Profiles.Releases public List GetMatchingPreferredWords(Series series, string title) { - var releaseProfiles = _releaseProfileService.AllForTags(series.Tags); + var releaseProfiles = _releaseProfileService.EnabledForTags(series.Tags, 0); var matchingPairs = new List>(); _logger.Trace("Calculating preferred word score for '{0}'", title); diff --git a/src/NzbDrone.Core/Profiles/Releases/ReleaseProfileService.cs b/src/NzbDrone.Core/Profiles/Releases/ReleaseProfileService.cs index 7ae1b79eb..f7bab3ae0 100644 --- a/src/NzbDrone.Core/Profiles/Releases/ReleaseProfileService.cs +++ b/src/NzbDrone.Core/Profiles/Releases/ReleaseProfileService.cs @@ -10,6 +10,7 @@ namespace NzbDrone.Core.Profiles.Releases List All(); List AllForTag(int tagId); List AllForTags(HashSet tagIds); + List EnabledForTags(HashSet tagIds, int indexerId); ReleaseProfile Get(int id); void Delete(int id); ReleaseProfile Add(ReleaseProfile restriction); @@ -42,6 +43,13 @@ namespace NzbDrone.Core.Profiles.Releases return _repo.All().Where(r => r.Tags.Intersect(tagIds).Any() || r.Tags.Empty()).ToList(); } + public List EnabledForTags(HashSet tagIds, int indexerId) + { + return (List)AllForTags(tagIds) + .Where(r => r.Enabled) + .Where(r => r.IndexerId == indexerId || r.IndexerId == 0); + } + public ReleaseProfile Get(int id) { return _repo.Get(id);