diff --git a/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj b/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj index fa0396a3d..53cb10061 100644 --- a/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj +++ b/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj @@ -336,6 +336,9 @@ + + + diff --git a/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/CleanTitleYearFixture.cs b/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/CleanTitleYearFixture.cs new file mode 100644 index 000000000..7a4bc5a2d --- /dev/null +++ b/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/CleanTitleYearFixture.cs @@ -0,0 +1,62 @@ +using System.Collections.Generic; +using System.Linq; +using FizzWare.NBuilder; +using FluentAssertions; +using NUnit.Framework; +using NzbDrone.Core.MediaFiles; +using NzbDrone.Core.Organizer; +using NzbDrone.Core.Qualities; +using NzbDrone.Core.Test.Framework; +using NzbDrone.Core.Tv; + +namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests +{ + [TestFixture] + public class CleanTitleYearFixture : CoreTest + { + private Series _series; + private Episode _episode; + private EpisodeFile _episodeFile; + private NamingConfig _namingConfig; + + [SetUp] + public void Setup() + { + _series = Builder + .CreateNew() + .Build(); + + _episode = Builder.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" }; + + _namingConfig = NamingConfig.Default; + _namingConfig.RenameEpisodes = true; + + Mocker.GetMock() + .Setup(c => c.GetConfig()).Returns(_namingConfig); + + Mocker.GetMock() + .Setup(v => v.Get(Moq.It.IsAny())) + .Returns(v => Quality.DefaultQualityDefinitions.First(c => c.Quality == v)); + } + + [TestCase("The Mist", 2018, "The Mist 2018")] + [TestCase("The Rat Pack (A&E)", 1999, "The Rat Pack AandE 1999")] + [TestCase("The Climax: I (Almost) Got Away With It (2016)", 2016, "The Climax I Almost Got Away With It 2016")] + public void should_get_expected_title_back(string title, int year, string expected) + { + _series.Title = title; + _series.Year = year; + _namingConfig.StandardEpisodeFormat = "{Series CleanTitleYear}"; + + Subject.BuildFileName(new List { _episode }, _series, _episodeFile) + .Should().Be(expected); + } + } +} diff --git a/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/FileNameBuilderFixture.cs b/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/FileNameBuilderFixture.cs index e28bc58f5..fdc1069fe 100644 --- a/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/FileNameBuilderFixture.cs +++ b/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/FileNameBuilderFixture.cs @@ -491,8 +491,10 @@ public void should_format_mediainfo_properly() { VideoCodec = "AVC", AudioFormat = "DTS", + AudioChannels = 6, AudioLanguages = "English/Spanish", - Subtitles = "English/Spanish/Italian" + Subtitles = "English/Spanish/Italian", + SchemaRevision = 3 }; Subject.BuildFileName(new List { _episode1 }, _series, _episodeFile) @@ -508,8 +510,10 @@ public void should_exclude_english_in_mediainfo_audio_language() { VideoCodec = "AVC", AudioFormat = "DTS", + AudioChannels = 6, AudioLanguages = "English", - Subtitles = "English/Spanish/Italian" + Subtitles = "English/Spanish/Italian", + SchemaRevision = 3 }; Subject.BuildFileName(new List { _episode1 }, _series, _episodeFile) diff --git a/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/TitleTheFixture.cs b/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/TitleTheFixture.cs index 8145ead25..dcdded4eb 100644 --- a/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/TitleTheFixture.cs +++ b/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/TitleTheFixture.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using FizzWare.NBuilder; using FluentAssertions; @@ -24,7 +24,6 @@ public void Setup() { _series = Builder .CreateNew() - .With(s => s.Title = "South Park") .Build(); _episode = Builder.CreateNew() @@ -57,7 +56,6 @@ public void Setup() [TestCase("The Amazing Race (Latin America)", "Amazing Race, The (Latin America)")] [TestCase("The Rat Pack (A&E)", "Rat Pack, The (A&E)")] [TestCase("The Climax: I (Almost) Got Away With It (2016)", "Climax- I (Almost) Got Away With It, The (2016)")] - //[TestCase("", "")] public void should_get_expected_title_back(string title, string expected) { _series.Title = title; diff --git a/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/TitleTheYearFixture.cs b/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/TitleTheYearFixture.cs new file mode 100644 index 000000000..f55ebacdc --- /dev/null +++ b/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/TitleTheYearFixture.cs @@ -0,0 +1,63 @@ +using System.Collections.Generic; +using System.Linq; +using FizzWare.NBuilder; +using FluentAssertions; +using NUnit.Framework; +using NzbDrone.Core.MediaFiles; +using NzbDrone.Core.Organizer; +using NzbDrone.Core.Qualities; +using NzbDrone.Core.Test.Framework; +using NzbDrone.Core.Tv; + +namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests +{ + [TestFixture] + public class TitleTheYearFixture : CoreTest + { + private Series _series; + private Episode _episode; + private EpisodeFile _episodeFile; + private NamingConfig _namingConfig; + + [SetUp] + public void Setup() + { + _series = Builder + .CreateNew() + .Build(); + + _episode = Builder.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" }; + + _namingConfig = NamingConfig.Default; + _namingConfig.RenameEpisodes = true; + + Mocker.GetMock() + .Setup(c => c.GetConfig()).Returns(_namingConfig); + + Mocker.GetMock() + .Setup(v => v.Get(Moq.It.IsAny())) + .Returns(v => Quality.DefaultQualityDefinitions.First(c => c.Quality == v)); + } + + [TestCase("The Mist", 2018, "Mist, The (2018)")] + [TestCase("The Rat Pack (A&E)", 1999, "Rat Pack, The (A&E) (1999)")] + [TestCase("The Climax: I (Almost) Got Away With It (2016)", 2016, "Climax- I (Almost) Got Away With It, The (2016)")] + [TestCase("A", 2017, "A (2017)")] + public void should_get_expected_title_back(string title, int year, string expected) + { + _series.Title = title; + _series.Year = year; + _namingConfig.StandardEpisodeFormat = "{Series TitleTheYear}"; + + Subject.BuildFileName(new List { _episode }, _series, _episodeFile) + .Should().Be(expected); + } + } +} diff --git a/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/TitleYearFixture.cs b/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/TitleYearFixture.cs new file mode 100644 index 000000000..1c2f03a94 --- /dev/null +++ b/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/TitleYearFixture.cs @@ -0,0 +1,62 @@ +using System.Collections.Generic; +using System.Linq; +using FizzWare.NBuilder; +using FluentAssertions; +using NUnit.Framework; +using NzbDrone.Core.MediaFiles; +using NzbDrone.Core.Organizer; +using NzbDrone.Core.Qualities; +using NzbDrone.Core.Test.Framework; +using NzbDrone.Core.Tv; + +namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests +{ + [TestFixture] + public class TitleYearFixture : CoreTest + { + private Series _series; + private Episode _episode; + private EpisodeFile _episodeFile; + private NamingConfig _namingConfig; + + [SetUp] + public void Setup() + { + _series = Builder + .CreateNew() + .Build(); + + _episode = Builder.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" }; + + _namingConfig = NamingConfig.Default; + _namingConfig.RenameEpisodes = true; + + Mocker.GetMock() + .Setup(c => c.GetConfig()).Returns(_namingConfig); + + Mocker.GetMock() + .Setup(v => v.Get(Moq.It.IsAny())) + .Returns(v => Quality.DefaultQualityDefinitions.First(c => c.Quality == v)); + } + + [TestCase("The Mist", 2018, "The Mist (2018)")] + [TestCase("The Rat Pack (A&E)", 1999, "The Rat Pack (A&E) (1999)")] + [TestCase("The Climax: I (Almost) Got Away With It (2016)", 2016, "The Climax- I (Almost) Got Away With It (2016)")] + public void should_get_expected_title_back(string title, int year, string expected) + { + _series.Title = title; + _series.Year = year; + _namingConfig.StandardEpisodeFormat = "{Series TitleYear}"; + + Subject.BuildFileName(new List { _episode }, _series, _episodeFile) + .Should().Be(expected); + } + } +} diff --git a/src/NzbDrone.Core/Organizer/FileNameBuilder.cs b/src/NzbDrone.Core/Organizer/FileNameBuilder.cs index 34f1e19c1..26d63a06b 100644 --- a/src/NzbDrone.Core/Organizer/FileNameBuilder.cs +++ b/src/NzbDrone.Core/Organizer/FileNameBuilder.cs @@ -55,7 +55,7 @@ public class FileNameBuilder : IBuildFileNames public static readonly Regex AirDateRegex = new Regex(@"\{Air(\s|\W|_)Date\}", RegexOptions.Compiled | RegexOptions.IgnoreCase); - public static readonly Regex SeriesTitleRegex = new Regex(@"(?\{(?:Series)(?[- ._])(Clean)?Title(The)?\})", + public static readonly Regex SeriesTitleRegex = new Regex(@"(?\{(?:Series)(?[- ._])(Clean)?Title(The)?(Year)?\})", RegexOptions.Compiled | RegexOptions.IgnoreCase); private static readonly Regex FileNameCleanupRegex = new Regex(@"([- ._])(\1)+", RegexOptions.Compiled); @@ -71,6 +71,8 @@ public class FileNameBuilder : IBuildFileNames private static readonly Regex TitlePrefixRegex = new Regex(@"^(The|An|A) (.*?)((?: *\([^)]+\))*)$", RegexOptions.Compiled | RegexOptions.IgnoreCase); + private static readonly Regex YearRegex = new Regex(@"\(\d{4}\)$", RegexOptions.Compiled | RegexOptions.IgnoreCase); + public FileNameBuilder(INamingConfigService namingConfigService, IQualityDefinitionService qualityDefinitionService, ICacheManager cacheManager, @@ -263,6 +265,17 @@ public static string TitleThe(string title) return TitlePrefixRegex.Replace(title, "$2, $1$3"); } + public static string TitleYear(string title, int year) + { + // Regex match incase the year in the title doesn't match the year, for whatever reason. + if (YearRegex.IsMatch(title)) + { + return title; + } + + return $"{title} ({year})"; + } + public static string CleanFileName(string name, bool replace = true) { string result = name; @@ -321,7 +334,10 @@ private void AddSeriesTokens(Dictionary> tokenH { tokenHandlers["{Series Title}"] = m => series.Title; tokenHandlers["{Series CleanTitle}"] = m => CleanTitle(series.Title); + tokenHandlers["{Series CleanTitleYear}"] = m => CleanTitle(TitleYear(series.Title, series.Year)); tokenHandlers["{Series TitleThe}"] = m => TitleThe(series.Title); + tokenHandlers["{Series TitleYear}"] = m => TitleYear(series.Title, series.Year); + tokenHandlers["{Series TitleTheYear}"] = m => TitleYear(TitleThe(series.Title), series.Year); } private string AddSeasonEpisodeNumberingTokens(string pattern, Dictionary> tokenHandlers, List episodes, NamingConfig namingConfig) diff --git a/src/NzbDrone.Core/Organizer/FileNameSampleService.cs b/src/NzbDrone.Core/Organizer/FileNameSampleService.cs index de1046485..78f076b5f 100644 --- a/src/NzbDrone.Core/Organizer/FileNameSampleService.cs +++ b/src/NzbDrone.Core/Organizer/FileNameSampleService.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using NzbDrone.Core.MediaFiles; using NzbDrone.Core.Qualities; using NzbDrone.Core.Tv; @@ -41,19 +41,22 @@ public FileNameSampleService(IBuildFileNames buildFileNames) _standardSeries = new Series { SeriesType = SeriesTypes.Standard, - Title = "The Series Title (2010)" + Title = "The Series Title!", + Year = 2010 }; _dailySeries = new Series { SeriesType = SeriesTypes.Daily, - Title = "The Series Title (2010)" + Title = "The Series Title!", + Year = 2010 }; _animeSeries = new Series { SeriesType = SeriesTypes.Anime, - Title = "The Series Title (2010)" + Title = "The Series Title!", + Year = 2010 }; _episode1 = new Episode