New: Named Release Profile preferred word renaming tokens
This commit is contained in:
parent
6596d0b4da
commit
d4cd4a9549
|
@ -11,6 +11,7 @@ using NzbDrone.Core.MediaFiles.Events;
|
|||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Organizer;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Profiles.Releases;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Test.Common;
|
||||
|
@ -42,7 +43,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeFileMovingServiceTests
|
|||
.Build();
|
||||
|
||||
Mocker.GetMock<IBuildFileNames>()
|
||||
.Setup(s => s.BuildFilePath(It.IsAny<List<Episode>>(), It.IsAny<Series>(), It.IsAny<EpisodeFile>(), It.IsAny<string>(), It.IsAny<NamingConfig>(), It.IsAny<List<string>>()))
|
||||
.Setup(s => s.BuildFilePath(It.IsAny<List<Episode>>(), It.IsAny<Series>(), It.IsAny<EpisodeFile>(), It.IsAny<string>(), It.IsAny<NamingConfig>(), It.IsAny<PreferredWordMatchResults>()))
|
||||
.Returns(@"C:\Test\TV\Series\Season 01\File Name.avi".AsOsAgnostic());
|
||||
|
||||
Mocker.GetMock<IBuildFileNames>()
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Organizer;
|
||||
using NzbDrone.Core.Profiles.Releases;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests
|
||||
{
|
||||
[TestFixture]
|
||||
|
||||
public class PreferredWordsFixture : CoreTest<FileNameBuilder>
|
||||
{
|
||||
private Series _series;
|
||||
private Episode _episode1;
|
||||
private EpisodeFile _episodeFile;
|
||||
private NamingConfig _namingConfig;
|
||||
|
||||
private PreferredWordMatchResults _preferredWords;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_series = Builder<Series>
|
||||
.CreateNew()
|
||||
.With(s => s.Title = "South Park")
|
||||
.Build();
|
||||
|
||||
|
||||
_namingConfig = NamingConfig.Default;
|
||||
_namingConfig.RenameEpisodes = true;
|
||||
|
||||
|
||||
Mocker.GetMock<INamingConfigService>()
|
||||
.Setup(c => c.GetConfig()).Returns(_namingConfig);
|
||||
|
||||
_episode1 = Builder<Episode>.CreateNew()
|
||||
.With(e => e.Title = "City Sushi")
|
||||
.With(e => e.SeasonNumber = 15)
|
||||
.With(e => e.EpisodeNumber = 6)
|
||||
.With(e => e.AbsoluteEpisodeNumber = 100)
|
||||
.Build();
|
||||
|
||||
_episodeFile = new EpisodeFile { Quality = new QualityModel(Quality.HDTV720p), ReleaseGroup = "SonarrTest" };
|
||||
|
||||
_preferredWords = new PreferredWordMatchResults() {
|
||||
All = new List<string>() {
|
||||
"x265",
|
||||
"extended"
|
||||
},
|
||||
ByReleaseProfile = new Dictionary<string, List<string>>() {
|
||||
{
|
||||
"CodecProfile",
|
||||
new List<string>()
|
||||
{
|
||||
"x265"
|
||||
}
|
||||
},
|
||||
{
|
||||
"EditionProfile",
|
||||
new List<string>()
|
||||
{
|
||||
"extended"
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Mocker.GetMock<IQualityDefinitionService>()
|
||||
.Setup(v => v.Get(Moq.It.IsAny<Quality>()))
|
||||
.Returns<Quality>(v => Quality.DefaultQualityDefinitions.First(c => c.Quality == v));
|
||||
}
|
||||
|
||||
[TestCase("{Preferred Words}", "x265 extended")]
|
||||
[TestCase("{Preferred Words:CodecProfile}", "x265")]
|
||||
[TestCase("{Preferred Words:EditionProfile}", "extended")]
|
||||
[TestCase("{Preferred Words:CodecProfile} - {PreferredWords:EditionProfile}", "x265 - extended")]
|
||||
public void should_replace_PreferredWords(string format, string expected)
|
||||
{
|
||||
_namingConfig.StandardEpisodeFormat = format;
|
||||
|
||||
Subject.BuildFileName(new List<Episode> { _episode1 }, _series, _episodeFile, preferredWords: _preferredWords)
|
||||
.Should().Be(expected);
|
||||
}
|
||||
|
||||
[TestCase("{Preferred Words:}", "{Preferred Words:}")]
|
||||
public void should_not_replace_PreferredWords(string format, string expected)
|
||||
{
|
||||
_namingConfig.StandardEpisodeFormat = format;
|
||||
|
||||
Subject.BuildFileName(new List<Episode> { _episode1 }, _series, _episodeFile, preferredWords: _preferredWords)
|
||||
.Should().Be(expected);
|
||||
}
|
||||
|
||||
[TestCase("{Preferred Words:NonexistentProfile}", "")]
|
||||
public void should_replace_PreferredWords_with_empty_string(string format, string expected)
|
||||
{
|
||||
_namingConfig.StandardEpisodeFormat = format;
|
||||
|
||||
Subject.BuildFileName(new List<Episode> { _episode1 }, _series, _episodeFile, preferredWords: _preferredWords)
|
||||
.Should().Be(expected);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,7 +15,8 @@ namespace NzbDrone.Core.Test.Profiles.Releases.PreferredWordService
|
|||
{
|
||||
private Series _series = null;
|
||||
private List<ReleaseProfile> _releaseProfiles = null;
|
||||
private string _title = "Series.Title.S01E01.720p.HDTV.x264-Sonarr";
|
||||
private List<ReleaseProfile> _namedReleaseProfiles = null;
|
||||
private string _title = "Series.Title.S01E01.extended.720p.HDTV.x264-Sonarr";
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
|
@ -35,6 +36,27 @@ namespace NzbDrone.Core.Test.Profiles.Releases.PreferredWordService
|
|||
}
|
||||
});
|
||||
|
||||
_namedReleaseProfiles = new List<ReleaseProfile>();
|
||||
|
||||
_namedReleaseProfiles.Add(new ReleaseProfile
|
||||
{
|
||||
Name = "CodecProfile",
|
||||
Preferred = new List<KeyValuePair<string, int>>
|
||||
{
|
||||
new KeyValuePair<string, int>("x264", 5),
|
||||
new KeyValuePair<string, int>("x265", -10)
|
||||
}
|
||||
});
|
||||
_namedReleaseProfiles.Add(new ReleaseProfile
|
||||
{
|
||||
Name = "EditionProfile",
|
||||
Preferred = new List<KeyValuePair<string, int>>
|
||||
{
|
||||
new KeyValuePair<string, int>("extended", 5),
|
||||
new KeyValuePair<string, int>("uncut", -10)
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Mocker.GetMock<ITermMatcherService>()
|
||||
.Setup(s => s.MatchingTerm(It.IsAny<string>(), _title))
|
||||
|
@ -48,6 +70,13 @@ namespace NzbDrone.Core.Test.Profiles.Releases.PreferredWordService
|
|||
.Returns(_releaseProfiles);
|
||||
}
|
||||
|
||||
private void GivenNamedReleaseProfile()
|
||||
{
|
||||
Mocker.GetMock<IReleaseProfileService>()
|
||||
.Setup(s => s.EnabledForTags(It.IsAny<HashSet<int>>(), It.IsAny<int>()))
|
||||
.Returns(_namedReleaseProfiles);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_empty_list_when_there_are_no_release_profiles()
|
||||
{
|
||||
|
@ -55,24 +84,58 @@ namespace NzbDrone.Core.Test.Profiles.Releases.PreferredWordService
|
|||
.Setup(s => s.EnabledForTags(It.IsAny<HashSet<int>>(), It.IsAny<int>()))
|
||||
.Returns(new List<ReleaseProfile>());
|
||||
|
||||
Subject.GetMatchingPreferredWords(_series, _title).Should().BeEmpty();
|
||||
var matchingResults = Subject.GetMatchingPreferredWords(_series, _title);
|
||||
matchingResults.All.Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_empty_list_when_there_are_no_matching_preferred_words()
|
||||
public void should_return_empty_list_when_there_are_no_matching_preferred_words_from_unnamedprofile()
|
||||
{
|
||||
_releaseProfiles.First().Preferred.RemoveAt(0);
|
||||
GivenReleaseProfile();
|
||||
|
||||
Subject.GetMatchingPreferredWords(_series, _title).Should().BeEmpty();
|
||||
var matchingResults = Subject.GetMatchingPreferredWords(_series, _title);
|
||||
matchingResults.All.Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_list_of_matching_terms()
|
||||
public void should_return_list_of_matching_terms_from_unnamedprofile()
|
||||
{
|
||||
GivenReleaseProfile();
|
||||
|
||||
Subject.GetMatchingPreferredWords(_series, _title).Should().Contain(new[] {"x264"});
|
||||
var matchingResults = Subject.GetMatchingPreferredWords(_series, _title);
|
||||
matchingResults.All.Should().Equal(new[] { "x264" });
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_empty_list_when_there_are_no_matching_preferred_words_from_namedprofiles()
|
||||
{
|
||||
_namedReleaseProfiles.First().Preferred.RemoveAt(0);
|
||||
_namedReleaseProfiles.Skip(1).First().Preferred.RemoveAt(0);
|
||||
|
||||
GivenNamedReleaseProfile();
|
||||
|
||||
var matchingResults = Subject.GetMatchingPreferredWords(_series, _title);
|
||||
matchingResults.All.Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_list_of_matching_terms_from_multiple_namedprofiles()
|
||||
{
|
||||
GivenNamedReleaseProfile();
|
||||
|
||||
var matchingResults = Subject.GetMatchingPreferredWords(_series, _title);
|
||||
matchingResults.ByReleaseProfile.Should().ContainKey("CodecProfile").WhichValue.Should().Equal(new[] { "x264" });
|
||||
matchingResults.ByReleaseProfile.Should().ContainKey("EditionProfile").WhichValue.Should().Equal(new[] { "extended" });
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_list_of_matching_terms_from_multiple_namedprofiles_all()
|
||||
{
|
||||
GivenNamedReleaseProfile();
|
||||
|
||||
var matchingResults = Subject.GetMatchingPreferredWords(_series, _title);
|
||||
matchingResults.All.Should().Equal(new[] { "x264", "extended" });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,8 +22,8 @@ namespace NzbDrone.Core.Organizer
|
|||
{
|
||||
public interface IBuildFileNames
|
||||
{
|
||||
string BuildFileName(List<Episode> episodes, Series series, EpisodeFile episodeFile, string extension = "", NamingConfig namingConfig = null, List<string> preferredWords = null);
|
||||
string BuildFilePath(List<Episode> episodes, Series series, EpisodeFile episodeFile, string extension, NamingConfig namingConfig = null, List<string> preferredWords = null);
|
||||
string BuildFileName(List<Episode> episodes, Series series, EpisodeFile episodeFile, string extension = "", NamingConfig namingConfig = null, PreferredWordMatchResults preferredWords = null);
|
||||
string BuildFilePath(List<Episode> episodes, Series series, EpisodeFile episodeFile, string extension, NamingConfig namingConfig = null, PreferredWordMatchResults preferredWords = null);
|
||||
string BuildSeasonPath(Series series, int seasonNumber);
|
||||
BasicNamingConfig GetBasicNamingConfig(NamingConfig nameSpec);
|
||||
string GetSeriesFolder(Series series, NamingConfig namingConfig = null);
|
||||
|
@ -100,7 +100,7 @@ namespace NzbDrone.Core.Organizer
|
|||
_logger = logger;
|
||||
}
|
||||
|
||||
private string BuildFileName(List<Episode> episodes, Series series, EpisodeFile episodeFile, string extension, int maxPath, NamingConfig namingConfig = null, List<string> preferredWords = null)
|
||||
private string BuildFileName(List<Episode> episodes, Series series, EpisodeFile episodeFile, string extension, int maxPath, NamingConfig namingConfig = null, PreferredWordMatchResults preferredWords = null)
|
||||
{
|
||||
if (namingConfig == null)
|
||||
{
|
||||
|
@ -183,12 +183,12 @@ namespace NzbDrone.Core.Organizer
|
|||
return string.Join(Path.DirectorySeparatorChar.ToString(), components) + extension;
|
||||
}
|
||||
|
||||
public string BuildFileName(List<Episode> episodes, Series series, EpisodeFile episodeFile, string extension = "", NamingConfig namingConfig = null, List<string> preferredWords = null)
|
||||
public string BuildFileName(List<Episode> episodes, Series series, EpisodeFile episodeFile, string extension = "", NamingConfig namingConfig = null, PreferredWordMatchResults preferredWords = null)
|
||||
{
|
||||
return BuildFileName(episodes, series, episodeFile, extension, LongPathSupport.MaxFilePathLength, namingConfig, preferredWords);
|
||||
}
|
||||
|
||||
public string BuildFilePath(List<Episode> episodes, Series series, EpisodeFile episodeFile, string extension, NamingConfig namingConfig = null, List<string> preferredWords = null)
|
||||
public string BuildFilePath(List<Episode> episodes, Series series, EpisodeFile episodeFile, string extension, NamingConfig namingConfig = null, PreferredWordMatchResults preferredWords = null)
|
||||
{
|
||||
Ensure.That(extension, () => extension).IsNotNullOrWhiteSpace();
|
||||
|
||||
|
@ -651,14 +651,34 @@ namespace NzbDrone.Core.Organizer
|
|||
tokenHandlers["{TvMazeId}"] = m => series.TvMazeId > 0 ? series.TvMazeId.ToString() : string.Empty;
|
||||
}
|
||||
|
||||
private void AddPreferredWords(Dictionary<string, Func<TokenMatch, string>> tokenHandlers, Series series, EpisodeFile episodeFile, List<string> preferredWords = null)
|
||||
private void AddPreferredWords(Dictionary<string, Func<TokenMatch, string>> tokenHandlers, Series series, EpisodeFile episodeFile, PreferredWordMatchResults preferredWords = null)
|
||||
{
|
||||
if (preferredWords == null)
|
||||
{
|
||||
preferredWords = _preferredWordService.GetMatchingPreferredWords(series, episodeFile.GetSceneOrFileName());
|
||||
}
|
||||
|
||||
tokenHandlers["{Preferred Words}"] = m => string.Join(" ", preferredWords);
|
||||
tokenHandlers["{Preferred Words}"] = m => {
|
||||
|
||||
var profileName = "";
|
||||
|
||||
if (m.CustomFormat != null)
|
||||
{
|
||||
profileName = m.CustomFormat.Trim();
|
||||
}
|
||||
|
||||
if (profileName.IsNullOrWhiteSpace())
|
||||
{
|
||||
return string.Join(" ", preferredWords.All);
|
||||
}
|
||||
|
||||
if (preferredWords.ByReleaseProfile.TryGetValue(profileName, out var profilePreferredWords))
|
||||
{
|
||||
return string.Join(" ", profilePreferredWords);
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
};
|
||||
}
|
||||
|
||||
private string GetLanguagesToken(string mediaInfoLanguages, string filter, bool skipEnglishOnly, bool quoted)
|
||||
|
|
|
@ -3,6 +3,7 @@ using NzbDrone.Core.MediaFiles;
|
|||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.MediaFiles.MediaInfo;
|
||||
using NzbDrone.Core.Profiles.Releases;
|
||||
|
||||
namespace NzbDrone.Core.Organizer
|
||||
{
|
||||
|
@ -34,7 +35,7 @@ namespace NzbDrone.Core.Organizer
|
|||
private static EpisodeFile _dailyEpisodeFile;
|
||||
private static EpisodeFile _animeEpisodeFile;
|
||||
private static EpisodeFile _animeMultiEpisodeFile;
|
||||
private static List<string> _preferredWords;
|
||||
private static PreferredWordMatchResults _preferredWords;
|
||||
|
||||
public FileNameSampleService(IBuildFileNames buildFileNames)
|
||||
{
|
||||
|
@ -169,9 +170,9 @@ namespace NzbDrone.Core.Organizer
|
|||
MediaInfo = mediaInfoAnime
|
||||
};
|
||||
|
||||
_preferredWords = new List<string>
|
||||
_preferredWords = new PreferredWordMatchResults()
|
||||
{
|
||||
"iNTERNAL"
|
||||
All = new List<string>() {"iNTERNAL" }
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NzbDrone.Core.Profiles.Releases
|
||||
{
|
||||
public class PreferredWordMatchResults
|
||||
{
|
||||
public List<string> All
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public Dictionary<string, List<string>> ByReleaseProfile
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public PreferredWordMatchResults()
|
||||
{
|
||||
All = new List<string>();
|
||||
ByReleaseProfile = new Dictionary<string, List<string>>();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,14 +3,15 @@ using NzbDrone.Core.Tv;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using System;
|
||||
|
||||
namespace NzbDrone.Core.Profiles.Releases
|
||||
{
|
||||
public interface IPreferredWordService
|
||||
{
|
||||
int Calculate(Series series, string title, int indexerId);
|
||||
List<string> GetMatchingPreferredWords(Series series, string title);
|
||||
}
|
||||
PreferredWordMatchResults GetMatchingPreferredWords(Series series, string title);
|
||||
}
|
||||
|
||||
public class PreferredWordService : IPreferredWordService
|
||||
{
|
||||
|
@ -52,15 +53,18 @@ namespace NzbDrone.Core.Profiles.Releases
|
|||
return score;
|
||||
}
|
||||
|
||||
public List<string> GetMatchingPreferredWords(Series series, string title)
|
||||
public PreferredWordMatchResults GetMatchingPreferredWords(Series series, string title)
|
||||
{
|
||||
var releaseProfiles = _releaseProfileService.EnabledForTags(series.Tags, 0);
|
||||
var matchingPairs = new List<KeyValuePair<string, int>>();
|
||||
var profileWords = new Dictionary<string, List<KeyValuePair<string, int>>>();
|
||||
var allWords = new List<KeyValuePair<string, int>>();
|
||||
|
||||
_logger.Trace("Calculating preferred word score for '{0}'", title);
|
||||
_logger.Trace("Determining preferred word matches for '{0}'", title);
|
||||
|
||||
foreach (var releaseProfile in releaseProfiles)
|
||||
{
|
||||
var matchingPairs = new List<KeyValuePair<string, int>>();
|
||||
|
||||
if (!releaseProfile.IncludePreferredWhenRenaming)
|
||||
{
|
||||
continue;
|
||||
|
@ -76,11 +80,34 @@ namespace NzbDrone.Core.Profiles.Releases
|
|||
matchingPairs.Add(new KeyValuePair<string, int>(matchingTerm, preferredPair.Value));
|
||||
}
|
||||
}
|
||||
|
||||
if (matchingPairs.Count > 0)
|
||||
{
|
||||
if (releaseProfile.Name.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
var profileName = releaseProfile.Name.Trim();
|
||||
|
||||
if (!profileWords.ContainsKey(profileName))
|
||||
{
|
||||
profileWords.Add(profileName, new List<KeyValuePair<string, int>>());
|
||||
}
|
||||
|
||||
profileWords[profileName].AddRange(matchingPairs);
|
||||
}
|
||||
|
||||
allWords.AddRange(matchingPairs); // Add the "everything grouping"
|
||||
}
|
||||
}
|
||||
|
||||
return matchingPairs.OrderByDescending(p => p.Value)
|
||||
.Select(p => p.Key)
|
||||
.ToList();
|
||||
var results = new PreferredWordMatchResults()
|
||||
{
|
||||
All = allWords.OrderByDescending(m => m.Value).Select(m => m.Key).ToList(),
|
||||
ByReleaseProfile = profileWords.ToDictionary(item => item.Key, item => item.Value.OrderByDescending(m => m.Value).Select(m => m.Key).ToList())
|
||||
};
|
||||
|
||||
_logger.Trace("Determined preferred word matches for '{0}'. Count {1}", title, allWords.Count);
|
||||
|
||||
return results;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue