Rewrote most of the renamer token handling code to give it a bit more generic architecture. Also added MediaInfo as possible token.
This commit is contained in:
parent
7b420fc033
commit
8a5edfeaf5
|
@ -85,19 +85,19 @@ namespace NzbDrone.Api.Config
|
|||
|
||||
sampleResource.SingleEpisodeExample = _filenameValidationService.ValidateStandardFilename(singleEpisodeSampleResult) != null
|
||||
? "Invalid format"
|
||||
: singleEpisodeSampleResult.Filename;
|
||||
: singleEpisodeSampleResult.FileName;
|
||||
|
||||
sampleResource.MultiEpisodeExample = _filenameValidationService.ValidateStandardFilename(multiEpisodeSampleResult) != null
|
||||
? "Invalid format"
|
||||
: multiEpisodeSampleResult.Filename;
|
||||
: multiEpisodeSampleResult.FileName;
|
||||
|
||||
sampleResource.DailyEpisodeExample = _filenameValidationService.ValidateDailyFilename(dailyEpisodeSampleResult) != null
|
||||
? "Invalid format"
|
||||
: dailyEpisodeSampleResult.Filename;
|
||||
: dailyEpisodeSampleResult.FileName;
|
||||
|
||||
sampleResource.AnimeEpisodeExample = _filenameValidationService.ValidateAnimeFilename(animeEpisodeSampleResult) != null
|
||||
? "Invalid format"
|
||||
: animeEpisodeSampleResult.Filename;
|
||||
: animeEpisodeSampleResult.FileName;
|
||||
|
||||
sampleResource.SeriesFolderExample = nameSpec.SeriesFolderFormat.IsNullOrWhiteSpace()
|
||||
? "Invalid format"
|
||||
|
|
|
@ -39,7 +39,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeFileMovingServiceTests
|
|||
.Build();
|
||||
|
||||
Mocker.GetMock<IBuildFileNames>()
|
||||
.Setup(s => s.BuildFilename(It.IsAny<List<Episode>>(), It.IsAny<Series>(), It.IsAny<EpisodeFile>()))
|
||||
.Setup(s => s.BuildFileName(It.IsAny<List<Episode>>(), It.IsAny<Series>(), It.IsAny<EpisodeFile>(), null))
|
||||
.Returns("File Name");
|
||||
|
||||
Mocker.GetMock<IBuildFileNames>()
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
"Law & Order- Criminal Intent - S10E07 - Icarus [HDTV-720p]")]
|
||||
public void CleanFileName(string name, string expectedName)
|
||||
{
|
||||
FileNameBuilder.CleanFilename(name).Should().Be(expectedName);
|
||||
FileNameBuilder.CleanFileName(name).Should().Be(expectedName);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
|
|
@ -69,7 +69,7 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
{
|
||||
_namingConfig.StandardEpisodeFormat = "{Series Title}";
|
||||
|
||||
Subject.BuildFilename(new List<Episode> {_episode1}, _series, _episodeFile)
|
||||
Subject.BuildFileName(new List<Episode> {_episode1}, _series, _episodeFile)
|
||||
.Should().Be("South Park");
|
||||
}
|
||||
|
||||
|
@ -78,7 +78,7 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
{
|
||||
_namingConfig.StandardEpisodeFormat = "{Series_Title}";
|
||||
|
||||
Subject.BuildFilename(new List<Episode> {_episode1}, _series, _episodeFile)
|
||||
Subject.BuildFileName(new List<Episode> {_episode1}, _series, _episodeFile)
|
||||
.Should().Be("South_Park");
|
||||
}
|
||||
|
||||
|
@ -87,7 +87,7 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
{
|
||||
_namingConfig.StandardEpisodeFormat = "{Series.Title}";
|
||||
|
||||
Subject.BuildFilename(new List<Episode> {_episode1}, _series, _episodeFile)
|
||||
Subject.BuildFileName(new List<Episode> {_episode1}, _series, _episodeFile)
|
||||
.Should().Be("South.Park");
|
||||
}
|
||||
|
||||
|
@ -96,7 +96,7 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
{
|
||||
_namingConfig.StandardEpisodeFormat = "{Series-Title}";
|
||||
|
||||
Subject.BuildFilename(new List<Episode> {_episode1}, _series, _episodeFile)
|
||||
Subject.BuildFileName(new List<Episode> {_episode1}, _series, _episodeFile)
|
||||
.Should().Be("South-Park");
|
||||
}
|
||||
|
||||
|
@ -105,7 +105,7 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
{
|
||||
_namingConfig.StandardEpisodeFormat = "{SERIES TITLE}";
|
||||
|
||||
Subject.BuildFilename(new List<Episode> {_episode1}, _series, _episodeFile)
|
||||
Subject.BuildFileName(new List<Episode> {_episode1}, _series, _episodeFile)
|
||||
.Should().Be("SOUTH PARK");
|
||||
}
|
||||
|
||||
|
@ -114,7 +114,7 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
{
|
||||
_namingConfig.StandardEpisodeFormat = "{sErIES-tItLE}";
|
||||
|
||||
Subject.BuildFilename(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
Subject.BuildFileName(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
.Should().Be(_series.Title.Replace(' ', '-'));
|
||||
}
|
||||
|
||||
|
@ -123,16 +123,26 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
{
|
||||
_namingConfig.StandardEpisodeFormat = "{series title}";
|
||||
|
||||
Subject.BuildFilename(new List<Episode> {_episode1}, _series, _episodeFile)
|
||||
Subject.BuildFileName(new List<Episode> {_episode1}, _series, _episodeFile)
|
||||
.Should().Be("south park");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_cleanup_Series_Title()
|
||||
{
|
||||
_namingConfig.StandardEpisodeFormat = "{Series.CleanTitle}";
|
||||
_series.Title = "South Park (1997)";
|
||||
|
||||
Subject.BuildFileName(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
.Should().Be("South.Park.1997");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_replace_episode_title()
|
||||
{
|
||||
_namingConfig.StandardEpisodeFormat = "{Episode Title}";
|
||||
|
||||
Subject.BuildFilename(new List<Episode> {_episode1}, _series, _episodeFile)
|
||||
Subject.BuildFileName(new List<Episode> {_episode1}, _series, _episodeFile)
|
||||
.Should().Be("City Sushi");
|
||||
}
|
||||
|
||||
|
@ -141,7 +151,7 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
{
|
||||
_namingConfig.StandardEpisodeFormat = "{ePisOde-TitLe}";
|
||||
|
||||
Subject.BuildFilename(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
Subject.BuildFileName(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
.Should().Be("City-Sushi");
|
||||
}
|
||||
|
||||
|
@ -151,7 +161,7 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
_episode1.SeasonNumber = 1;
|
||||
_namingConfig.StandardEpisodeFormat = "{season}x{episode}";
|
||||
|
||||
Subject.BuildFilename(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
Subject.BuildFileName(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
.Should().Be("1x6");
|
||||
}
|
||||
|
||||
|
@ -161,7 +171,7 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
_episode1.SeasonNumber = 1;
|
||||
_namingConfig.StandardEpisodeFormat = "{season:00}x{episode}";
|
||||
|
||||
Subject.BuildFilename(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
Subject.BuildFileName(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
.Should().Be("01x6");
|
||||
}
|
||||
|
||||
|
@ -171,7 +181,7 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
_episode1.SeasonNumber = 1;
|
||||
_namingConfig.StandardEpisodeFormat = "{season}x{episode}";
|
||||
|
||||
Subject.BuildFilename(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
Subject.BuildFileName(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
.Should().Be("1x6");
|
||||
}
|
||||
|
||||
|
@ -181,7 +191,7 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
_episode1.SeasonNumber = 1;
|
||||
_namingConfig.StandardEpisodeFormat = "{season}x{episode:00}";
|
||||
|
||||
Subject.BuildFilename(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
Subject.BuildFileName(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
.Should().Be("1x06");
|
||||
}
|
||||
|
||||
|
@ -190,7 +200,7 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
{
|
||||
_namingConfig.StandardEpisodeFormat = "{Quality Title}";
|
||||
|
||||
Subject.BuildFilename(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
Subject.BuildFileName(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
.Should().Be("HDTV-720p");
|
||||
}
|
||||
|
||||
|
@ -200,7 +210,7 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
_namingConfig.StandardEpisodeFormat = "{Quality Title}";
|
||||
_episodeFile.Quality.Proper = true;
|
||||
|
||||
Subject.BuildFilename(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
Subject.BuildFileName(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
.Should().Be("HDTV-720p Proper");
|
||||
}
|
||||
|
||||
|
@ -209,7 +219,7 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
{
|
||||
_namingConfig.StandardEpisodeFormat = "{Series Title} - S{season:00}E{episode:00} - {Episode Title} [{Quality Title}]";
|
||||
|
||||
Subject.BuildFilename(new List<Episode> {_episode1}, _series, _episodeFile)
|
||||
Subject.BuildFileName(new List<Episode> {_episode1}, _series, _episodeFile)
|
||||
.Should().Be("South Park - S15E06 - City Sushi [HDTV-720p]");
|
||||
}
|
||||
|
||||
|
@ -219,7 +229,7 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
_namingConfig.RenameEpisodes = false;
|
||||
_episodeFile.Path = @"C:\Test\TV\30 Rock - S01E01 - Test";
|
||||
|
||||
Subject.BuildFilename(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
Subject.BuildFileName(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
.Should().Be(Path.GetFileNameWithoutExtension(_episodeFile.Path));
|
||||
}
|
||||
|
||||
|
@ -230,7 +240,7 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
_episodeFile.SceneName = "30.Rock.S01E01.xvid-LOL";
|
||||
_episodeFile.Path = @"C:\Test\TV\30 Rock - S01E01 - Test";
|
||||
|
||||
Subject.BuildFilename(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
Subject.BuildFileName(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
.Should().Be("30.Rock.S01E01.xvid-LOL");
|
||||
}
|
||||
|
||||
|
@ -253,7 +263,7 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
.Build();
|
||||
|
||||
|
||||
Subject.BuildFilename(new List<Episode> {episode2, episode}, new Series {Title = "30 Rock"}, _episodeFile)
|
||||
Subject.BuildFileName(new List<Episode> {episode2, episode}, new Series {Title = "30 Rock"}, _episodeFile)
|
||||
.Should().Be("30 Rock - S06E06-E07 - Hey, Baby, What's Wrong!");
|
||||
}
|
||||
|
||||
|
@ -266,7 +276,7 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
_episode1.Title = "Hello";
|
||||
_episode2.Title = "World";
|
||||
|
||||
Subject.BuildFilename(new List<Episode> {_episode1, _episode2}, _series, _episodeFile)
|
||||
Subject.BuildFileName(new List<Episode> {_episode1, _episode2}, _series, _episodeFile)
|
||||
.Should().Be("South Park - S15E06-E07 - Hello + World");
|
||||
}
|
||||
|
||||
|
@ -281,7 +291,7 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
_episode1.AirDate = "2012-12-13";
|
||||
_episode1.Title = "Kristen Stewart";
|
||||
|
||||
Subject.BuildFilename(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
Subject.BuildFileName(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
.Should().Be("The Daily Show with Jon Stewart - 2012-12-13 - Kristen Stewart");
|
||||
}
|
||||
|
||||
|
@ -296,7 +306,7 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
_episode1.AirDate = null;
|
||||
_episode1.Title = "Kristen Stewart";
|
||||
|
||||
Subject.BuildFilename(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
Subject.BuildFileName(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
.Should().Be("The Daily Show with Jon Stewart - Unknown - Kristen Stewart");
|
||||
}
|
||||
|
||||
|
@ -306,7 +316,7 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
_namingConfig.StandardEpisodeFormat = "{Series Title} - S{season:00}E{episode:00} - {Episode Title}";
|
||||
_namingConfig.MultiEpisodeStyle = 0;
|
||||
|
||||
Subject.BuildFilename(new List<Episode> {_episode1, _episode2}, _series, _episodeFile)
|
||||
Subject.BuildFileName(new List<Episode> {_episode1, _episode2}, _series, _episodeFile)
|
||||
.Should().Be("South Park - S15E06-07 - City Sushi");
|
||||
}
|
||||
|
||||
|
@ -316,7 +326,7 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
_namingConfig.StandardEpisodeFormat = "{Series Title} - S{season:00}E{episode:00} - {Episode Title}";
|
||||
_namingConfig.MultiEpisodeStyle = 1;
|
||||
|
||||
Subject.BuildFilename(new List<Episode> { _episode1, _episode2 }, _series, _episodeFile)
|
||||
Subject.BuildFileName(new List<Episode> { _episode1, _episode2 }, _series, _episodeFile)
|
||||
.Should().Be("South Park - S15E06 - S15E07 - City Sushi");
|
||||
}
|
||||
|
||||
|
@ -326,7 +336,7 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
_namingConfig.StandardEpisodeFormat = "{Series Title} - S{season:00}E{episode:00} - {Episode Title}";
|
||||
_namingConfig.MultiEpisodeStyle = 2;
|
||||
|
||||
Subject.BuildFilename(new List<Episode> { _episode1, _episode2 }, _series, _episodeFile)
|
||||
Subject.BuildFileName(new List<Episode> { _episode1, _episode2 }, _series, _episodeFile)
|
||||
.Should().Be("South Park - S15E06E07 - City Sushi");
|
||||
}
|
||||
|
||||
|
@ -336,7 +346,7 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
_namingConfig.StandardEpisodeFormat = "{Series Title} - S{season:00}E{episode:00} - {Episode Title}";
|
||||
_namingConfig.MultiEpisodeStyle = 3;
|
||||
|
||||
Subject.BuildFilename(new List<Episode> { _episode1, _episode2 }, _series, _episodeFile)
|
||||
Subject.BuildFileName(new List<Episode> { _episode1, _episode2 }, _series, _episodeFile)
|
||||
.Should().Be("South Park - S15E06-E07 - City Sushi");
|
||||
}
|
||||
|
||||
|
@ -348,7 +358,7 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
|
||||
_namingConfig.StandardEpisodeFormat = "{Episode Title}";
|
||||
|
||||
Subject.BuildFilename(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
Subject.BuildFileName(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
.Should().Be(title);
|
||||
}
|
||||
|
||||
|
@ -357,7 +367,7 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
{
|
||||
_namingConfig.StandardEpisodeFormat = "{Release Group}";
|
||||
|
||||
Subject.BuildFilename(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
Subject.BuildFileName(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
.Should().Be(_episodeFile.ReleaseGroup);
|
||||
}
|
||||
|
||||
|
@ -370,7 +380,7 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
_episodeFile.SceneName = "30.Rock.S01E01.xvid-LOL";
|
||||
_episodeFile.Path = @"C:\Test\TV\30 Rock - S01E01 - Test";
|
||||
|
||||
Subject.BuildFilename(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
Subject.BuildFileName(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
.Should().Be("30 Rock - 30.Rock.S01E01.xvid-LOL");
|
||||
}
|
||||
|
||||
|
@ -387,7 +397,7 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
.Build();
|
||||
|
||||
|
||||
Subject.BuildFilename(new List<Episode> { episode }, new Series { Title = "30 Rock" }, _episodeFile)
|
||||
Subject.BuildFileName(new List<Episode> { episode }, new Series { Title = "30 Rock" }, _episodeFile)
|
||||
.Should().Be("30 Rock - S06E06 - Part 1");
|
||||
}
|
||||
|
||||
|
@ -404,7 +414,7 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
.Build();
|
||||
|
||||
|
||||
Subject.BuildFilename(new List<Episode> { episode }, new Series { Title = "30 Rock" }, _episodeFile)
|
||||
Subject.BuildFileName(new List<Episode> { episode }, new Series { Title = "30 Rock" }, _episodeFile)
|
||||
.Should().Be("30 Rock - S06E06 - Part 1");
|
||||
}
|
||||
|
||||
|
@ -419,7 +429,7 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
.With(e => e.EpisodeNumber = 6)
|
||||
.Build();
|
||||
|
||||
Subject.BuildFilename(new List<Episode> { episode }, new Series { Title = "Chicago P.D." }, _episodeFile)
|
||||
Subject.BuildFileName(new List<Episode> { episode }, new Series { Title = "Chicago P.D." }, _episodeFile)
|
||||
.Should().Be("Chicago.P.D.S06E06.Part.1");
|
||||
}
|
||||
|
||||
|
@ -434,7 +444,7 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
.With(e => e.EpisodeNumber = 6)
|
||||
.Build();
|
||||
|
||||
Subject.BuildFilename(new List<Episode> { episode }, new Series { Title = "Chicago P.D.." }, _episodeFile)
|
||||
Subject.BuildFileName(new List<Episode> { episode }, new Series { Title = "Chicago P.D.." }, _episodeFile)
|
||||
.Should().Be("Chicago.P.D.S06E06.Part.1");
|
||||
}
|
||||
|
||||
|
@ -443,7 +453,7 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
{
|
||||
_namingConfig.StandardEpisodeFormat = "{Series.Title}.S{season:00}E{episode:00}.{absolute:00}.{Episode.Title}";
|
||||
|
||||
Subject.BuildFilename(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
Subject.BuildFileName(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
.Should().Be("South.Park.S15E06.City.Sushi");
|
||||
}
|
||||
|
||||
|
@ -453,7 +463,7 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
_series.SeriesType = SeriesTypes.Anime;
|
||||
_namingConfig.AnimeEpisodeFormat = "{Series.Title}.S{season:00}E{episode:00}.{absolute:00}.{Episode.Title}";
|
||||
|
||||
Subject.BuildFilename(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
Subject.BuildFileName(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
.Should().Be("South.Park.S15E06.100.City.Sushi");
|
||||
}
|
||||
|
||||
|
@ -463,7 +473,7 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
_series.SeriesType = SeriesTypes.Anime;
|
||||
_namingConfig.AnimeEpisodeFormat = "{Series.Title}.S{season:00}E{episode:00}.{Episode.Title}";
|
||||
|
||||
Subject.BuildFilename(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
Subject.BuildFileName(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
.Should().Be("South.Park.S15E06.City.Sushi");
|
||||
}
|
||||
|
||||
|
@ -473,7 +483,7 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
_series.SeriesType = SeriesTypes.Anime;
|
||||
_namingConfig.AnimeEpisodeFormat = "{Series.Title}.{absolute:00}.{Episode.Title}";
|
||||
|
||||
Subject.BuildFilename(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
Subject.BuildFileName(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
.Should().Be("South.Park.100.City.Sushi");
|
||||
}
|
||||
|
||||
|
@ -483,7 +493,7 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
_series.SeriesType = SeriesTypes.Anime;
|
||||
_namingConfig.AnimeEpisodeFormat = "{Series Title} - {absolute:000} - {Episode Title}";
|
||||
|
||||
Subject.BuildFilename(new List<Episode> { _episode1, _episode2 }, _series, _episodeFile)
|
||||
Subject.BuildFileName(new List<Episode> { _episode1, _episode2 }, _series, _episodeFile)
|
||||
.Should().Be("South Park - 100-101 - City Sushi");
|
||||
}
|
||||
|
||||
|
@ -496,7 +506,7 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
_namingConfig.StandardEpisodeFormat = "{Series Title} - {season:0}x{episode:00} - {Episode Title}";
|
||||
_namingConfig.AnimeEpisodeFormat = "{Series Title} - {absolute:000} - {Episode Title}";
|
||||
|
||||
Subject.BuildFilename(new List<Episode> { _episode1, }, _series, _episodeFile)
|
||||
Subject.BuildFileName(new List<Episode> { _episode1, }, _series, _episodeFile)
|
||||
.Should().Be("South Park - 15x06 - City Sushi");
|
||||
}
|
||||
|
||||
|
@ -507,8 +517,62 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
_namingConfig.MultiEpisodeStyle = (int)MultiEpisodeStyle.Duplicate;
|
||||
_namingConfig.AnimeEpisodeFormat = "{Series Title} - {absolute:000} - {Episode Title}";
|
||||
|
||||
Subject.BuildFilename(new List<Episode> { _episode1, _episode2 }, _series, _episodeFile)
|
||||
Subject.BuildFileName(new List<Episode> { _episode1, _episode2 }, _series, _episodeFile)
|
||||
.Should().Be("South Park - 100 - 101 - City Sushi");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_include_affixes_if_value_not_empty()
|
||||
{
|
||||
_namingConfig.StandardEpisodeFormat = "{Series.Title}.S{season:00}E{episode:00}{_Episode.Title_}";
|
||||
|
||||
Subject.BuildFileName(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
.Should().Be("South.Park.S15E06_City.Sushi_");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_include_affixes_if_value_empty()
|
||||
{
|
||||
_namingConfig.StandardEpisodeFormat = "{Series.Title}.S{season:00}E{episode:00}{_Episode.Title_}";
|
||||
|
||||
_episode1.Title = "";
|
||||
|
||||
Subject.BuildFileName(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
.Should().Be("South.Park.S15E06");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_format_mediainfo_properly()
|
||||
{
|
||||
_namingConfig.StandardEpisodeFormat = "{Series.Title}.S{season:00}E{episode:00}.{Episode.Title}.{MEDIAINFO.FULL}";
|
||||
|
||||
_episodeFile.MediaInfo = new Core.MediaFiles.MediaInfo.MediaInfoModel()
|
||||
{
|
||||
VideoCodec = "AVC",
|
||||
AudioFormat = "DTS",
|
||||
AudioLanguages = "English/Spanish",
|
||||
Subtitles = "English/Spanish/Italian"
|
||||
};
|
||||
|
||||
Subject.BuildFileName(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
.Should().Be("South.Park.S15E06.City.Sushi.X264.DTS[EN+ES].[EN+ES+IT]");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_exclude_english_in_mediainfo_audio_language()
|
||||
{
|
||||
_namingConfig.StandardEpisodeFormat = "{Series.Title}.S{season:00}E{episode:00}.{Episode.Title}.{MEDIAINFO.FULL}";
|
||||
|
||||
_episodeFile.MediaInfo = new Core.MediaFiles.MediaInfo.MediaInfoModel()
|
||||
{
|
||||
VideoCodec = "AVC",
|
||||
AudioFormat = "DTS",
|
||||
AudioLanguages = "English",
|
||||
Subtitles = "English/Spanish/Italian"
|
||||
};
|
||||
|
||||
Subject.BuildFileName(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
.Should().Be("South.Park.S15E06.City.Sushi.X264.DTS.[EN+ES+IT]");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -27,7 +27,9 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
{
|
||||
namingConfig.SeriesFolderFormat = format;
|
||||
|
||||
Subject.GetSeriesFolder(seriesTitle).Should().Be(expected);
|
||||
var series = new NzbDrone.Core.Tv.Series { Title = seriesTitle };
|
||||
|
||||
Subject.GetSeriesFolder(series).Should().Be(expected);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -26,7 +26,7 @@ namespace NzbDrone.Core.Test.TvTests.SeriesServiceTests
|
|||
fakeSeries.RootFolderPath = @"C:\Test\TV";
|
||||
|
||||
Mocker.GetMock<IBuildFileNames>()
|
||||
.Setup(s => s.GetSeriesFolder(fakeSeries.Title))
|
||||
.Setup(s => s.GetSeriesFolder(fakeSeries, null))
|
||||
.Returns(fakeSeries.Title);
|
||||
|
||||
var series = Subject.AddSeries(fakeSeries);
|
||||
|
|
|
@ -46,7 +46,7 @@ namespace NzbDrone.Core.Download.Clients.Pneumatic
|
|||
throw new NotSupportedException("Full season releases are not supported with Pneumatic.");
|
||||
}
|
||||
|
||||
title = FileNameBuilder.CleanFilename(title);
|
||||
title = FileNameBuilder.CleanFileName(title);
|
||||
|
||||
//Save to the Pneumatic directory (The user will need to ensure its accessible by XBMC)
|
||||
var filename = Path.Combine(Settings.NzbFolder, title + ".nzb");
|
||||
|
|
|
@ -46,7 +46,7 @@ namespace NzbDrone.Core.Download.Clients.UsenetBlackhole
|
|||
var url = remoteEpisode.Release.DownloadUrl;
|
||||
var title = remoteEpisode.Release.Title;
|
||||
|
||||
title = FileNameBuilder.CleanFilename(title);
|
||||
title = FileNameBuilder.CleanFileName(title);
|
||||
|
||||
var filename = Path.Combine(Settings.NzbFolder, title + ".nzb");
|
||||
|
||||
|
@ -61,7 +61,7 @@ namespace NzbDrone.Core.Download.Clients.UsenetBlackhole
|
|||
{
|
||||
foreach (var folder in _diskProvider.GetDirectories(Settings.WatchFolder))
|
||||
{
|
||||
var title = FileNameBuilder.CleanFilename(Path.GetFileName(folder));
|
||||
var title = FileNameBuilder.CleanFileName(Path.GetFileName(folder));
|
||||
|
||||
var files = _diskProvider.GetFiles(folder, SearchOption.AllDirectories);
|
||||
|
||||
|
@ -95,7 +95,7 @@ namespace NzbDrone.Core.Download.Clients.UsenetBlackhole
|
|||
|
||||
foreach (var videoFile in _diskScanService.GetVideoFiles(Settings.WatchFolder, false))
|
||||
{
|
||||
var title = FileNameBuilder.CleanFilename(Path.GetFileName(videoFile));
|
||||
var title = FileNameBuilder.CleanFileName(Path.GetFileName(videoFile));
|
||||
|
||||
var historyItem = new DownloadClientItem
|
||||
{
|
||||
|
|
|
@ -49,7 +49,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
public EpisodeFile MoveEpisodeFile(EpisodeFile episodeFile, Series series)
|
||||
{
|
||||
var episodes = _episodeService.GetEpisodesByFileId(episodeFile.Id);
|
||||
var newFileName = _buildFileNames.BuildFilename(episodes, series, episodeFile);
|
||||
var newFileName = _buildFileNames.BuildFileName(episodes, series, episodeFile);
|
||||
var filePath = _buildFileNames.BuildFilePath(series, episodes.First().SeasonNumber, newFileName, Path.GetExtension(episodeFile.Path));
|
||||
|
||||
_logger.Debug("Renaming episode file: {0} to {1}", episodeFile, filePath);
|
||||
|
@ -59,7 +59,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
|
||||
public EpisodeFile MoveEpisodeFile(EpisodeFile episodeFile, LocalEpisode localEpisode)
|
||||
{
|
||||
var newFileName = _buildFileNames.BuildFilename(localEpisode.Episodes, localEpisode.Series, episodeFile);
|
||||
var newFileName = _buildFileNames.BuildFileName(localEpisode.Episodes, localEpisode.Series, episodeFile);
|
||||
var filePath = _buildFileNames.BuildFilePath(localEpisode.Series, localEpisode.SeasonNumber, newFileName, Path.GetExtension(episodeFile.Path));
|
||||
|
||||
_logger.Debug("Moving episode file: {0} to {1}", episodeFile, filePath);
|
||||
|
@ -69,7 +69,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
|
||||
public EpisodeFile CopyEpisodeFile(EpisodeFile episodeFile, LocalEpisode localEpisode)
|
||||
{
|
||||
var newFileName = _buildFileNames.BuildFilename(localEpisode.Episodes, localEpisode.Series, episodeFile);
|
||||
var newFileName = _buildFileNames.BuildFileName(localEpisode.Episodes, localEpisode.Series, episodeFile);
|
||||
var filePath = _buildFileNames.BuildFilePath(localEpisode.Series, localEpisode.SeasonNumber, newFileName, Path.GetExtension(episodeFile.Path));
|
||||
|
||||
_logger.Debug("Copying episode file: {0} to {1}", episodeFile, filePath);
|
||||
|
|
|
@ -85,7 +85,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
}
|
||||
|
||||
var seasonNumber = episodesInFile.First().SeasonNumber;
|
||||
var newName = _filenameBuilder.BuildFilename(episodesInFile, series, file);
|
||||
var newName = _filenameBuilder.BuildFileName(episodesInFile, series, file);
|
||||
var newPath = _filenameBuilder.BuildFilePath(series, seasonNumber, newName, Path.GetExtension(file.Path));
|
||||
|
||||
if (!file.Path.PathEquals(newPath))
|
||||
|
|
|
@ -634,10 +634,10 @@
|
|||
<Compile Include="Organizer\EpisodeSortingType.cs" />
|
||||
<Compile Include="Organizer\Exception.cs" />
|
||||
<Compile Include="Organizer\FileNameBuilder.cs" />
|
||||
<Compile Include="Organizer\FilenameBuilderTokenEqualityComparer.cs" />
|
||||
<Compile Include="Organizer\FilenameSampleService.cs" />
|
||||
<Compile Include="Organizer\FileNameBuilderTokenEqualityComparer.cs" />
|
||||
<Compile Include="Organizer\FileNameSampleService.cs" />
|
||||
<Compile Include="Organizer\FileNameValidation.cs" />
|
||||
<Compile Include="Organizer\FilenameValidationService.cs" />
|
||||
<Compile Include="Organizer\FileNameValidationService.cs" />
|
||||
<Compile Include="Organizer\NamingConfig.cs" />
|
||||
<Compile Include="Organizer\NamingConfigService.cs" />
|
||||
<Compile Include="Organizer\SampleResult.cs" />
|
||||
|
|
|
@ -14,13 +14,11 @@ namespace NzbDrone.Core.Organizer
|
|||
{
|
||||
public interface IBuildFileNames
|
||||
{
|
||||
string BuildFilename(IList<Episode> episodes, Series series, EpisodeFile episodeFile);
|
||||
string BuildFilename(IList<Episode> episodes, Series series, EpisodeFile episodeFile, NamingConfig namingConfig);
|
||||
string BuildFilePath(Series series, int seasonNumber, string fileName, string extension);
|
||||
string BuildFileName(List<Episode> episodes, Series series, EpisodeFile episodeFile, NamingConfig namingConfig = null);
|
||||
string BuildFilePath(Series series, Int32 seasonNumber, String fileName, String extension);
|
||||
BasicNamingConfig GetBasicNamingConfig(NamingConfig nameSpec);
|
||||
string GetSeriesFolder(string seriesTitle);
|
||||
string GetSeriesFolder(string seriesTitle, NamingConfig namingConfig);
|
||||
string GetSeasonFolder(string seriesTitle, int seasonNumber, NamingConfig namingConfig);
|
||||
string GetSeriesFolder(Series series, NamingConfig namingConfig = null);
|
||||
string GetSeasonFolder(Series series, Int32 seasonNumber, NamingConfig namingConfig = null);
|
||||
}
|
||||
|
||||
public class FileNameBuilder : IBuildFileNames
|
||||
|
@ -30,7 +28,7 @@ namespace NzbDrone.Core.Organizer
|
|||
private readonly ICached<EpisodeFormat> _patternCache;
|
||||
private readonly Logger _logger;
|
||||
|
||||
private static readonly Regex TitleRegex = new Regex(@"(?<token>\{(?:\w+)(?<separator>\s|\.|-|_)\w+\})",
|
||||
private static readonly Regex TitleRegex = new Regex(@"\{(?<prefix>[- ._]*)(?<token>(?:[a-z0-9]+)(?:(?<separator>[- ._]+)(?:[a-z0-9]+))?)(?::(?<customFormat>[a-z0-9]+))?(?<suffix>[- ._]*)\}",
|
||||
RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
private static readonly Regex EpisodeRegex = new Regex(@"(?<episode>\{episode(?:\:0+)?})",
|
||||
|
@ -50,12 +48,12 @@ 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(@"(?<token>\{(?:Series)(?<separator>\s|\.|-|_)Title\})",
|
||||
public static readonly Regex SeriesTitleRegex = new Regex(@"(?<token>\{(?:Series)(?<separator>\s|\.|-|_)(Clean)?Title\})",
|
||||
RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
private static readonly Regex FilenameCleanupRegex = new Regex(@"\.{2,}", RegexOptions.Compiled);
|
||||
private static readonly Regex FileNameCleanupRegex = new Regex(@"\.{2,}", RegexOptions.Compiled);
|
||||
|
||||
private static readonly char[] EpisodeTitleTrimCharaters = new[] { ' ', '.', '?' };
|
||||
private static readonly char[] EpisodeTitleTrimCharacters = new[] { ' ', '.', '?' };
|
||||
|
||||
public FileNameBuilder(INamingConfigService namingConfigService,
|
||||
IQualityDefinitionService qualityDefinitionService,
|
||||
|
@ -68,18 +66,16 @@ namespace NzbDrone.Core.Organizer
|
|||
_logger = logger;
|
||||
}
|
||||
|
||||
public string BuildFilename(IList<Episode> episodes, Series series, EpisodeFile episodeFile)
|
||||
public string BuildFileName(List<Episode> episodes, Series series, EpisodeFile episodeFile, NamingConfig namingConfig = null)
|
||||
{
|
||||
var nameSpec = _namingConfigService.GetConfig();
|
||||
if (namingConfig == null)
|
||||
{
|
||||
namingConfig = _namingConfigService.GetConfig();
|
||||
}
|
||||
|
||||
return BuildFilename(episodes, series, episodeFile, nameSpec);
|
||||
}
|
||||
|
||||
public string BuildFilename(IList<Episode> episodes, Series series, EpisodeFile episodeFile, NamingConfig namingConfig)
|
||||
{
|
||||
if (!namingConfig.RenameEpisodes)
|
||||
{
|
||||
if (String.IsNullOrWhiteSpace(episodeFile.SceneName))
|
||||
if (episodeFile.SceneName.IsNullOrWhiteSpace())
|
||||
{
|
||||
return Path.GetFileNameWithoutExtension(episodeFile.Path);
|
||||
}
|
||||
|
@ -87,42 +83,33 @@ namespace NzbDrone.Core.Organizer
|
|||
return episodeFile.SceneName;
|
||||
}
|
||||
|
||||
if (String.IsNullOrWhiteSpace(namingConfig.StandardEpisodeFormat) && series.SeriesType == SeriesTypes.Standard)
|
||||
if (namingConfig.StandardEpisodeFormat.IsNullOrWhiteSpace() && series.SeriesType == SeriesTypes.Standard)
|
||||
{
|
||||
throw new NamingFormatException("Standard episode format cannot be null");
|
||||
}
|
||||
|
||||
if (String.IsNullOrWhiteSpace(namingConfig.DailyEpisodeFormat) && series.SeriesType == SeriesTypes.Daily)
|
||||
if (namingConfig.DailyEpisodeFormat.IsNullOrWhiteSpace() && series.SeriesType == SeriesTypes.Daily)
|
||||
{
|
||||
throw new NamingFormatException("Daily episode format cannot be null");
|
||||
}
|
||||
|
||||
var sortedEpisodes = episodes.OrderBy(e => e.EpisodeNumber).ToList();
|
||||
var pattern = namingConfig.StandardEpisodeFormat;
|
||||
|
||||
var tokenHandlers = new Dictionary<String, Func<TokenMatch, String>>(FileNameBuilderTokenEqualityComparer.Instance);
|
||||
|
||||
episodes = episodes.OrderBy(e => e.SeasonNumber).ThenBy(e => e.EpisodeNumber).ToList();
|
||||
|
||||
AddSeriesTokens(tokenHandlers, series);
|
||||
|
||||
AddEpisodeTokens(tokenHandlers, episodes);
|
||||
|
||||
AddEpisodeFileTokens(tokenHandlers, episodeFile);
|
||||
|
||||
AddMediaInfoTokens(tokenHandlers, episodeFile);
|
||||
|
||||
var episodeTitles = new List<string>
|
||||
{
|
||||
sortedEpisodes.First().Title.TrimEnd(EpisodeTitleTrimCharaters)
|
||||
};
|
||||
|
||||
var tokenValues = new Dictionary<string, string>(FilenameBuilderTokenEqualityComparer.Instance);
|
||||
|
||||
tokenValues.Add("{Series Title}", series.Title);
|
||||
tokenValues.Add("{Original Title}", episodeFile.SceneName);
|
||||
tokenValues.Add("{Release Group}", episodeFile.ReleaseGroup);
|
||||
|
||||
if (series.SeriesType == SeriesTypes.Daily)
|
||||
{
|
||||
pattern = namingConfig.DailyEpisodeFormat;
|
||||
|
||||
if (!String.IsNullOrWhiteSpace(episodes.First().AirDate))
|
||||
{
|
||||
tokenValues.Add("{Air Date}", episodes.First().AirDate.Replace('-', ' '));
|
||||
}
|
||||
|
||||
else {
|
||||
tokenValues.Add("{Air Date}", "Unknown");
|
||||
}
|
||||
}
|
||||
|
||||
if (series.SeriesType == SeriesTypes.Anime && episodes.All(e => e.AbsoluteEpisodeNumber > 0))
|
||||
|
@ -137,7 +124,7 @@ namespace NzbDrone.Core.Organizer
|
|||
pattern = pattern.Replace(episodeFormat.SeasonEpisodePattern, "{Season Episode}");
|
||||
var seasonEpisodePattern = episodeFormat.SeasonEpisodePattern;
|
||||
|
||||
foreach (var episode in sortedEpisodes.Skip(1))
|
||||
foreach (var episode in episodes.Skip(1))
|
||||
{
|
||||
switch ((MultiEpisodeStyle)namingConfig.MultiEpisodeStyle)
|
||||
{
|
||||
|
@ -158,12 +145,10 @@ namespace NzbDrone.Core.Organizer
|
|||
seasonEpisodePattern += "-" + episodeFormat.EpisodePattern;
|
||||
break;
|
||||
}
|
||||
|
||||
episodeTitles.Add(episode.Title.TrimEnd(EpisodeTitleTrimCharaters));
|
||||
}
|
||||
|
||||
seasonEpisodePattern = ReplaceNumberTokens(seasonEpisodePattern, sortedEpisodes);
|
||||
tokenValues.Add("{Season Episode}", seasonEpisodePattern);
|
||||
seasonEpisodePattern = ReplaceNumberTokens(seasonEpisodePattern, episodes);
|
||||
tokenHandlers["{Season Episode}"] = m => seasonEpisodePattern;
|
||||
}
|
||||
|
||||
//TODO: Extract to another method
|
||||
|
@ -181,7 +166,7 @@ namespace NzbDrone.Core.Organizer
|
|||
pattern = pattern.Replace(absoluteEpisodeFormat.AbsoluteEpisodePattern, "{Absolute Pattern}");
|
||||
var absoluteEpisodePattern = absoluteEpisodeFormat.AbsoluteEpisodePattern;
|
||||
|
||||
foreach (var episode in sortedEpisodes.Skip(1))
|
||||
foreach (var episode in episodes.Skip(1))
|
||||
{
|
||||
switch ((MultiEpisodeStyle)namingConfig.MultiEpisodeStyle)
|
||||
{
|
||||
|
@ -204,24 +189,17 @@ namespace NzbDrone.Core.Organizer
|
|||
absoluteEpisodePattern += "-" + absoluteEpisodeFormat.AbsoluteEpisodePattern;
|
||||
break;
|
||||
}
|
||||
|
||||
episodeTitles.Add(episode.Title.TrimEnd(EpisodeTitleTrimCharaters));
|
||||
}
|
||||
|
||||
absoluteEpisodePattern = ReplaceAbsoluteNumberTokens(absoluteEpisodePattern, sortedEpisodes);
|
||||
tokenValues.Add("{Absolute Pattern}", absoluteEpisodePattern);
|
||||
absoluteEpisodePattern = ReplaceAbsoluteNumberTokens(absoluteEpisodePattern, episodes);
|
||||
tokenHandlers["{Absolute Pattern}"] = m => absoluteEpisodePattern;
|
||||
}
|
||||
}
|
||||
|
||||
tokenValues.Add("{Episode Title}", GetEpisodeTitle(episodeTitles));
|
||||
tokenValues.Add("{Quality Title}", GetQualityTitle(episodeFile.Quality));
|
||||
var filename = ReplaceTokens(pattern, tokenHandlers).Trim();
|
||||
filename = FileNameCleanupRegex.Replace(filename, match => match.Captures[0].Value[0].ToString());
|
||||
|
||||
AddMediaInfoTokens(episodeFile, tokenValues);
|
||||
|
||||
var filename = ReplaceTokens(pattern, tokenValues).Trim();
|
||||
filename = FilenameCleanupRegex.Replace(filename, match => match.Captures[0].Value[0].ToString() );
|
||||
|
||||
return CleanFilename(filename);
|
||||
return filename;
|
||||
}
|
||||
|
||||
public string BuildFilePath(Series series, int seasonNumber, string fileName, string extension)
|
||||
|
@ -240,10 +218,10 @@ namespace NzbDrone.Core.Organizer
|
|||
else
|
||||
{
|
||||
var nameSpec = _namingConfigService.GetConfig();
|
||||
seasonFolder = GetSeasonFolder(series.Title, seasonNumber, nameSpec);
|
||||
seasonFolder = GetSeasonFolder(series, seasonNumber, nameSpec);
|
||||
}
|
||||
|
||||
seasonFolder = CleanFilename(seasonFolder);
|
||||
seasonFolder = CleanFileName(seasonFolder);
|
||||
|
||||
path = Path.Combine(path, seasonFolder);
|
||||
}
|
||||
|
@ -297,160 +275,260 @@ namespace NzbDrone.Core.Organizer
|
|||
return basicNamingConfig;
|
||||
}
|
||||
|
||||
public string GetSeriesFolder(string seriesTitle)
|
||||
public string GetSeriesFolder(Series series, NamingConfig namingConfig = null)
|
||||
{
|
||||
var namingConfig = _namingConfigService.GetConfig();
|
||||
if (namingConfig == null)
|
||||
{
|
||||
namingConfig = _namingConfigService.GetConfig();
|
||||
}
|
||||
|
||||
return GetSeriesFolder(seriesTitle, namingConfig);
|
||||
var tokenHandlers = new Dictionary<string, Func<TokenMatch, String>>(FileNameBuilderTokenEqualityComparer.Instance);
|
||||
|
||||
AddSeriesTokens(tokenHandlers, series);
|
||||
|
||||
return ReplaceTokens(namingConfig.SeriesFolderFormat, tokenHandlers);
|
||||
}
|
||||
|
||||
public string GetSeriesFolder(string seriesTitle, NamingConfig namingConfig)
|
||||
public string GetSeasonFolder(Series series, Int32 seasonNumber, NamingConfig namingConfig = null)
|
||||
{
|
||||
seriesTitle = CleanFilename(seriesTitle);
|
||||
if (namingConfig == null)
|
||||
{
|
||||
namingConfig = _namingConfigService.GetConfig();
|
||||
}
|
||||
|
||||
var tokenValues = new Dictionary<string, string>(FilenameBuilderTokenEqualityComparer.Instance);
|
||||
tokenValues.Add("{Series Title}", seriesTitle);
|
||||
var tokenHandlers = new Dictionary<string, Func<TokenMatch, String>>(FileNameBuilderTokenEqualityComparer.Instance);
|
||||
|
||||
return ReplaceTokens(namingConfig.SeriesFolderFormat, tokenValues);
|
||||
AddSeriesTokens(tokenHandlers, series);
|
||||
|
||||
AddSeasonTokens(tokenHandlers, seasonNumber);
|
||||
|
||||
return ReplaceTokens(namingConfig.SeasonFolderFormat, tokenHandlers);
|
||||
}
|
||||
|
||||
public string GetSeasonFolder(string seriesTitle, int seasonNumber, NamingConfig namingConfig)
|
||||
public static string CleanTitle(string name)
|
||||
{
|
||||
var tokenValues = new Dictionary<string, string>(FilenameBuilderTokenEqualityComparer.Instance);
|
||||
tokenValues.Add("{Series Title}", seriesTitle);
|
||||
|
||||
var seasonFolder = ReplaceSeasonTokens(namingConfig.SeasonFolderFormat, seasonNumber);
|
||||
return ReplaceTokens(seasonFolder, tokenValues);
|
||||
string[] dropCharacters = { ":", ".", "(", ")" };
|
||||
|
||||
string result = name;
|
||||
|
||||
for (int i = 0; i < dropCharacters.Length; i++)
|
||||
{
|
||||
result = result.Replace(dropCharacters[i], "");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static string CleanFilename(string name)
|
||||
public static string CleanFileName(string name)
|
||||
{
|
||||
string result = name;
|
||||
string[] badCharacters = { "\\", "/", "<", ">", "?", "*", ":", "|", "\"" };
|
||||
string[] goodCharacters = { "+", "+", "", "", "!", "-", "-", "", "" };
|
||||
string[] goodCharacters = { "+", "+", "", "", "!", "-", "-", "", "" };
|
||||
|
||||
for (int i = 0; i < badCharacters.Length; i++)
|
||||
{
|
||||
result = result.Replace(badCharacters[i], goodCharacters[i]);
|
||||
}
|
||||
|
||||
return result.Trim();
|
||||
}
|
||||
|
||||
private void AddMediaInfoTokens(EpisodeFile episodeFile, Dictionary<string, string> tokenValues)
|
||||
private void AddSeriesTokens(Dictionary<String, Func<TokenMatch, String>> tokenHandlers, Series series)
|
||||
{
|
||||
if (episodeFile.MediaInfo == null)
|
||||
return;
|
||||
|
||||
var mediaInfoFull = string.Empty;
|
||||
|
||||
switch (episodeFile.MediaInfo.VideoCodec)
|
||||
{
|
||||
case "AVC":
|
||||
if (Path.GetFileNameWithoutExtension(episodeFile.Path).Contains("x264"))
|
||||
mediaInfoFull += "x264";
|
||||
else if (Path.GetFileNameWithoutExtension(episodeFile.Path).Contains("h264"))
|
||||
mediaInfoFull += "h264";
|
||||
else
|
||||
mediaInfoFull += "h264";
|
||||
break;
|
||||
|
||||
default:
|
||||
mediaInfoFull += episodeFile.MediaInfo.VideoCodec;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (episodeFile.MediaInfo.AudioFormat)
|
||||
{
|
||||
case "AC-3":
|
||||
mediaInfoFull += ".AC3";
|
||||
break;
|
||||
|
||||
case "MPEG Audio":
|
||||
if (episodeFile.MediaInfo.AudioProfile == "Layer 3")
|
||||
mediaInfoFull += ".MP3";
|
||||
else
|
||||
mediaInfoFull += "." + episodeFile.MediaInfo.AudioFormat;
|
||||
break;
|
||||
|
||||
case "DTS":
|
||||
mediaInfoFull += "." + episodeFile.MediaInfo.AudioFormat;
|
||||
break;
|
||||
|
||||
default:
|
||||
mediaInfoFull += "." + episodeFile.MediaInfo.AudioFormat;
|
||||
break;
|
||||
}
|
||||
|
||||
tokenValues.Add("{MediaInfo Short}", mediaInfoFull);
|
||||
|
||||
var audioLanguagesToken = GetLanguagesToken(episodeFile.MediaInfo.AudioLanguages);
|
||||
if (!string.IsNullOrEmpty(audioLanguagesToken) && audioLanguagesToken != "EN")
|
||||
mediaInfoFull += string.Format("[{0}]", audioLanguagesToken);
|
||||
|
||||
var subtitleLanguagesToken = GetLanguagesToken(episodeFile.MediaInfo.Subtitles);
|
||||
if (!string.IsNullOrEmpty(subtitleLanguagesToken))
|
||||
mediaInfoFull += string.Format(".[{0}]", subtitleLanguagesToken);
|
||||
|
||||
tokenValues.Add("{MediaInfo Full}", mediaInfoFull);
|
||||
tokenHandlers["{Series Title}"] = m => series.Title;
|
||||
tokenHandlers["{Series CleanTitle}"] = m => CleanTitle(series.Title);
|
||||
}
|
||||
|
||||
private string GetLanguagesToken(string mediaInfoLanguages)
|
||||
private void AddSeasonTokens(Dictionary<String, Func<TokenMatch, String>> tokenHandlers, Int32 seasonNumber)
|
||||
{
|
||||
List<string> tokens = new List<string>();
|
||||
foreach (var item in mediaInfoLanguages.Split('/'))
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(item))
|
||||
tokens.Add(item.Trim());
|
||||
}
|
||||
|
||||
var cultures = System.Globalization.CultureInfo.GetCultures(System.Globalization.CultureTypes.NeutralCultures);
|
||||
for (int i = 0; i < tokens.Count; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
var cultureInfo = cultures.FirstOrDefault(p => p.EnglishName == tokens[i]);
|
||||
|
||||
if (cultureInfo != null)
|
||||
tokens[i] = cultureInfo.TwoLetterISOLanguageName.ToUpper();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
return string.Join("+", tokens.Distinct());
|
||||
tokenHandlers["{Season}"] = m => seasonNumber.ToString(m.CustomFormat ?? "0");
|
||||
}
|
||||
|
||||
private string ReplaceTokens(string pattern, Dictionary<string, string> tokenValues)
|
||||
private void AddEpisodeTokens(Dictionary<String, Func<TokenMatch, String>> tokenHandlers, List<Episode> episodes)
|
||||
{
|
||||
return TitleRegex.Replace(pattern, match => ReplaceToken(match, tokenValues));
|
||||
}
|
||||
|
||||
private string ReplaceToken(Match match, Dictionary<string, string> tokenValues)
|
||||
{
|
||||
var separator = match.Groups["separator"].Value;
|
||||
var token = match.Groups["token"].Value;
|
||||
var replacementText = "";
|
||||
var patternTokenArray = token.ToCharArray();
|
||||
if (!tokenValues.TryGetValue(token, out replacementText)) return null;
|
||||
|
||||
if (patternTokenArray.All(t => !Char.IsLetter(t) || Char.IsLower(t)))
|
||||
if (!episodes.First().AirDate.IsNullOrWhiteSpace())
|
||||
{
|
||||
replacementText = replacementText.ToLowerInvariant();
|
||||
tokenHandlers["{Air Date}"] = m => episodes.First().AirDate.Replace('-', ' ');
|
||||
}
|
||||
else
|
||||
{
|
||||
tokenHandlers["{Air Date}"] = m => "Unknown";
|
||||
}
|
||||
|
||||
else if (patternTokenArray.All(t => !Char.IsLetter(t) || Char.IsUpper(t)))
|
||||
tokenHandlers["{Episode Title}"] = m => GetEpisodeTitle(episodes);
|
||||
}
|
||||
|
||||
private void AddEpisodeFileTokens(Dictionary<String, Func<TokenMatch, String>> tokenHandlers, EpisodeFile episodeFile)
|
||||
{
|
||||
tokenHandlers["{Original Title}"]= m => episodeFile.SceneName;
|
||||
tokenHandlers["{Release Group}"] = m => episodeFile.ReleaseGroup;
|
||||
tokenHandlers["{Quality Title}"] = m => GetQualityTitle(episodeFile.Quality);
|
||||
}
|
||||
|
||||
private void AddMediaInfoTokens(Dictionary<String, Func<TokenMatch, String>> tokenHandlers, EpisodeFile episodeFile)
|
||||
{
|
||||
if (episodeFile.MediaInfo == null) return;
|
||||
|
||||
String mediaInfoVideo;
|
||||
switch (episodeFile.MediaInfo.VideoCodec)
|
||||
{
|
||||
case "AVC":
|
||||
// TODO: What to do if the original SceneName is hashed?
|
||||
if (!episodeFile.SceneName.IsNullOrWhiteSpace() && Path.GetFileNameWithoutExtension(episodeFile.SceneName).Contains("h264"))
|
||||
{
|
||||
mediaInfoVideo = "h264";
|
||||
}
|
||||
else
|
||||
{
|
||||
mediaInfoVideo = "x264";
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
mediaInfoVideo = episodeFile.MediaInfo.VideoCodec;
|
||||
break;
|
||||
}
|
||||
|
||||
String mediaInfoAudio;
|
||||
switch (episodeFile.MediaInfo.AudioFormat)
|
||||
{
|
||||
case "AC-3":
|
||||
mediaInfoAudio = "AC3";
|
||||
break;
|
||||
|
||||
case "MPEG Audio":
|
||||
if (episodeFile.MediaInfo.AudioProfile == "Layer 3")
|
||||
{
|
||||
mediaInfoAudio = "MP3";
|
||||
}
|
||||
else
|
||||
{
|
||||
mediaInfoAudio = episodeFile.MediaInfo.AudioFormat;
|
||||
}
|
||||
break;
|
||||
|
||||
case "DTS":
|
||||
mediaInfoAudio = episodeFile.MediaInfo.AudioFormat;
|
||||
break;
|
||||
|
||||
default:
|
||||
mediaInfoAudio = episodeFile.MediaInfo.AudioFormat;
|
||||
break;
|
||||
}
|
||||
|
||||
var mediaInfoAudioLanguages = GetLanguagesToken(episodeFile.MediaInfo.AudioLanguages);
|
||||
if (!mediaInfoAudioLanguages.IsNullOrWhiteSpace())
|
||||
{
|
||||
mediaInfoAudioLanguages = String.Format("[{0}]", mediaInfoAudioLanguages);
|
||||
}
|
||||
|
||||
if (mediaInfoAudioLanguages == "[EN]")
|
||||
{
|
||||
mediaInfoAudioLanguages = String.Empty;
|
||||
}
|
||||
|
||||
var mediaInfoSubtitleLanguages = GetLanguagesToken(episodeFile.MediaInfo.Subtitles);
|
||||
if (!mediaInfoSubtitleLanguages.IsNullOrWhiteSpace())
|
||||
{
|
||||
mediaInfoSubtitleLanguages = String.Format("[{0}]", mediaInfoSubtitleLanguages);
|
||||
}
|
||||
|
||||
tokenHandlers["{MediaInfo Video}"] = m => mediaInfoVideo;
|
||||
tokenHandlers["{MediaInfo Audio}"] = m => mediaInfoAudio;
|
||||
|
||||
tokenHandlers["{MediaInfo Simple}"] = m => String.Format("{0} {1}", mediaInfoVideo, mediaInfoAudio);
|
||||
|
||||
tokenHandlers["{MediaInfo Full}"] = m => String.Format("{0} {1}{2} {3}", mediaInfoVideo, mediaInfoAudio, mediaInfoAudioLanguages, mediaInfoSubtitleLanguages);
|
||||
}
|
||||
|
||||
private string GetLanguagesToken(String mediaInfoLanguages)
|
||||
{
|
||||
List<string> tokens = new List<string>();
|
||||
foreach (var item in mediaInfoLanguages.Split('/'))
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(item))
|
||||
tokens.Add(item.Trim());
|
||||
}
|
||||
|
||||
var cultures = System.Globalization.CultureInfo.GetCultures(System.Globalization.CultureTypes.NeutralCultures);
|
||||
for (int i = 0; i < tokens.Count; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
var cultureInfo = cultures.FirstOrDefault(p => p.EnglishName == tokens[i]);
|
||||
|
||||
if (cultureInfo != null)
|
||||
tokens[i] = cultureInfo.TwoLetterISOLanguageName.ToUpper();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
return string.Join("+", tokens.Distinct());
|
||||
}
|
||||
|
||||
private string ReplaceTokens(String pattern, Dictionary<String, Func<TokenMatch, String>> tokenHandlers)
|
||||
{
|
||||
return TitleRegex.Replace(pattern, match => ReplaceToken(match, tokenHandlers));
|
||||
}
|
||||
|
||||
private string ReplaceToken(Match match, Dictionary<String, Func<TokenMatch, String>> tokenHandlers)
|
||||
{
|
||||
var tokenMatch = new TokenMatch
|
||||
{
|
||||
RegexMatch = match,
|
||||
Prefix = match.Groups["prefix"].Value,
|
||||
Separator = match.Groups["separator"].Value,
|
||||
Suffix = match.Groups["suffix"].Value,
|
||||
Token = match.Groups["token"].Value,
|
||||
CustomFormat = match.Groups["customFormat"].Value
|
||||
};
|
||||
|
||||
if (tokenMatch.CustomFormat.IsNullOrWhiteSpace())
|
||||
{
|
||||
tokenMatch.CustomFormat = null;
|
||||
}
|
||||
|
||||
var tokenHandler = tokenHandlers.GetValueOrDefault(tokenMatch.Token, m => String.Empty);
|
||||
|
||||
var replacementText = tokenHandler(tokenMatch).Trim();
|
||||
|
||||
if (tokenMatch.Token.All(t => !Char.IsLetter(t) || Char.IsLower(t)))
|
||||
{
|
||||
replacementText = replacementText.ToLower();
|
||||
}
|
||||
else if (tokenMatch.Token.All(t => !Char.IsLetter(t) || Char.IsUpper(t)))
|
||||
{
|
||||
replacementText = replacementText.ToUpper();
|
||||
}
|
||||
|
||||
if (!separator.Equals(" "))
|
||||
if (!tokenMatch.Separator.IsNullOrWhiteSpace())
|
||||
{
|
||||
replacementText = replacementText.Replace(" ", separator);
|
||||
replacementText = replacementText.Replace(" ", tokenMatch.Separator);
|
||||
}
|
||||
|
||||
replacementText = CleanFileName(replacementText);
|
||||
|
||||
if (!replacementText.IsNullOrWhiteSpace())
|
||||
{
|
||||
replacementText = tokenMatch.Prefix + replacementText + tokenMatch.Suffix;
|
||||
}
|
||||
|
||||
return replacementText;
|
||||
}
|
||||
|
||||
|
||||
private sealed class TokenMatch
|
||||
{
|
||||
public Match RegexMatch { get; set; }
|
||||
public String Prefix { get; set; }
|
||||
public String Separator { get; set; }
|
||||
public String Suffix { get; set; }
|
||||
public String Token { get; set; }
|
||||
public String CustomFormat { get; set; }
|
||||
}
|
||||
|
||||
private string ReplaceNumberTokens(string pattern, List<Episode> episodes)
|
||||
{
|
||||
var episodeIndex = 0;
|
||||
|
@ -531,17 +609,22 @@ namespace NzbDrone.Core.Organizer
|
|||
return null;
|
||||
}
|
||||
|
||||
private string GetEpisodeTitle(List<string> episodeTitles)
|
||||
private String GetEpisodeTitle(List<Episode> episodes)
|
||||
{
|
||||
if (episodeTitles.Count == 1)
|
||||
if (episodes.Count == 1)
|
||||
{
|
||||
return episodeTitles.First();
|
||||
return episodes.First().Title.TrimEnd(EpisodeTitleTrimCharacters);
|
||||
}
|
||||
|
||||
return String.Join(" + ", episodeTitles.Select(Parser.Parser.CleanupEpisodeTitle).Distinct());
|
||||
var titles = episodes
|
||||
.Select(c => c.Title.TrimEnd(EpisodeTitleTrimCharacters))
|
||||
.Select(Parser.Parser.CleanupEpisodeTitle)
|
||||
.Distinct();
|
||||
|
||||
return String.Join(" + ", titles);
|
||||
}
|
||||
|
||||
private string GetQualityTitle(QualityModel quality)
|
||||
private String GetQualityTitle(QualityModel quality)
|
||||
{
|
||||
if (quality.Proper)
|
||||
return _qualityDefinitionService.Get(quality.Quality).Title + " Proper";
|
||||
|
|
|
@ -4,13 +4,13 @@ using System.Text.RegularExpressions;
|
|||
|
||||
namespace NzbDrone.Core.Organizer
|
||||
{
|
||||
public class FilenameBuilderTokenEqualityComparer : IEqualityComparer<String>
|
||||
public class FileNameBuilderTokenEqualityComparer : IEqualityComparer<String>
|
||||
{
|
||||
public static readonly FilenameBuilderTokenEqualityComparer Instance = new FilenameBuilderTokenEqualityComparer();
|
||||
public static readonly FileNameBuilderTokenEqualityComparer Instance = new FileNameBuilderTokenEqualityComparer();
|
||||
|
||||
private static readonly Regex SimpleTokenRegex = new Regex(@"\s|_|\W", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
private FilenameBuilderTokenEqualityComparer()
|
||||
private FileNameBuilderTokenEqualityComparer()
|
||||
{
|
||||
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.MediaFiles.MediaInfo;
|
||||
|
||||
namespace NzbDrone.Core.Organizer
|
||||
{
|
||||
|
@ -16,7 +17,7 @@ namespace NzbDrone.Core.Organizer
|
|||
String GetSeasonFolderSample(NamingConfig nameSpec);
|
||||
}
|
||||
|
||||
public class FilenameSampleService : IFilenameSampleService
|
||||
public class FileNameSampleService : IFilenameSampleService
|
||||
{
|
||||
private readonly IBuildFileNames _buildFileNames;
|
||||
private static Series _standardSeries;
|
||||
|
@ -31,26 +32,26 @@ namespace NzbDrone.Core.Organizer
|
|||
private static EpisodeFile _dailyEpisodeFile;
|
||||
private static EpisodeFile _animeEpisodeFile;
|
||||
|
||||
public FilenameSampleService(IBuildFileNames buildFileNames)
|
||||
public FileNameSampleService(IBuildFileNames buildFileNames)
|
||||
{
|
||||
_buildFileNames = buildFileNames;
|
||||
|
||||
_standardSeries = new Series
|
||||
{
|
||||
SeriesType = SeriesTypes.Standard,
|
||||
Title = "Series Title"
|
||||
};
|
||||
{
|
||||
SeriesType = SeriesTypes.Standard,
|
||||
Title = "Series Title (2010)"
|
||||
};
|
||||
|
||||
_dailySeries = new Series
|
||||
{
|
||||
SeriesType = SeriesTypes.Daily,
|
||||
Title = "Series Title"
|
||||
Title = "Series Title (2010)"
|
||||
};
|
||||
|
||||
_animeSeries = new Series
|
||||
{
|
||||
SeriesType = SeriesTypes.Anime,
|
||||
Title = "Series Title"
|
||||
Title = "Series Title (2010)"
|
||||
};
|
||||
|
||||
_episode1 = new Episode
|
||||
|
@ -73,32 +74,52 @@ namespace NzbDrone.Core.Organizer
|
|||
_singleEpisode = new List<Episode> { _episode1 };
|
||||
_multiEpisodes = new List<Episode> { _episode1, _episode2 };
|
||||
|
||||
var mediaInfo = new MediaInfoModel()
|
||||
{
|
||||
VideoCodec = "AVC",
|
||||
AudioFormat = "DTS",
|
||||
AudioLanguages = "English",
|
||||
Subtitles = "English/German"
|
||||
};
|
||||
|
||||
var mediaInfoAnime = new MediaInfoModel()
|
||||
{
|
||||
VideoCodec = "AVC",
|
||||
AudioFormat = "DTS",
|
||||
AudioLanguages = "Japanese",
|
||||
Subtitles = "Japanese/English"
|
||||
};
|
||||
|
||||
_singleEpisodeFile = new EpisodeFile
|
||||
{
|
||||
Quality = new QualityModel(Quality.HDTV720p),
|
||||
Path = @"C:\Test\Series.Title.S01E01.720p.HDTV.x264-EVOLVE.mkv",
|
||||
ReleaseGroup = "RlsGrp"
|
||||
ReleaseGroup = "RlsGrp",
|
||||
MediaInfo = mediaInfo
|
||||
};
|
||||
|
||||
_multiEpisodeFile = new EpisodeFile
|
||||
{
|
||||
Quality = new QualityModel(Quality.HDTV720p),
|
||||
Path = @"C:\Test\Series.Title.S01E01-E02.720p.HDTV.x264-EVOLVE.mkv",
|
||||
ReleaseGroup = "RlsGrp"
|
||||
ReleaseGroup = "RlsGrp",
|
||||
MediaInfo = mediaInfo
|
||||
};
|
||||
|
||||
_dailyEpisodeFile = new EpisodeFile
|
||||
{
|
||||
Quality = new QualityModel(Quality.HDTV720p),
|
||||
Path = @"C:\Test\Series.Title.2013.10.30.HDTV.x264-EVOLVE.mkv",
|
||||
ReleaseGroup = "RlsGrp"
|
||||
ReleaseGroup = "RlsGrp",
|
||||
MediaInfo = mediaInfo
|
||||
};
|
||||
|
||||
_animeEpisodeFile = new EpisodeFile
|
||||
{
|
||||
Quality = new QualityModel(Quality.HDTV720p),
|
||||
Path = @"C:\Test\Series.Title.001.HDTV.x264-EVOLVE.mkv",
|
||||
ReleaseGroup = "RlsGrp"
|
||||
ReleaseGroup = "RlsGrp",
|
||||
MediaInfo = mediaInfoAnime
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -106,7 +127,7 @@ namespace NzbDrone.Core.Organizer
|
|||
{
|
||||
var result = new SampleResult
|
||||
{
|
||||
Filename = BuildSample(_singleEpisode, _standardSeries, _singleEpisodeFile, nameSpec),
|
||||
FileName = BuildSample(_singleEpisode, _standardSeries, _singleEpisodeFile, nameSpec),
|
||||
Series = _standardSeries,
|
||||
Episodes = _singleEpisode,
|
||||
EpisodeFile = _singleEpisodeFile
|
||||
|
@ -119,7 +140,7 @@ namespace NzbDrone.Core.Organizer
|
|||
{
|
||||
var result = new SampleResult
|
||||
{
|
||||
Filename = BuildSample(_multiEpisodes, _standardSeries, _multiEpisodeFile, nameSpec),
|
||||
FileName = BuildSample(_multiEpisodes, _standardSeries, _multiEpisodeFile, nameSpec),
|
||||
Series = _standardSeries,
|
||||
Episodes = _multiEpisodes,
|
||||
EpisodeFile = _multiEpisodeFile
|
||||
|
@ -132,7 +153,7 @@ namespace NzbDrone.Core.Organizer
|
|||
{
|
||||
var result = new SampleResult
|
||||
{
|
||||
Filename = BuildSample(_singleEpisode, _dailySeries, _dailyEpisodeFile, nameSpec),
|
||||
FileName = BuildSample(_singleEpisode, _dailySeries, _dailyEpisodeFile, nameSpec),
|
||||
Series = _dailySeries,
|
||||
Episodes = _singleEpisode,
|
||||
EpisodeFile = _dailyEpisodeFile
|
||||
|
@ -145,7 +166,7 @@ namespace NzbDrone.Core.Organizer
|
|||
{
|
||||
var result = new SampleResult
|
||||
{
|
||||
Filename = BuildSample(_singleEpisode, _animeSeries, _animeEpisodeFile, nameSpec),
|
||||
FileName = BuildSample(_singleEpisode, _animeSeries, _animeEpisodeFile, nameSpec),
|
||||
Series = _animeSeries,
|
||||
Episodes = _singleEpisode,
|
||||
EpisodeFile = _animeEpisodeFile
|
||||
|
@ -156,19 +177,19 @@ namespace NzbDrone.Core.Organizer
|
|||
|
||||
public string GetSeriesFolderSample(NamingConfig nameSpec)
|
||||
{
|
||||
return _buildFileNames.GetSeriesFolder(_standardSeries.Title, nameSpec);
|
||||
return _buildFileNames.GetSeriesFolder(_standardSeries, nameSpec);
|
||||
}
|
||||
|
||||
public string GetSeasonFolderSample(NamingConfig nameSpec)
|
||||
{
|
||||
return _buildFileNames.GetSeasonFolder(_standardSeries.Title, _episode1.SeasonNumber, nameSpec);
|
||||
return _buildFileNames.GetSeasonFolder(_standardSeries, _episode1.SeasonNumber, nameSpec);
|
||||
}
|
||||
|
||||
private string BuildSample(List<Episode> episodes, Series series, EpisodeFile episodeFile, NamingConfig nameSpec)
|
||||
{
|
||||
try
|
||||
{
|
||||
return _buildFileNames.BuildFilename(episodes, series, episodeFile, nameSpec);
|
||||
return _buildFileNames.BuildFileName(episodes, series, episodeFile, nameSpec);
|
||||
}
|
||||
catch (NamingFormatException)
|
||||
{
|
||||
|
|
|
@ -14,14 +14,14 @@ namespace NzbDrone.Core.Organizer
|
|||
ValidationFailure ValidateAnimeFilename(SampleResult sampleResult);
|
||||
}
|
||||
|
||||
public class FilenameValidationService : IFilenameValidationService
|
||||
public class FileNameValidationService : IFilenameValidationService
|
||||
{
|
||||
private const string ERROR_MESSAGE = "Produces invalid file names";
|
||||
|
||||
public ValidationFailure ValidateStandardFilename(SampleResult sampleResult)
|
||||
{
|
||||
var validationFailure = new ValidationFailure("StandardEpisodeFormat", ERROR_MESSAGE);
|
||||
var parsedEpisodeInfo = Parser.Parser.ParseTitle(sampleResult.Filename);
|
||||
var parsedEpisodeInfo = Parser.Parser.ParseTitle(sampleResult.FileName);
|
||||
|
||||
if (parsedEpisodeInfo == null)
|
||||
{
|
||||
|
@ -39,7 +39,7 @@ namespace NzbDrone.Core.Organizer
|
|||
public ValidationFailure ValidateDailyFilename(SampleResult sampleResult)
|
||||
{
|
||||
var validationFailure = new ValidationFailure("DailyEpisodeFormat", ERROR_MESSAGE);
|
||||
var parsedEpisodeInfo = Parser.Parser.ParseTitle(sampleResult.Filename);
|
||||
var parsedEpisodeInfo = Parser.Parser.ParseTitle(sampleResult.FileName);
|
||||
|
||||
if (parsedEpisodeInfo == null)
|
||||
{
|
||||
|
@ -67,7 +67,7 @@ namespace NzbDrone.Core.Organizer
|
|||
public ValidationFailure ValidateAnimeFilename(SampleResult sampleResult)
|
||||
{
|
||||
var validationFailure = new ValidationFailure("AnimeEpisodeFormat", ERROR_MESSAGE);
|
||||
var parsedEpisodeInfo = Parser.Parser.ParseTitle(sampleResult.Filename);
|
||||
var parsedEpisodeInfo = Parser.Parser.ParseTitle(sampleResult.FileName);
|
||||
|
||||
if (parsedEpisodeInfo == null)
|
||||
{
|
||||
|
|
|
@ -9,7 +9,7 @@ namespace NzbDrone.Core.Organizer
|
|||
{
|
||||
public class SampleResult
|
||||
{
|
||||
public string Filename { get; set; }
|
||||
public String FileName { get; set; }
|
||||
public Series Series { get; set; }
|
||||
public List<Episode> Episodes { get; set; }
|
||||
public EpisodeFile EpisodeFile { get; set; }
|
||||
|
|
|
@ -71,7 +71,7 @@ namespace NzbDrone.Core.Tv
|
|||
|
||||
if (String.IsNullOrWhiteSpace(newSeries.Path))
|
||||
{
|
||||
var folderName = _fileNameBuilder.GetSeriesFolder(newSeries.Title);
|
||||
var folderName = _fileNameBuilder.GetSeriesFolder(newSeries);
|
||||
newSeries.Path = Path.Combine(newSeries.RootFolderPath, folderName);
|
||||
}
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
{{> EpisodeNamingPartial}}
|
||||
{{> EpisodeTitleNamingPartial}}
|
||||
{{> QualityTitleNamingPartial}}
|
||||
{{> MediaInfoNamingPartial}}
|
||||
{{> ReleaseGroupNamingPartial}}
|
||||
{{> OriginalTitleNamingPartial}}
|
||||
{{> SeparatorNamingPartial}}
|
||||
|
@ -79,6 +80,7 @@
|
|||
{{> EpisodeNamingPartial}}
|
||||
{{> EpisodeTitleNamingPartial}}
|
||||
{{> QualityTitleNamingPartial}}
|
||||
{{> MediaInfoNamingPartial}}
|
||||
{{> ReleaseGroupNamingPartial}}
|
||||
{{> OriginalTitleNamingPartial}}
|
||||
{{> SeparatorNamingPartial}}
|
||||
|
@ -110,6 +112,7 @@
|
|||
{{> EpisodeNamingPartial}}
|
||||
{{> EpisodeTitleNamingPartial}}
|
||||
{{> QualityTitleNamingPartial}}
|
||||
{{> MediaInfoNamingPartial}}
|
||||
{{> ReleaseGroupNamingPartial}}
|
||||
{{> OriginalTitleNamingPartial}}
|
||||
{{> SeparatorNamingPartial}}
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<li class="dropdown-submenu">
|
||||
<a href="#" tabindex="-1" data-token="MediaInfo.Simple">MediaInfo</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="#" data-token="MediaInfo Simple">MediaInfo Simple</a></li>
|
||||
<li><a href="#" data-token="MediaInfo.Simple">MediaInfo.Simple</a></li>
|
||||
<li><a href="#" data-token="MediaInfo_Simple">MediaInfo_Simple</a></li>
|
||||
<li><a href="#" data-token="MediaInfo Full">MediaInfo Full</a></li>
|
||||
<li><a href="#" data-token="MediaInfo.Full">MediaInfo.Full</a></li>
|
||||
<li><a href="#" data-token="MediaInfo_Full">MediaInfo_Full</a></li>
|
||||
</ul>
|
||||
</li>
|
|
@ -4,5 +4,8 @@
|
|||
<li><a href="#" data-token="Series Title">Series Title</a></li>
|
||||
<li><a href="#" data-token="Series.Title">Series.Title</a></li>
|
||||
<li><a href="#" data-token="Series_Title">Series_Title</a></li>
|
||||
<li><a href="#" data-token="Series CleanTitle">Series CleanTitle</a></li>
|
||||
<li><a href="#" data-token="Series.CleanTitle">Series.CleanTitle</a></li>
|
||||
<li><a href="#" data-token="Series_CleanTitle">Series_CleanTitle</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
|
Loading…
Reference in New Issue