diff --git a/src/NzbDrone.Api/Config/NamingConfigResource.cs b/src/NzbDrone.Api/Config/NamingConfigResource.cs
index 9ca779dac..1e5ab16e3 100644
--- a/src/NzbDrone.Api/Config/NamingConfigResource.cs
+++ b/src/NzbDrone.Api/Config/NamingConfigResource.cs
@@ -9,8 +9,8 @@ namespace NzbDrone.Api.Config
public Int32 MultiEpisodeStyle { get; set; }
public string StandardEpisodeFormat { get; set; }
public string DailyEpisodeFormat { get; set; }
+ public string SeriesFolderFormat { get; set; }
public string SeasonFolderFormat { get; set; }
-
public bool IncludeSeriesTitle { get; set; }
public bool IncludeEpisodeTitle { get; set; }
public bool IncludeQuality { get; set; }
diff --git a/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj b/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj
index f4a352f2e..dd0723b87 100644
--- a/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj
+++ b/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj
@@ -176,6 +176,7 @@
+
diff --git a/src/NzbDrone.Core.Test/OrganizerTests/GetSeriesFolderFixture.cs b/src/NzbDrone.Core.Test/OrganizerTests/GetSeriesFolderFixture.cs
new file mode 100644
index 000000000..abe7bf78b
--- /dev/null
+++ b/src/NzbDrone.Core.Test/OrganizerTests/GetSeriesFolderFixture.cs
@@ -0,0 +1,33 @@
+using FluentAssertions;
+using NUnit.Framework;
+using NzbDrone.Core.Organizer;
+using NzbDrone.Core.Test.Framework;
+
+namespace NzbDrone.Core.Test.OrganizerTests
+{
+ [TestFixture]
+
+ public class GetSeriesFolderFixture : CoreTest
+ {
+ private NamingConfig namingConfig;
+
+ [SetUp]
+ public void Setup()
+ {
+ namingConfig = new NamingConfig();
+
+ Mocker.GetMock()
+ .Setup(c => c.GetConfig()).Returns(namingConfig);
+ }
+
+ [TestCase("30 Rock", "{Series Title}", "30 Rock")]
+ [TestCase("30 Rock", "{Series.Title}", "30.Rock")]
+ [TestCase("24/7 Road to the NHL Winter Classic", "{Series Title}", "24+7 Road to the NHL Winter Classic")]
+ public void should_use_seriesFolderFormat_to_build_folder_name(string seriesTitle, string format, string expected)
+ {
+ namingConfig.SeriesFolderFormat = format;
+
+ Subject.GetSeriesFolder(seriesTitle).Should().Be(expected);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/NzbDrone.Core/Datastore/Migration/035_add_series_folder_format_to_naming_config.cs b/src/NzbDrone.Core/Datastore/Migration/035_add_series_folder_format_to_naming_config.cs
new file mode 100644
index 000000000..9423a54f0
--- /dev/null
+++ b/src/NzbDrone.Core/Datastore/Migration/035_add_series_folder_format_to_naming_config.cs
@@ -0,0 +1,16 @@
+using FluentMigrator;
+using NzbDrone.Core.Datastore.Migration.Framework;
+
+namespace NzbDrone.Core.Datastore.Migration
+{
+ [Migration(35)]
+ public class add_series_folder_format_to_naming_config : NzbDroneMigrationBase
+ {
+ protected override void MainDbUpgrade()
+ {
+ Alter.Table("NamingConfig").AddColumn("SeriesFolderFormat").AsString().Nullable();
+
+ Execute.Sql("UPDATE NamingConfig SET SeriesFolderFormat = '{Series Title}'");
+ }
+ }
+}
diff --git a/src/NzbDrone.Core/NzbDrone.Core.csproj b/src/NzbDrone.Core/NzbDrone.Core.csproj
index 4567bc73a..5dbf4fd48 100644
--- a/src/NzbDrone.Core/NzbDrone.Core.csproj
+++ b/src/NzbDrone.Core/NzbDrone.Core.csproj
@@ -190,6 +190,7 @@
+
diff --git a/src/NzbDrone.Core/Organizer/FileNameBuilder.cs b/src/NzbDrone.Core/Organizer/FileNameBuilder.cs
index 4a1abfed5..905b73456 100644
--- a/src/NzbDrone.Core/Organizer/FileNameBuilder.cs
+++ b/src/NzbDrone.Core/Organizer/FileNameBuilder.cs
@@ -16,6 +16,7 @@ namespace NzbDrone.Core.Organizer
string BuildFilename(IList episodes, Series series, EpisodeFile episodeFile, NamingConfig namingConfig);
string BuildFilePath(Series series, int seasonNumber, string fileName, string extension);
BasicNamingConfig GetBasicNamingConfig(NamingConfig nameSpec);
+ string GetSeriesFolder(string seriesTitle);
}
public class FileNameBuilder : IBuildFileNames
@@ -151,6 +152,7 @@ namespace NzbDrone.Core.Organizer
public string BuildFilePath(Series series, int seasonNumber, string fileName, string extension)
{
string path = series.Path;
+
if (series.SeasonFolder)
{
string seasonFolder;
@@ -222,6 +224,17 @@ namespace NzbDrone.Core.Organizer
return basicNamingConfig;
}
+ public string GetSeriesFolder(string seriesTitle)
+ {
+ seriesTitle = CleanFilename(seriesTitle);
+
+ var nameSpec = _namingConfigService.GetConfig();
+ var tokenValues = new Dictionary(FilenameBuilderTokenEqualityComparer.Instance);
+ tokenValues.Add("{Series Title}", seriesTitle);
+
+ return ReplaceTokens(nameSpec.SeriesFolderFormat, tokenValues);
+ }
+
public static string CleanFilename(string name)
{
string result = name;
diff --git a/src/NzbDrone.Core/Organizer/NamingConfig.cs b/src/NzbDrone.Core/Organizer/NamingConfig.cs
index 7a537e3ce..fcfcdd940 100644
--- a/src/NzbDrone.Core/Organizer/NamingConfig.cs
+++ b/src/NzbDrone.Core/Organizer/NamingConfig.cs
@@ -14,6 +14,7 @@ namespace NzbDrone.Core.Organizer
MultiEpisodeStyle = 0,
StandardEpisodeFormat = "{Series Title} - S{season:00}E{episode:00} - {Episode Title} {Quality Title}",
DailyEpisodeFormat = "{Series Title} - {Air-Date} - {Episode Title} {Quality Title}",
+ SeriesFolderFormat = "{Series Title}",
SeasonFolderFormat = "Season {season}"
};
}
@@ -23,6 +24,7 @@ namespace NzbDrone.Core.Organizer
public int MultiEpisodeStyle { get; set; }
public string StandardEpisodeFormat { get; set; }
public string DailyEpisodeFormat { get; set; }
+ public string SeriesFolderFormat { get; set; }
public string SeasonFolderFormat { get; set; }
}
}
\ No newline at end of file
diff --git a/src/NzbDrone.Core/Tv/SeriesService.cs b/src/NzbDrone.Core/Tv/SeriesService.cs
index 18b67a732..5387f3704 100644
--- a/src/NzbDrone.Core/Tv/SeriesService.cs
+++ b/src/NzbDrone.Core/Tv/SeriesService.cs
@@ -31,24 +31,24 @@ namespace NzbDrone.Core.Tv
public class SeriesService : ISeriesService
{
private readonly ISeriesRepository _seriesRepository;
- private readonly IConfigService _configService;
private readonly IEventAggregator _eventAggregator;
private readonly ISceneMappingService _sceneMappingService;
private readonly IEpisodeService _episodeService;
+ private readonly IBuildFileNames _fileNameBuilder;
private readonly Logger _logger;
public SeriesService(ISeriesRepository seriesRepository,
- IConfigService configServiceService,
IEventAggregator eventAggregator,
ISceneMappingService sceneMappingService,
IEpisodeService episodeService,
+ IBuildFileNames fileNameBuilder,
Logger logger)
{
_seriesRepository = seriesRepository;
- _configService = configServiceService;
_eventAggregator = eventAggregator;
_sceneMappingService = sceneMappingService;
_episodeService = episodeService;
+ _fileNameBuilder = fileNameBuilder;
_logger = logger;
}
@@ -63,7 +63,7 @@ namespace NzbDrone.Core.Tv
if (String.IsNullOrWhiteSpace(newSeries.Path))
{
- var folderName = FileNameBuilder.CleanFilename(newSeries.Title);
+ var folderName = _fileNameBuilder.GetSeriesFolder(newSeries.Title);
newSeries.Path = Path.Combine(newSeries.RootFolderPath, folderName);
}
diff --git a/src/UI/Settings/MediaManagement/Naming/NamingViewTemplate.html b/src/UI/Settings/MediaManagement/Naming/NamingViewTemplate.html
index 33586db4a..af3839918 100644
--- a/src/UI/Settings/MediaManagement/Naming/NamingViewTemplate.html
+++ b/src/UI/Settings/MediaManagement/Naming/NamingViewTemplate.html
@@ -98,6 +98,24 @@
+
+
+
+
+
+