diff --git a/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderFixture.cs b/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderFixture.cs index 8106f6b87..a0eb1106e 100644 --- a/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderFixture.cs +++ b/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderFixture.cs @@ -874,5 +874,37 @@ namespace NzbDrone.Core.Test.OrganizerTests Subject.BuildFileName(new List { _episode1 }, _series, _episodeFile) .Should().Be("Sonarr"); } + + [Test] + public void should_scenify_series_title_when_using_period_separator() + { + _series.Title = "Girlfriends' Guide to Divorce"; + _namingConfig.StandardEpisodeFormat = "{Series.CleanTitle}"; + + Subject.BuildFileName(new List { _episode1 }, _series, _episodeFile) + .Should().Be("Girlfriends.Guide.to.Divorce"); + } + + [Test] + public void should_scenify_episode_title_when_using_period_separator() + { + _episode1.Title = "Rule #23: Never Lie to the Kids"; + + _namingConfig.StandardEpisodeFormat = "{Episode.CleanTitle}"; + + Subject.BuildFileName(new List { _episode1 }, _series, _episodeFile) + .Should().Be("Rule.23.Never.Lie.to.the.Kids"); + } + + [Test] + public void should_replace_forward_slash_sign_when_scenifying_episode_title() + { + _episode1.Title = "Anne Hathaway/Florence + The Machine"; + + _namingConfig.StandardEpisodeFormat = "{Episode.CleanTitle}"; + + Subject.BuildFileName(new List { _episode1 }, _series, _episodeFile) + .Should().Be("Anne.Hathaway.Florence.The.Machine"); + } } -} \ No newline at end of file +} diff --git a/src/NzbDrone.Core/Organizer/FileNameBuilder.cs b/src/NzbDrone.Core/Organizer/FileNameBuilder.cs index baa1bb622..0c90e6538 100644 --- a/src/NzbDrone.Core/Organizer/FileNameBuilder.cs +++ b/src/NzbDrone.Core/Organizer/FileNameBuilder.cs @@ -56,6 +56,9 @@ namespace NzbDrone.Core.Organizer private static readonly Regex FileNameCleanupRegex = new Regex(@"([- ._])(\1)+", RegexOptions.Compiled); private static readonly Regex TrimSeparatorsRegex = new Regex(@"[- ._]$", RegexOptions.Compiled); + private static readonly Regex ScenifyRemoveChars = new Regex(@"[^a-z0-9+\/ ]", RegexOptions.Compiled | RegexOptions.IgnoreCase); + private static readonly Regex ScenifyReplaceChars = new Regex(@"[+\/]", RegexOptions.Compiled | RegexOptions.IgnoreCase); + private static readonly char[] EpisodeTitleTrimCharacters = new[] { ' ', '.', '?' }; public FileNameBuilder(INamingConfigService namingConfigService, @@ -232,18 +235,12 @@ namespace NzbDrone.Core.Organizer return CleanFolderName(ReplaceTokens(namingConfig.SeasonFolderFormat, tokenHandlers)); } - public static string CleanTitle(string name) + public static string CleanTitle(string title) { - string[] dropCharacters = { ":", ".", "(", ")" }; - - string result = name; - - for (int i = 0; i < dropCharacters.Length; i++) - { - result = result.Replace(dropCharacters[i], ""); - } + title = ScenifyReplaceChars.Replace(title, " "); + title = ScenifyRemoveChars.Replace(title, String.Empty); - return result; + return title; } public static string CleanFileName(string name) @@ -411,6 +408,7 @@ namespace NzbDrone.Core.Organizer } tokenHandlers["{Episode Title}"] = m => GetEpisodeTitle(episodes); + tokenHandlers["{Episode CleanTitle}"] = m => CleanTitle(GetEpisodeTitle(episodes)); } private void AddEpisodeFileTokens(Dictionary> tokenHandlers, Series series, EpisodeFile episodeFile) @@ -715,4 +713,4 @@ namespace NzbDrone.Core.Organizer Scene = 3, Range = 4 } -} \ No newline at end of file +} diff --git a/src/UI/Settings/MediaManagement/Naming/Partials/EpisodeTitleNamingPartial.hbs b/src/UI/Settings/MediaManagement/Naming/Partials/EpisodeTitleNamingPartial.hbs index d4ae003d6..17128f526 100644 --- a/src/UI/Settings/MediaManagement/Naming/Partials/EpisodeTitleNamingPartial.hbs +++ b/src/UI/Settings/MediaManagement/Naming/Partials/EpisodeTitleNamingPartial.hbs @@ -4,5 +4,8 @@
  • Episode Title
  • Episode.Title
  • Episode_Title
  • +
  • Episode CleanTitle
  • +
  • Episode.CleanTitle
  • +
  • Episode_CleanTitle