From 3973571411b466a18d0ce6de828ed837683247ed Mon Sep 17 00:00:00 2001 From: Stevie Robinson Date: Sun, 22 Jan 2023 00:55:00 +0100 Subject: [PATCH] New: Added new series title rename tokens without year Closes #5369 --- .../MediaManagement/Naming/NamingModal.js | 3 + .../CleanTitleWithoutYearFixture.cs | 78 ++++++++++++++++++ .../TitleTheWithoutYearFixture.cs | 79 +++++++++++++++++++ .../TitleWithoutYearFixture.cs | 78 ++++++++++++++++++ .../Organizer/FileNameBuilder.cs | 12 ++- .../Organizer/FileNameValidation.cs | 2 +- 6 files changed, 250 insertions(+), 2 deletions(-) create mode 100644 src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/CleanTitleWithoutYearFixture.cs create mode 100644 src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/TitleTheWithoutYearFixture.cs create mode 100644 src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/TitleWithoutYearFixture.cs diff --git a/frontend/src/Settings/MediaManagement/Naming/NamingModal.js b/frontend/src/Settings/MediaManagement/Naming/NamingModal.js index 48d2c7be8..3d2530048 100644 --- a/frontend/src/Settings/MediaManagement/Naming/NamingModal.js +++ b/frontend/src/Settings/MediaManagement/Naming/NamingModal.js @@ -46,9 +46,12 @@ const seriesTokens = [ { token: '{Series Title}', example: 'Series Title\'s' }, { token: '{Series CleanTitle}', example: 'Series Titles' }, { token: '{Series CleanTitleYear}', example: 'Series Titles! 2010' }, + { token: '{Series CleanTitleWithoutYear}', example: 'Series Titles!' }, { token: '{Series TitleThe}', example: 'Series Title\'s, The' }, { token: '{Series TitleTheYear}', example: 'Series Title\'s, The (2010)' }, + { token: '{Series TitleTheWithoutYear}', example: 'Series Title\'s, The' }, { token: '{Series TitleYear}', example: 'Series Title\'s (2010)' }, + { token: '{Series TitleWithoutYear}', example: 'Series Title\'s' }, { token: '{Series TitleFirstCharacter}', example: 'S' }, { token: '{Series Year}', example: '2010' } ]; diff --git a/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/CleanTitleWithoutYearFixture.cs b/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/CleanTitleWithoutYearFixture.cs new file mode 100644 index 000000000..1cf761402 --- /dev/null +++ b/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/CleanTitleWithoutYearFixture.cs @@ -0,0 +1,78 @@ +using System.Collections.Generic; +using System.Linq; +using FizzWare.NBuilder; +using FluentAssertions; +using NUnit.Framework; +using NzbDrone.Core.CustomFormats; +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 CleanTitleWithoutYearFixture : 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)); + + Mocker.GetMock() + .Setup(v => v.All()) + .Returns(new List()); + } + + [TestCase("The Mist", 2018, "The Mist")] + [TestCase("The Rat Pack (A&E)", 1999, "The Rat Pack AandE")] + [TestCase("The Climax: I (Almost) Got Away With It (2016)", 2016, "The Climax I Almost Got Away With It")] + public void should_get_expected_title_back(string title, int year, string expected) + { + _series.Title = title; + _series.Year = year; + _namingConfig.StandardEpisodeFormat = "{Series CleanTitleWithoutYear}"; + + Subject.BuildFileName(new List { _episode }, _series, _episodeFile) + .Should().Be(expected); + } + + [Test] + public void should_not_include_0_for_year() + { + _series.Title = "The Alienist"; + _series.Year = 0; + _namingConfig.StandardEpisodeFormat = "{Series CleanTitleWithoutYear}"; + + Subject.BuildFileName(new List { _episode }, _series, _episodeFile) + .Should().Be("The Alienist"); + } + } +} diff --git a/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/TitleTheWithoutYearFixture.cs b/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/TitleTheWithoutYearFixture.cs new file mode 100644 index 000000000..8662a9f8a --- /dev/null +++ b/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/TitleTheWithoutYearFixture.cs @@ -0,0 +1,79 @@ +using System.Collections.Generic; +using System.Linq; +using FizzWare.NBuilder; +using FluentAssertions; +using NUnit.Framework; +using NzbDrone.Core.CustomFormats; +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 TitleTheWithoutYearFixture : 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)); + + Mocker.GetMock() + .Setup(v => v.All()) + .Returns(new List()); + } + + [TestCase("The Mist", 2018, "Mist, The")] + [TestCase("The Rat Pack (A&E)", 1999, "Rat Pack, The (A&E)")] + [TestCase("The Climax: I (Almost) Got Away With It (2016)", 2016, "Climax - I (Almost) Got Away With It, The")] + [TestCase("A", 2017, "A")] + public void should_get_expected_title_back(string title, int year, string expected) + { + _series.Title = title; + _series.Year = year; + _namingConfig.StandardEpisodeFormat = "{Series TitleTheWithoutYear}"; + + Subject.BuildFileName(new List { _episode }, _series, _episodeFile) + .Should().Be(expected); + } + + [Test] + public void should_not_include_0_for_year() + { + _series.Title = "The Alienist"; + _series.Year = 0; + _namingConfig.StandardEpisodeFormat = "{Series TitleTheWithoutYear}"; + + Subject.BuildFileName(new List { _episode }, _series, _episodeFile) + .Should().Be("Alienist, The"); + } + } +} diff --git a/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/TitleWithoutYearFixture.cs b/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/TitleWithoutYearFixture.cs new file mode 100644 index 000000000..c7422af33 --- /dev/null +++ b/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/TitleWithoutYearFixture.cs @@ -0,0 +1,78 @@ +using System.Collections.Generic; +using System.Linq; +using FizzWare.NBuilder; +using FluentAssertions; +using NUnit.Framework; +using NzbDrone.Core.CustomFormats; +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 TitleWithoutYearFixture : 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)); + + Mocker.GetMock() + .Setup(v => v.All()) + .Returns(new List()); + } + + [TestCase("The Mist", 2018, "The Mist")] + [TestCase("The Rat Pack (A&E)", 1999, "The Rat Pack (A&E)")] + [TestCase("The Climax: I (Almost) Got Away With It (2016)", 2016, "The Climax - I (Almost) Got Away With It")] + public void should_get_expected_title_back(string title, int year, string expected) + { + _series.Title = title; + _series.Year = year; + _namingConfig.StandardEpisodeFormat = "{Series TitleWithoutYear}"; + + Subject.BuildFileName(new List { _episode }, _series, _episodeFile) + .Should().Be(expected); + } + + [Test] + public void should_not_include_0_for_year() + { + _series.Title = "The Alienist"; + _series.Year = 0; + _namingConfig.StandardEpisodeFormat = "{Series TitleWithoutYear}"; + + Subject.BuildFileName(new List { _episode }, _series, _episodeFile) + .Should().Be("The Alienist"); + } + } +} diff --git a/src/NzbDrone.Core/Organizer/FileNameBuilder.cs b/src/NzbDrone.Core/Organizer/FileNameBuilder.cs index 205d7fbb5..86cc2d294 100644 --- a/src/NzbDrone.Core/Organizer/FileNameBuilder.cs +++ b/src/NzbDrone.Core/Organizer/FileNameBuilder.cs @@ -66,7 +66,7 @@ namespace NzbDrone.Core.Organizer 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)?(Year)?\})", + public static readonly Regex SeriesTitleRegex = new Regex(@"(?\{(?:Series)(?[- ._])(Clean)?Title(The)?(Without)?(Year)?\})", RegexOptions.Compiled | RegexOptions.IgnoreCase); private static readonly Regex FileNameCleanupRegex = new Regex(@"([- ._])(\1)+", RegexOptions.Compiled); @@ -370,6 +370,13 @@ namespace NzbDrone.Core.Organizer return $"{title} ({year})"; } + public static string TitleWithoutYear(string title) + { + title = YearRegex.Replace(title, ""); + + return title; + } + public static string CleanFileName(string name, bool replace = true) { string result = name; @@ -453,9 +460,12 @@ namespace NzbDrone.Core.Organizer 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 CleanTitleWithoutYear}"] = m => CleanTitle(TitleWithoutYear(series.Title)); tokenHandlers["{Series TitleThe}"] = m => TitleThe(series.Title); tokenHandlers["{Series TitleYear}"] = m => TitleYear(series.Title, series.Year); + tokenHandlers["{Series TitleWithoutYear}"] = m => TitleWithoutYear(series.Title); tokenHandlers["{Series TitleTheYear}"] = m => TitleYear(TitleThe(series.Title), series.Year); + tokenHandlers["{Series TitleTheWithoutYear}"] = m => TitleWithoutYear(TitleThe(series.Title)); tokenHandlers["{Series TitleFirstCharacter}"] = m => TitleThe(series.Title).Substring(0, 1).FirstCharToUpper(); tokenHandlers["{Series Year}"] = m => series.Year.ToString(); } diff --git a/src/NzbDrone.Core/Organizer/FileNameValidation.cs b/src/NzbDrone.Core/Organizer/FileNameValidation.cs index 8efe5fc4d..0ae7987f6 100644 --- a/src/NzbDrone.Core/Organizer/FileNameValidation.cs +++ b/src/NzbDrone.Core/Organizer/FileNameValidation.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.RegularExpressions;