From 1199ae4e4f72d99f6205c5c47a83586fd7b4d364 Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Sat, 9 May 2020 16:45:35 -0700 Subject: [PATCH] New: Use filename for preferred word score if it's higher than scene name --- ...isodeFilePreferredWordCalculatorFixture.cs | 80 +++++++++++++++++++ .../Specifications/CutoffSpecification.cs | 9 ++- .../UpgradeDiskSpecification.cs | 9 ++- .../EpisodeFilePreferredWordCalculator.cs | 46 +++++++++++ 4 files changed, 136 insertions(+), 8 deletions(-) create mode 100644 src/NzbDrone.Core.Test/MediaFiles/EpisodeFilePreferredWordCalculatorFixture.cs create mode 100644 src/NzbDrone.Core/MediaFiles/EpisodeFilePreferredWordCalculator.cs diff --git a/src/NzbDrone.Core.Test/MediaFiles/EpisodeFilePreferredWordCalculatorFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/EpisodeFilePreferredWordCalculatorFixture.cs new file mode 100644 index 000000000..6a0e0548e --- /dev/null +++ b/src/NzbDrone.Core.Test/MediaFiles/EpisodeFilePreferredWordCalculatorFixture.cs @@ -0,0 +1,80 @@ +using FizzWare.NBuilder; +using FluentAssertions; +using Moq; +using NUnit.Framework; +using NzbDrone.Core.MediaFiles; +using NzbDrone.Core.Profiles.Releases; +using NzbDrone.Core.Test.Framework; +using NzbDrone.Core.Tv; + +namespace NzbDrone.Core.Test.MediaFiles +{ + [TestFixture] + public class EpisodeFilePreferredWordCalculatorFixture : CoreTest + { + private Series _series; + private EpisodeFile _episodeFile; + + [SetUp] + public void Setup() + { + _series = Builder.CreateNew().Build(); + _episodeFile = Builder.CreateNew().Build(); + } + + private void GivenPreferredWordScore(string title, int score) + { + Mocker.GetMock() + .Setup(s => s.Calculate(It.IsAny(), title, 0)) + .Returns(score); + } + + [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); + + Subject.Calculate(_series, _episodeFile).Should().Be(20); + } + + [Test] + public void should_return_score_for_full_file_name_when_relative_file_name_is_not_available() + { + _episodeFile.SceneName = null; + _episodeFile.RelativePath = null; + + GivenPreferredWordScore(_episodeFile.Path, 20); + + Subject.Calculate(_series, _episodeFile).Should().Be(20); + } + + [Test] + public void should_return_score_for_relative_file_name_when_scene_name_is_null() + { + _episodeFile.SceneName = null; + + GivenPreferredWordScore(_episodeFile.RelativePath, 20); + + Subject.Calculate(_series, _episodeFile).Should().Be(20); + } + + [Test] + public void should_return_score_for_scene_name_when_higher_than_relative_file_name() + { + GivenPreferredWordScore(_episodeFile.SceneName, 50); + GivenPreferredWordScore(_episodeFile.RelativePath, 20); + + Subject.Calculate(_series, _episodeFile).Should().Be(50); + } + + [Test] + public void should_return_score_for_relative_file_if_available() + { + GivenPreferredWordScore(_episodeFile.RelativePath, 20); + GivenPreferredWordScore(_episodeFile.Path, 50); + + Subject.Calculate(_series, _episodeFile).Should().Be(20); + } + } +} \ No newline at end of file diff --git a/src/NzbDrone.Core/DecisionEngine/Specifications/CutoffSpecification.cs b/src/NzbDrone.Core/DecisionEngine/Specifications/CutoffSpecification.cs index 0804ed690..e9bd0875e 100644 --- a/src/NzbDrone.Core/DecisionEngine/Specifications/CutoffSpecification.cs +++ b/src/NzbDrone.Core/DecisionEngine/Specifications/CutoffSpecification.cs @@ -1,6 +1,7 @@ using System.Linq; using NLog; using NzbDrone.Core.IndexerSearch.Definitions; +using NzbDrone.Core.MediaFiles; using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Profiles.Releases; @@ -9,13 +10,13 @@ namespace NzbDrone.Core.DecisionEngine.Specifications public class CutoffSpecification : IDecisionEngineSpecification { private readonly UpgradableSpecification _upgradableSpecification; - private readonly IPreferredWordService _preferredWordServiceCalculator; + private readonly IEpisodeFilePreferredWordCalculator _episodeFilePreferredWordCalculator; private readonly Logger _logger; - public CutoffSpecification(UpgradableSpecification upgradableSpecification, IPreferredWordService preferredWordServiceCalculator, Logger logger) + public CutoffSpecification(UpgradableSpecification upgradableSpecification, IEpisodeFilePreferredWordCalculator episodeFilePreferredWordCalculator, Logger logger) { _upgradableSpecification = upgradableSpecification; - _preferredWordServiceCalculator = preferredWordServiceCalculator; + _episodeFilePreferredWordCalculator = episodeFilePreferredWordCalculator; _logger = logger; } @@ -41,7 +42,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications languageProfile, file.Quality, file.Language, - _preferredWordServiceCalculator.Calculate(subject.Series, file.GetSceneOrFileName(), subject.Release.IndexerId), + _episodeFilePreferredWordCalculator.Calculate(subject.Series, file), subject.ParsedEpisodeInfo.Quality, subject.PreferredWordScore)) { diff --git a/src/NzbDrone.Core/DecisionEngine/Specifications/UpgradeDiskSpecification.cs b/src/NzbDrone.Core/DecisionEngine/Specifications/UpgradeDiskSpecification.cs index 2db74c886..9e386277a 100644 --- a/src/NzbDrone.Core/DecisionEngine/Specifications/UpgradeDiskSpecification.cs +++ b/src/NzbDrone.Core/DecisionEngine/Specifications/UpgradeDiskSpecification.cs @@ -1,6 +1,7 @@ using System.Linq; using NLog; using NzbDrone.Core.IndexerSearch.Definitions; +using NzbDrone.Core.MediaFiles; using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Profiles.Releases; @@ -9,13 +10,13 @@ namespace NzbDrone.Core.DecisionEngine.Specifications public class UpgradeDiskSpecification : IDecisionEngineSpecification { private readonly UpgradableSpecification _upgradableSpecification; - private readonly IPreferredWordService _preferredWordServiceCalculator; + private readonly IEpisodeFilePreferredWordCalculator _episodeFilePreferredWordCalculator; private readonly Logger _logger; - public UpgradeDiskSpecification(UpgradableSpecification upgradableSpecification, IPreferredWordService preferredWordServiceCalculator, Logger logger) + public UpgradeDiskSpecification(UpgradableSpecification upgradableSpecification, IEpisodeFilePreferredWordCalculator episodeFilePreferredWordCalculator, Logger logger) { _upgradableSpecification = upgradableSpecification; - _preferredWordServiceCalculator = preferredWordServiceCalculator; + _episodeFilePreferredWordCalculator = episodeFilePreferredWordCalculator; _logger = logger; } @@ -38,7 +39,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications subject.Series.LanguageProfile, file.Quality, file.Language, - _preferredWordServiceCalculator.Calculate(subject.Series, file.GetSceneOrFileName(), subject.Release?.IndexerId ?? 0), + _episodeFilePreferredWordCalculator.Calculate(subject.Series, file), subject.ParsedEpisodeInfo.Quality, subject.ParsedEpisodeInfo.Language, subject.PreferredWordScore)) diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeFilePreferredWordCalculator.cs b/src/NzbDrone.Core/MediaFiles/EpisodeFilePreferredWordCalculator.cs new file mode 100644 index 000000000..d9178f6ad --- /dev/null +++ b/src/NzbDrone.Core/MediaFiles/EpisodeFilePreferredWordCalculator.cs @@ -0,0 +1,46 @@ +using System.Collections.Generic; +using NzbDrone.Common.Extensions; +using NzbDrone.Core.Profiles.Releases; +using NzbDrone.Core.Tv; + +namespace NzbDrone.Core.MediaFiles +{ + public interface IEpisodeFilePreferredWordCalculator + { + int Calculate(Series series, EpisodeFile episodeFile); + } + + public class EpisodeFilePreferredWordCalculator : IEpisodeFilePreferredWordCalculator + { + private readonly IPreferredWordService _preferredWordService; + + public EpisodeFilePreferredWordCalculator(IPreferredWordService preferredWordService) + { + _preferredWordService = preferredWordService; + } + public int Calculate(Series series, EpisodeFile episodeFile) + { + var scores = new List(); + + if (episodeFile.SceneName.IsNotNullOrWhiteSpace()) + { + scores.Add(_preferredWordService.Calculate(series, episodeFile.SceneName, 0)); + } + + // Calculate using RelativePath or Path, but not both + if (episodeFile.RelativePath.IsNotNullOrWhiteSpace()) + { + scores.Add(_preferredWordService.Calculate(series, episodeFile.RelativePath, 0)); + } + else if (episodeFile.Path.IsNotNullOrWhiteSpace()) + { + scores.Add(_preferredWordService.Calculate(series, episodeFile.Path, 0)); + } + + // Return the highest score, this will allow media info in file names to be used to improve preferred word scoring. + // TODO: A full map of preferred words should be de-duped and used to create an aggregated score using the scene name and the file name. + + return scores.MaxOrDefault(); + } + } +}