diff --git a/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/TitleTheFixture.cs b/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/TitleTheFixture.cs new file mode 100644 index 000000000..1c49b444a --- /dev/null +++ b/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/TitleTheFixture.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.Movies; +using NzbDrone.Core.Organizer; +using NzbDrone.Core.Qualities; +using NzbDrone.Core.Test.Framework; + +namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests +{ + [TestFixture] + public class TitleTheFixture : CoreTest + { + private Movie _movie; + private MovieFile _movieFile; + private NamingConfig _namingConfig; + + [SetUp] + public void Setup() + { + _movie = Builder + .CreateNew() + .With(e => e.Title = "Batman") + .Build(); + + _movieFile = new MovieFile { Quality = new QualityModel(Quality.HDTV720p), ReleaseGroup = "RadarrTest" }; + + _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", "Mist, The")] + [TestCase("A Place to Call Home", "Place to Call Home, A")] + [TestCase("An Adventure in Space and Time", "Adventure in Space and Time, An")] + [TestCase("The Flash (2010)", "Flash, The (2010)")] + [TestCase("A League Of Their Own (AU)", "League Of Their Own, A (AU)")] + [TestCase("The Fixer (ZH) (2015)", "Fixer, The (ZH) (2015)")] + [TestCase("The Sixth Sense 2 (Thai)", "Sixth Sense 2, The (Thai)")] + [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)")] + public void should_get_expected_title_back(string title, string expected) + { + _movie.Title = title; + _namingConfig.StandardMovieFormat = "{Movie TitleThe}"; + + Subject.BuildFileName(_movie, _movieFile) + .Should().Be(expected); + } + + [TestCase("A")] + [TestCase("Anne")] + [TestCase("Theodore")] + [TestCase("3%")] + public void should_not_change_title(string title) + { + _movie.Title = title; + _namingConfig.StandardMovieFormat = "{Movie TitleThe}"; + + Subject.BuildFileName(_movie, _movieFile) + .Should().Be(title); + } + } +} diff --git a/src/NzbDrone.Core/Organizer/FileNameBuilder.cs b/src/NzbDrone.Core/Organizer/FileNameBuilder.cs index 6eb20bca5..155ad573a 100644 --- a/src/NzbDrone.Core/Organizer/FileNameBuilder.cs +++ b/src/NzbDrone.Core/Organizer/FileNameBuilder.cs @@ -64,6 +64,8 @@ namespace NzbDrone.Core.Organizer private static readonly char[] EpisodeTitleTrimCharacters = new[] { ' ', '.', '?' }; + private static readonly Regex TitlePrefixRegex = new Regex(@"^(The|An|A) (.*?)((?: *\([^)]+\))*)$", RegexOptions.Compiled | RegexOptions.IgnoreCase); + public FileNameBuilder(INamingConfigService namingConfigService, IQualityDefinitionService qualityDefinitionService, IUpdateMediaInfo mediaInfoUpdater, @@ -167,24 +169,7 @@ namespace NzbDrone.Core.Organizer public static string TitleThe(string title) { - string[] prefixes = { "The ", "An ", "A " }; - - if (title.Length < 5) - { - return title; - } - - foreach (string prefix in prefixes) - { - int prefix_length = prefix.Length; - if (prefix.ToLower() == title.Substring(0, prefix_length).ToLower()) - { - title = title.Substring(prefix_length) + ", " + prefix.Trim(); - break; - } - } - - return title.Trim(); + return TitlePrefixRegex.Replace(title, "$2, $1$3"); } public static string CleanFileName(string name, bool replace = true, ColonReplacementFormat colonReplacement = ColonReplacementFormat.Delete)