Fixed: Include matching value of preferred word regex, not the actual regex

This commit is contained in:
Mark McDowall 2019-02-26 18:54:59 -08:00
parent 1222aeaab6
commit 78b3c9552b
11 changed files with 147 additions and 88 deletions

View File

@ -30,7 +30,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
}
};
Mocker.SetConstant<ITermMatcher>(Mocker.Resolve<TermMatcher>());
Mocker.SetConstant<ITermMatcherService>(Mocker.Resolve<TermMatcherService>());
}
private void GivenRestictions(string required, string ignored)

View File

@ -43,7 +43,7 @@ namespace NzbDrone.Core.Test.Profiles.Releases.PreferredWordService
private void GivenMatchingTerms(params string[] terms)
{
Mocker.GetMock<ITermMatcher>()
Mocker.GetMock<ITermMatcherService>()
.Setup(s => s.IsMatch(It.IsAny<string>(), _title))
.Returns<string, string>((term, title) => terms.Contains(term));
}

View File

@ -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<string> ContainsAny(List<string> terms, string title)
{
return terms.Where(t => _termMatcher.IsMatch(t, title)).ToList();
return terms.Where(t => _termMatcherService.IsMatch(t, title)).ToList();
}
}
}

View File

@ -1012,6 +1012,9 @@
<Compile Include="Profiles\Qualities\QualityProfileService.cs" />
<Compile Include="Profiles\Qualities\QualityIndex.cs" />
<Compile Include="Profiles\Releases\PreferredWordService.cs" />
<Compile Include="Profiles\Releases\TermMatchers\CaseInsensitiveTermMatcher.cs" />
<Compile Include="Profiles\Releases\TermMatchers\ITermMatcher.cs" />
<Compile Include="Profiles\Releases\TermMatchers\RegexTermMatcher.cs" />
<Compile Include="ProgressMessaging\ProgressMessageContext.cs" />
<Compile Include="Qualities\QualityDetectionSource.cs" />
<Compile Include="Qualities\QualityFinder.cs" />
@ -1145,7 +1148,7 @@
<Compile Include="Profiles\Releases\ReleaseProfile.cs" />
<Compile Include="Profiles\Releases\ReleaseProfileRepository.cs" />
<Compile Include="Profiles\Releases\ReleaseProfileService.cs" />
<Compile Include="Profiles\Releases\TermMatcher.cs" />
<Compile Include="Profiles\Releases\TermMatcherService.cs" />
<Compile Include="Rest\JsonNetSerializer.cs" />
<Compile Include="Rest\RestClientFactory.cs" />
<Compile Include="Rest\RestException.cs" />

View File

@ -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);

View File

@ -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<string> GetMatchingPreferredWords(Series series, string title, bool isRenaming);
List<string> 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<KeyValuePair<string, int>>();
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<string> 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<KeyValuePair<string, int>> GetMatchingPairs(Series series, string title, bool isRenaming)
public List<string> GetMatchingPreferredWords(Series series, string title)
{
var releaseProfiles = _releaseProfileService.AllForTags(series.Tags);
var result = new List<KeyValuePair<string, int>>();
var matchingPairs = new List<KeyValuePair<string, int>>();
_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<string, int>(matchingTerm, preferredPair.Value));
}
}
}
return result;
return matchingPairs.OrderByDescending(p => p.Value)
.Select(p => p.Key)
.ToList();
}
}
}

View File

@ -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<Predicate<string>> _matcherCache;
public TermMatcher(ICacheManager cacheManager)
{
_matcherCache = cacheManager.GetCache<Predicate<string>>(GetType());
}
public bool IsMatch(string term, string value)
{
return GetMatcher(term)(value);
}
public Predicate<string> GetMatcher(string term)
{
return _matcherCache.Get(term, () => CreateMatcherInternal(term), TimeSpan.FromHours(24));
}
private Predicate<string> 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);
}
}
}
}

View File

@ -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<ITermMatcher> _matcherCache;
public TermMatcherService(ICacheManager cacheManager)
{
_matcherCache = cacheManager.GetCache<ITermMatcher>(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);
}
}
}
}

View File

@ -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;
}
}
}

View File

@ -0,0 +1,8 @@
namespace NzbDrone.Core.Profiles.Releases.TermMatchers
{
public interface ITermMatcher
{
bool IsMatch(string value);
string MatchingTerm(string value);
}
}

View File

@ -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;
}
}
}