diff --git a/src/NzbDrone.Core.Test/DecisionEngineTests/ReleaseRestrictionsSpecificationFixture.cs b/src/NzbDrone.Core.Test/DecisionEngineTests/ReleaseRestrictionsSpecificationFixture.cs index a79a82d44..d551e2853 100644 --- a/src/NzbDrone.Core.Test/DecisionEngineTests/ReleaseRestrictionsSpecificationFixture.cs +++ b/src/NzbDrone.Core.Test/DecisionEngineTests/ReleaseRestrictionsSpecificationFixture.cs @@ -30,7 +30,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests } }; - Mocker.SetConstant(Mocker.Resolve()); + Mocker.SetConstant(Mocker.Resolve()); } private void GivenRestictions(string required, string ignored) diff --git a/src/NzbDrone.Core.Test/Profiles/Releases/PreferredWordService/CalculateFixture.cs b/src/NzbDrone.Core.Test/Profiles/Releases/PreferredWordService/CalculateFixture.cs index 48584950d..55e7cf476 100644 --- a/src/NzbDrone.Core.Test/Profiles/Releases/PreferredWordService/CalculateFixture.cs +++ b/src/NzbDrone.Core.Test/Profiles/Releases/PreferredWordService/CalculateFixture.cs @@ -43,7 +43,7 @@ namespace NzbDrone.Core.Test.Profiles.Releases.PreferredWordService private void GivenMatchingTerms(params string[] terms) { - Mocker.GetMock() + Mocker.GetMock() .Setup(s => s.IsMatch(It.IsAny(), _title)) .Returns((term, title) => terms.Contains(term)); } diff --git a/src/NzbDrone.Core/DecisionEngine/Specifications/ReleaseRestrictionsSpecification.cs b/src/NzbDrone.Core/DecisionEngine/Specifications/ReleaseRestrictionsSpecification.cs index 7fe907c64..743e68e20 100644 --- a/src/NzbDrone.Core/DecisionEngine/Specifications/ReleaseRestrictionsSpecification.cs +++ b/src/NzbDrone.Core/DecisionEngine/Specifications/ReleaseRestrictionsSpecification.cs @@ -13,13 +13,13 @@ namespace NzbDrone.Core.DecisionEngine.Specifications { private readonly Logger _logger; private readonly IReleaseProfileService _releaseProfileService; - private readonly ITermMatcher _termMatcher; + private readonly ITermMatcherService _termMatcherService; - public ReleaseRestrictionsSpecification(ITermMatcher termMatcher, IReleaseProfileService releaseProfileService, Logger logger) + public ReleaseRestrictionsSpecification(ITermMatcherService termMatcherService, IReleaseProfileService releaseProfileService, Logger logger) { _logger = logger; _releaseProfileService = releaseProfileService; - _termMatcher = termMatcher; + _termMatcherService = termMatcherService; } public SpecificationPriority Priority => SpecificationPriority.Default; @@ -67,7 +67,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications private List ContainsAny(List terms, string title) { - return terms.Where(t => _termMatcher.IsMatch(t, title)).ToList(); + return terms.Where(t => _termMatcherService.IsMatch(t, title)).ToList(); } } } diff --git a/src/NzbDrone.Core/NzbDrone.Core.csproj b/src/NzbDrone.Core/NzbDrone.Core.csproj index f31ad35d6..7678ef3a3 100644 --- a/src/NzbDrone.Core/NzbDrone.Core.csproj +++ b/src/NzbDrone.Core/NzbDrone.Core.csproj @@ -1012,6 +1012,9 @@ + + + @@ -1145,7 +1148,7 @@ - + diff --git a/src/NzbDrone.Core/Organizer/FileNameBuilder.cs b/src/NzbDrone.Core/Organizer/FileNameBuilder.cs index 0a6c4aa83..ea5f69284 100644 --- a/src/NzbDrone.Core/Organizer/FileNameBuilder.cs +++ b/src/NzbDrone.Core/Organizer/FileNameBuilder.cs @@ -617,7 +617,7 @@ namespace NzbDrone.Core.Organizer { if (preferredWords == null) { - preferredWords = _preferredWordService.GetMatchingPreferredWords(series, episodeFile.GetSceneOrFileName(), true); + preferredWords = _preferredWordService.GetMatchingPreferredWords(series, episodeFile.GetSceneOrFileName()); } tokenHandlers["{Preferred Words}"] = m => string.Join(" ", preferredWords); diff --git a/src/NzbDrone.Core/Profiles/Releases/PreferredWordService.cs b/src/NzbDrone.Core/Profiles/Releases/PreferredWordService.cs index d8ca43b4d..18ca1c9e5 100644 --- a/src/NzbDrone.Core/Profiles/Releases/PreferredWordService.cs +++ b/src/NzbDrone.Core/Profiles/Releases/PreferredWordService.cs @@ -2,25 +2,26 @@ using NLog; using NzbDrone.Core.Tv; using System.Collections.Generic; using System.Linq; +using NzbDrone.Common.Extensions; namespace NzbDrone.Core.Profiles.Releases { public interface IPreferredWordService { int Calculate(Series series, string title); - List GetMatchingPreferredWords(Series series, string title, bool isRenaming); + List GetMatchingPreferredWords(Series series, string title); } public class PreferredWordService : IPreferredWordService { private readonly IReleaseProfileService _releaseProfileService; - private readonly ITermMatcher _termMatcher; + private readonly ITermMatcherService _termMatcherService; private readonly Logger _logger; - public PreferredWordService(IReleaseProfileService releaseProfileService, ITermMatcher termMatcher, Logger logger) + public PreferredWordService(IReleaseProfileService releaseProfileService, ITermMatcherService termMatcherService, Logger logger) { _releaseProfileService = releaseProfileService; - _termMatcher = termMatcher; + _termMatcherService = termMatcherService; _logger = logger; } @@ -28,7 +29,22 @@ namespace NzbDrone.Core.Profiles.Releases { _logger.Trace("Calculating preferred word score for '{0}'", title); - var matchingPairs = GetMatchingPairs(series, title, false); + var releaseProfiles = _releaseProfileService.AllForTags(series.Tags); + var matchingPairs = new List>(); + + foreach (var releaseProfile in releaseProfiles) + { + foreach (var preferredPair in releaseProfile.Preferred) + { + var term = preferredPair.Key; + + if (_termMatcherService.IsMatch(term, title)) + { + matchingPairs.Add(preferredPair); + } + } + } + var score = matchingPairs.Sum(p => p.Value); _logger.Trace("Calculated preferred word score for '{0}': {1}", title, score); @@ -36,25 +52,16 @@ namespace NzbDrone.Core.Profiles.Releases return score; } - public List GetMatchingPreferredWords(Series series, string title, bool isRenaming) - { - var matchingPairs = GetMatchingPairs(series, title, isRenaming); - - return matchingPairs.OrderByDescending(p => p.Value) - .Select(p => p.Key) - .ToList(); - } - - private List> GetMatchingPairs(Series series, string title, bool isRenaming) + public List GetMatchingPreferredWords(Series series, string title) { var releaseProfiles = _releaseProfileService.AllForTags(series.Tags); - var result = new List>(); + var matchingPairs = new List>(); _logger.Trace("Calculating preferred word score for '{0}'", title); foreach (var releaseProfile in releaseProfiles) { - if (isRenaming && !releaseProfile.IncludePreferredWhenRenaming) + if (!releaseProfile.IncludePreferredWhenRenaming) { continue; } @@ -62,15 +69,18 @@ namespace NzbDrone.Core.Profiles.Releases foreach (var preferredPair in releaseProfile.Preferred) { var term = preferredPair.Key; + var matchingTerm = _termMatcherService.MatchingTerm(term, title); - if (_termMatcher.IsMatch(term, title)) + if (matchingTerm.IsNotNullOrWhiteSpace()) { - result.Add(preferredPair); + matchingPairs.Add(new KeyValuePair(matchingTerm, preferredPair.Value)); } } } - return result; + return matchingPairs.OrderByDescending(p => p.Value) + .Select(p => p.Key) + .ToList(); } } } diff --git a/src/NzbDrone.Core/Profiles/Releases/TermMatcher.cs b/src/NzbDrone.Core/Profiles/Releases/TermMatcher.cs deleted file mode 100644 index f8c8fd82d..000000000 --- a/src/NzbDrone.Core/Profiles/Releases/TermMatcher.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System; -using System.Text.RegularExpressions; -using NzbDrone.Common.Cache; - -namespace NzbDrone.Core.Profiles.Releases -{ - public interface ITermMatcher - { - bool IsMatch(string term, string value); - } - - public class TermMatcher : ITermMatcher - { - private ICached> _matcherCache; - - public TermMatcher(ICacheManager cacheManager) - { - _matcherCache = cacheManager.GetCache>(GetType()); - } - - public bool IsMatch(string term, string value) - { - return GetMatcher(term)(value); - } - - public Predicate GetMatcher(string term) - { - return _matcherCache.Get(term, () => CreateMatcherInternal(term), TimeSpan.FromHours(24)); - } - - private Predicate CreateMatcherInternal(string term) - { - Regex regex; - if (PerlRegexFactory.TryCreateRegex(term, out regex)) - { - return regex.IsMatch; - } - else - { - return new CaseInsensitiveTermMatcher(term).IsMatch; - - } - } - - private sealed class CaseInsensitiveTermMatcher - { - private readonly string _term; - - public CaseInsensitiveTermMatcher(string term) - { - _term = term.ToLowerInvariant(); - } - - public bool IsMatch(string value) - { - return value.ToLowerInvariant().Contains(_term); - } - } - } -} diff --git a/src/NzbDrone.Core/Profiles/Releases/TermMatcherService.cs b/src/NzbDrone.Core/Profiles/Releases/TermMatcherService.cs new file mode 100644 index 000000000..21448d367 --- /dev/null +++ b/src/NzbDrone.Core/Profiles/Releases/TermMatcherService.cs @@ -0,0 +1,52 @@ +using System; +using System.Text.RegularExpressions; +using NzbDrone.Common.Cache; +using NzbDrone.Core.Profiles.Releases.TermMatchers; + +namespace NzbDrone.Core.Profiles.Releases +{ + public interface ITermMatcherService + { + bool IsMatch(string term, string value); + string MatchingTerm(string term, string value); + } + + public class TermMatcherService : ITermMatcherService + { + private ICached _matcherCache; + + public TermMatcherService(ICacheManager cacheManager) + { + _matcherCache = cacheManager.GetCache(GetType()); + } + + public bool IsMatch(string term, string value) + { + return GetMatcher(term).IsMatch(value); + } + + public string MatchingTerm(string term, string value) + { + return GetMatcher(term).MatchingTerm(value); + } + + public ITermMatcher GetMatcher(string term) + { + return _matcherCache.Get(term, () => CreateMatcherInternal(term), TimeSpan.FromHours(24)); + } + + private ITermMatcher CreateMatcherInternal(string term) + { + Regex regex; + if (PerlRegexFactory.TryCreateRegex(term, out regex)) + { + return new RegexTermMatcher(regex); + } + else + { + return new CaseInsensitiveTermMatcher(term); + + } + } + } +} diff --git a/src/NzbDrone.Core/Profiles/Releases/TermMatchers/CaseInsensitiveTermMatcher.cs b/src/NzbDrone.Core/Profiles/Releases/TermMatchers/CaseInsensitiveTermMatcher.cs new file mode 100644 index 000000000..170521f85 --- /dev/null +++ b/src/NzbDrone.Core/Profiles/Releases/TermMatchers/CaseInsensitiveTermMatcher.cs @@ -0,0 +1,22 @@ +namespace NzbDrone.Core.Profiles.Releases.TermMatchers +{ + public sealed class CaseInsensitiveTermMatcher : ITermMatcher + { + private readonly string _term; + + public CaseInsensitiveTermMatcher(string term) + { + _term = term.ToLowerInvariant(); + } + + public bool IsMatch(string value) + { + return value.ToLowerInvariant().Contains(_term); + } + + public string MatchingTerm(string value) + { + return _term; + } + } +} diff --git a/src/NzbDrone.Core/Profiles/Releases/TermMatchers/ITermMatcher.cs b/src/NzbDrone.Core/Profiles/Releases/TermMatchers/ITermMatcher.cs new file mode 100644 index 000000000..0122372ab --- /dev/null +++ b/src/NzbDrone.Core/Profiles/Releases/TermMatchers/ITermMatcher.cs @@ -0,0 +1,8 @@ +namespace NzbDrone.Core.Profiles.Releases.TermMatchers +{ + public interface ITermMatcher + { + bool IsMatch(string value); + string MatchingTerm(string value); + } +} diff --git a/src/NzbDrone.Core/Profiles/Releases/TermMatchers/RegextermMatcher.cs b/src/NzbDrone.Core/Profiles/Releases/TermMatchers/RegextermMatcher.cs new file mode 100644 index 000000000..39125bb69 --- /dev/null +++ b/src/NzbDrone.Core/Profiles/Releases/TermMatchers/RegextermMatcher.cs @@ -0,0 +1,24 @@ +using System.Text.RegularExpressions; + +namespace NzbDrone.Core.Profiles.Releases.TermMatchers +{ + public class RegexTermMatcher : ITermMatcher + { + private readonly Regex _regex; + + public RegexTermMatcher(Regex regex) + { + _regex = regex; + } + + public bool IsMatch(string value) + { + return _regex.IsMatch(value); + } + + public string MatchingTerm(string value) + { + return _regex.Match(value).Value; + } + } +}