Fixed: Negative preferred word scores being trumped by 0 scores without any matches

This commit is contained in:
Mark McDowall 2022-02-24 19:11:09 -08:00
parent 66af08a830
commit acdf02d569
3 changed files with 94 additions and 31 deletions

View File

@ -1,4 +1,6 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using FizzWare.NBuilder;
using FluentAssertions;
using Moq;
@ -15,26 +17,33 @@ namespace NzbDrone.Core.Test.MediaFiles
{
private Series _series;
private EpisodeFile _episodeFile;
private readonly KeyValuePair<string, int> _positiveScore = new KeyValuePair<string, int>("Positive", 10);
private readonly KeyValuePair<string, int> _negativeScore = new KeyValuePair<string, int>("Negative", -10);
private KeyValuePair<string, int> _neutralScore = new KeyValuePair<string, int>("Neutral", 0);
[SetUp]
public void Setup()
{
_series = Builder<Series>.CreateNew().Build();
_episodeFile = Builder<EpisodeFile>.CreateNew().Build();
Mocker.GetMock<IPreferredWordService>()
.Setup(s => s.GetMatchingPreferredWordsAndScores(It.IsAny<Series>(), It.IsAny<string>(), 0))
.Returns(new List<KeyValuePair<string, int>>());
}
private void GivenPreferredWordScore(string title, int score)
private void GivenPreferredWordScore(string title, params KeyValuePair<string, int>[] matches)
{
Mocker.GetMock<IPreferredWordService>()
.Setup(s => s.Calculate(It.IsAny<Series>(), title, 0))
.Returns(score);
.Setup(s => s.GetMatchingPreferredWordsAndScores(It.IsAny<Series>(), title, 0))
.Returns(matches.ToList());
}
[Test]
public void should_return_score_for_relative_file_name_when_it_is_higher_than_scene_name()
{
GivenPreferredWordScore(_episodeFile.SceneName, 10);
GivenPreferredWordScore(_episodeFile.RelativePath, 20);
GivenPreferredWordScore(_episodeFile.SceneName, _positiveScore);
GivenPreferredWordScore(_episodeFile.RelativePath, _positiveScore, _positiveScore);
Subject.Calculate(_series, _episodeFile).Should().Be(20);
}
@ -45,7 +54,7 @@ namespace NzbDrone.Core.Test.MediaFiles
_episodeFile.SceneName = null;
_episodeFile.RelativePath = null;
GivenPreferredWordScore(_episodeFile.Path, 20);
GivenPreferredWordScore(_episodeFile.Path, _positiveScore, _positiveScore);
Subject.Calculate(_series, _episodeFile).Should().Be(20);
}
@ -55,7 +64,7 @@ namespace NzbDrone.Core.Test.MediaFiles
{
_episodeFile.SceneName = null;
GivenPreferredWordScore(_episodeFile.RelativePath, 20);
GivenPreferredWordScore(_episodeFile.RelativePath, _positiveScore, _positiveScore);
Subject.Calculate(_series, _episodeFile).Should().Be(20);
}
@ -63,17 +72,17 @@ namespace NzbDrone.Core.Test.MediaFiles
[Test]
public void should_return_score_for_scene_name_when_higher_than_relative_file_name()
{
GivenPreferredWordScore(_episodeFile.SceneName, 50);
GivenPreferredWordScore(_episodeFile.RelativePath, 20);
GivenPreferredWordScore(_episodeFile.SceneName, _positiveScore, _positiveScore, _positiveScore);
GivenPreferredWordScore(_episodeFile.RelativePath, _positiveScore, _positiveScore);
Subject.Calculate(_series, _episodeFile).Should().Be(50);
Subject.Calculate(_series, _episodeFile).Should().Be(30);
}
[Test]
public void should_return_score_for_relative_file_if_available()
{
GivenPreferredWordScore(_episodeFile.RelativePath, 20);
GivenPreferredWordScore(_episodeFile.Path, 50);
GivenPreferredWordScore(_episodeFile.RelativePath, _positiveScore, _positiveScore);
GivenPreferredWordScore(_episodeFile.Path, _positiveScore, _positiveScore, _positiveScore);
Subject.Calculate(_series, _episodeFile).Should().Be(20);
}
@ -86,12 +95,12 @@ namespace NzbDrone.Core.Test.MediaFiles
_episodeFile.OriginalFilePath = Path.Combine(folderName, fileName);
GivenPreferredWordScore(_episodeFile.RelativePath, 20);
GivenPreferredWordScore(_episodeFile.Path, 50);
GivenPreferredWordScore(folderName, 60);
GivenPreferredWordScore(fileName, 50);
GivenPreferredWordScore(_episodeFile.RelativePath, _positiveScore);
GivenPreferredWordScore(_episodeFile.Path, _positiveScore, _positiveScore);
GivenPreferredWordScore(folderName, _positiveScore, _positiveScore, _positiveScore);
GivenPreferredWordScore(fileName, _positiveScore, _positiveScore);
Subject.Calculate(_series, _episodeFile).Should().Be(60);
Subject.Calculate(_series, _episodeFile).Should().Be(30);
}
[Test]
@ -102,12 +111,42 @@ namespace NzbDrone.Core.Test.MediaFiles
_episodeFile.OriginalFilePath = Path.Combine(folderName, fileName);
GivenPreferredWordScore(_episodeFile.RelativePath, 20);
GivenPreferredWordScore(_episodeFile.Path, 50);
GivenPreferredWordScore(folderName, 40);
GivenPreferredWordScore(fileName, 50);
GivenPreferredWordScore(_episodeFile.RelativePath, _positiveScore);
GivenPreferredWordScore(_episodeFile.Path, _positiveScore, _positiveScore);
GivenPreferredWordScore(folderName, _positiveScore, _positiveScore);
GivenPreferredWordScore(fileName, _positiveScore, _positiveScore, _positiveScore);
Subject.Calculate(_series, _episodeFile).Should().Be(50);
Subject.Calculate(_series, _episodeFile).Should().Be(30);
}
[Test]
public void should_return_negative_score_if_0_result_has_no_matches()
{
var folderName = "folder-name";
var fileName = "file-name";
_episodeFile.OriginalFilePath = Path.Combine(folderName, fileName);
GivenPreferredWordScore(_episodeFile.RelativePath, _negativeScore);
GivenPreferredWordScore(fileName);
Subject.Calculate(_series, _episodeFile).Should().Be(-10);
}
[Test]
public void should_return_0_score_if_0_result_has_matches()
{
var folderName = "folder-name";
var fileName = "file-name";
_episodeFile.OriginalFilePath = Path.Combine(folderName, fileName);
GivenPreferredWordScore(_episodeFile.RelativePath, _negativeScore);
GivenPreferredWordScore(_episodeFile.Path, _negativeScore);
GivenPreferredWordScore(folderName, _negativeScore);
GivenPreferredWordScore(fileName, _neutralScore);
Subject.Calculate(_series, _episodeFile).Should().Be(0);
}
}
}

View File

@ -32,7 +32,7 @@ namespace NzbDrone.Core.MediaFiles
if (episodeFile.SceneName.IsNotNullOrWhiteSpace())
{
scores.Add(_preferredWordService.Calculate(series, episodeFile.SceneName, 0));
AddScoreIfApplicable(series, episodeFile.SceneName, scores);
}
else
{
@ -49,7 +49,7 @@ namespace NzbDrone.Core.MediaFiles
var isLast = i == segments.Count - 1;
var segment = isLast ? Path.GetFileNameWithoutExtension(segments[i]) : segments[i];
scores.Add(_preferredWordService.Calculate(series, segment, 0));
AddScoreIfApplicable(series, segment, scores);
}
}
else
@ -60,11 +60,11 @@ namespace NzbDrone.Core.MediaFiles
// Calculate using RelativePath or Path, but not both
if (episodeFile.RelativePath.IsNotNullOrWhiteSpace())
{
scores.Add(_preferredWordService.Calculate(series, episodeFile.RelativePath, 0));
AddScoreIfApplicable(series, episodeFile.RelativePath, scores);
}
else if (episodeFile.Path.IsNotNullOrWhiteSpace())
{
scores.Add(_preferredWordService.Calculate(series, episodeFile.Path, 0));
AddScoreIfApplicable(series, episodeFile.Path, scores);
}
// Return the highest score, this will allow media info in file names to be used to improve preferred word scoring.
@ -72,5 +72,22 @@ namespace NzbDrone.Core.MediaFiles
return scores.MaxOrDefault();
}
private void AddScoreIfApplicable(Series series, string title, List<int> scores)
{
var score = 0;
_logger.Trace("Calculating preferred word score for '{0}'", title);
var matchingPairs = _preferredWordService.GetMatchingPreferredWordsAndScores(series, title, 0);
// Only add the score if there are matching terms, uncalculated
if (matchingPairs.Any())
{
score = matchingPairs.Sum(p => p.Value);
scores.Add(score);
}
_logger.Trace("Calculated preferred word score for '{0}': {1} ({2} match(es))", title, score, matchingPairs.Count);
}
}
}

View File

@ -10,6 +10,7 @@ namespace NzbDrone.Core.Profiles.Releases
public interface IPreferredWordService
{
int Calculate(Series series, string title, int indexerId);
List<KeyValuePair<string, int>> GetMatchingPreferredWordsAndScores(Series series, string title, int indexerId);
PreferredWordMatchResults GetMatchingPreferredWords(Series series, string title);
}
@ -30,6 +31,16 @@ namespace NzbDrone.Core.Profiles.Releases
{
_logger.Trace("Calculating preferred word score for '{0}'", title);
var matchingPairs = GetMatchingPreferredWordsAndScores(series, title, indexerId);
var score = matchingPairs.Sum(p => p.Value);
_logger.Trace("Calculated preferred word score for '{0}': {1} ({2} match(es))", title, score, matchingPairs.Count);
return score;
}
public List<KeyValuePair<string, int>> GetMatchingPreferredWordsAndScores(Series series, string title, int indexerId)
{
var releaseProfiles = _releaseProfileService.EnabledForTags(series.Tags, indexerId);
var matchingPairs = new List<KeyValuePair<string, int>>();
@ -46,11 +57,7 @@ namespace NzbDrone.Core.Profiles.Releases
}
}
var score = matchingPairs.Sum(p => p.Value);
_logger.Trace("Calculated preferred word score for '{0}': {1}", title, score);
return score;
return matchingPairs;
}
public PreferredWordMatchResults GetMatchingPreferredWords(Series series, string title)