From 05e4af9ae723a129950fa344dbee41c583056199 Mon Sep 17 00:00:00 2001 From: Tim Turner Date: Fri, 6 Jan 2017 22:51:15 -0500 Subject: [PATCH] 1st pass at Movie Naming Parser is failing on the sample --- src/NzbDrone.Api/Config/NamingConfigModule.cs | 67 +++--- .../Config/NamingConfigResource.cs | 12 +- .../109_add_movie_formats_to_naming_config.cs | 7 +- .../Organizer/FileNameBuilder.cs | 211 ++++++++++++++---- .../Organizer/FileNameSampleService.cs | 47 ++++ .../Organizer/FileNameValidationService.cs | 14 ++ .../FileManagementViewTemplate.hbs | 4 +- .../MediaManagement/Naming/NamingView.js | 6 +- .../Naming/NamingViewTemplate.hbs | 8 +- 9 files changed, 288 insertions(+), 88 deletions(-) diff --git a/src/NzbDrone.Api/Config/NamingConfigModule.cs b/src/NzbDrone.Api/Config/NamingConfigModule.cs index 301966406..3e063bff4 100644 --- a/src/NzbDrone.Api/Config/NamingConfigModule.cs +++ b/src/NzbDrone.Api/Config/NamingConfigModule.cs @@ -81,39 +81,50 @@ namespace NzbDrone.Api.Config var nameSpec = config.ToModel(); var sampleResource = new NamingSampleResource(); - var singleEpisodeSampleResult = _filenameSampleService.GetStandardSample(nameSpec); - var multiEpisodeSampleResult = _filenameSampleService.GetMultiEpisodeSample(nameSpec); - var dailyEpisodeSampleResult = _filenameSampleService.GetDailySample(nameSpec); - var animeEpisodeSampleResult = _filenameSampleService.GetAnimeSample(nameSpec); - var animeMultiEpisodeSampleResult = _filenameSampleService.GetAnimeMultiEpisodeSample(nameSpec); + //var singleEpisodeSampleResult = _filenameSampleService.GetStandardSample(nameSpec); + //var multiEpisodeSampleResult = _filenameSampleService.GetMultiEpisodeSample(nameSpec); + //var dailyEpisodeSampleResult = _filenameSampleService.GetDailySample(nameSpec); + //var animeEpisodeSampleResult = _filenameSampleService.GetAnimeSample(nameSpec); + //var animeMultiEpisodeSampleResult = _filenameSampleService.GetAnimeMultiEpisodeSample(nameSpec); - sampleResource.SingleEpisodeExample = _filenameValidationService.ValidateStandardFilename(singleEpisodeSampleResult) != null - ? "Invalid format" - : singleEpisodeSampleResult.FileName; + var movieSampleResult = _filenameSampleService.GetMovieSample(nameSpec); + - sampleResource.MultiEpisodeExample = _filenameValidationService.ValidateStandardFilename(multiEpisodeSampleResult) != null - ? "Invalid format" - : multiEpisodeSampleResult.FileName; + //sampleResource.SingleEpisodeExample = _filenameValidationService.ValidateStandardFilename(singleEpisodeSampleResult) != null + // ? "Invalid format" + // : singleEpisodeSampleResult.FileName; - sampleResource.DailyEpisodeExample = _filenameValidationService.ValidateDailyFilename(dailyEpisodeSampleResult) != null - ? "Invalid format" - : dailyEpisodeSampleResult.FileName; + //sampleResource.MultiEpisodeExample = _filenameValidationService.ValidateStandardFilename(multiEpisodeSampleResult) != null + // ? "Invalid format" + // : multiEpisodeSampleResult.FileName; - sampleResource.AnimeEpisodeExample = _filenameValidationService.ValidateAnimeFilename(animeEpisodeSampleResult) != null - ? "Invalid format" - : animeEpisodeSampleResult.FileName; + //sampleResource.DailyEpisodeExample = _filenameValidationService.ValidateDailyFilename(dailyEpisodeSampleResult) != null + // ? "Invalid format" + // : dailyEpisodeSampleResult.FileName; - sampleResource.AnimeMultiEpisodeExample = _filenameValidationService.ValidateAnimeFilename(animeMultiEpisodeSampleResult) != null - ? "Invalid format" - : animeMultiEpisodeSampleResult.FileName; + //sampleResource.AnimeEpisodeExample = _filenameValidationService.ValidateAnimeFilename(animeEpisodeSampleResult) != null + // ? "Invalid format" + // : animeEpisodeSampleResult.FileName; - sampleResource.SeriesFolderExample = nameSpec.SeriesFolderFormat.IsNullOrWhiteSpace() - ? "Invalid format" - : _filenameSampleService.GetSeriesFolderSample(nameSpec); + //sampleResource.AnimeMultiEpisodeExample = _filenameValidationService.ValidateAnimeFilename(animeMultiEpisodeSampleResult) != null + // ? "Invalid format" + // : animeMultiEpisodeSampleResult.FileName; + + sampleResource.MovieExample = _filenameValidationService.ValidateMovieFilename(movieSampleResult) != null + ? "Invalid Format" + : movieSampleResult.FileName; + + //sampleResource.SeriesFolderExample = nameSpec.SeriesFolderFormat.IsNullOrWhiteSpace() + // ? "Invalid format" + // : _filenameSampleService.GetSeriesFolderSample(nameSpec); + + //sampleResource.SeasonFolderExample = nameSpec.SeasonFolderFormat.IsNullOrWhiteSpace() + // ? "Invalid format" + // : _filenameSampleService.GetSeasonFolderSample(nameSpec); - sampleResource.SeasonFolderExample = nameSpec.SeasonFolderFormat.IsNullOrWhiteSpace() + sampleResource.MovieFolderExample = nameSpec.MovieFolderFormat.IsNullOrWhiteSpace() ? "Invalid format" - : _filenameSampleService.GetSeasonFolderSample(nameSpec); + : _filenameSampleService.GetMovieFolderSample(nameSpec); return sampleResource.AsResponse(); } @@ -126,7 +137,7 @@ namespace NzbDrone.Api.Config var animeEpisodeSampleResult = _filenameSampleService.GetAnimeSample(nameSpec); var animeMultiEpisodeSampleResult = _filenameSampleService.GetAnimeMultiEpisodeSample(nameSpec); - //var movieSampleResult = _filenameSampleService.GetMovieSample(nameSpec); + var movieSampleResult = _filenameSampleService.GetMovieSample(nameSpec); var singleEpisodeValidationResult = _filenameValidationService.ValidateStandardFilename(singleEpisodeSampleResult); var multiEpisodeValidationResult = _filenameValidationService.ValidateStandardFilename(multiEpisodeSampleResult); @@ -134,7 +145,7 @@ namespace NzbDrone.Api.Config var animeEpisodeValidationResult = _filenameValidationService.ValidateAnimeFilename(animeEpisodeSampleResult); var animeMultiEpisodeValidationResult = _filenameValidationService.ValidateAnimeFilename(animeMultiEpisodeSampleResult); - //var standardMovieValidationResult = _filenameValidationService.ValidateStandardMovieFilename(movieSampleResult); + var standardMovieValidationResult = _filenameValidationService.ValidateMovieFilename(movieSampleResult); var validationFailures = new List(); @@ -144,7 +155,7 @@ namespace NzbDrone.Api.Config validationFailures.AddIfNotNull(animeEpisodeValidationResult); validationFailures.AddIfNotNull(animeMultiEpisodeValidationResult); - //validationFailures.AddIfNotNull(standardMovieValidationResult); + validationFailures.AddIfNotNull(standardMovieValidationResult); if (validationFailures.Any()) { diff --git a/src/NzbDrone.Api/Config/NamingConfigResource.cs b/src/NzbDrone.Api/Config/NamingConfigResource.cs index 110a7d402..f65d90e48 100644 --- a/src/NzbDrone.Api/Config/NamingConfigResource.cs +++ b/src/NzbDrone.Api/Config/NamingConfigResource.cs @@ -68,12 +68,12 @@ namespace NzbDrone.Api.Config RenameEpisodes = resource.RenameEpisodes, ReplaceIllegalCharacters = resource.ReplaceIllegalCharacters, - MultiEpisodeStyle = resource.MultiEpisodeStyle, - StandardEpisodeFormat = resource.StandardEpisodeFormat, - DailyEpisodeFormat = resource.DailyEpisodeFormat, - AnimeEpisodeFormat = resource.AnimeEpisodeFormat, - SeriesFolderFormat = resource.SeriesFolderFormat, - SeasonFolderFormat = resource.SeasonFolderFormat, + //MultiEpisodeStyle = resource.MultiEpisodeStyle, + //StandardEpisodeFormat = resource.StandardEpisodeFormat, + //DailyEpisodeFormat = resource.DailyEpisodeFormat, + //AnimeEpisodeFormat = resource.AnimeEpisodeFormat, + //SeriesFolderFormat = resource.SeriesFolderFormat, + //SeasonFolderFormat = resource.SeasonFolderFormat, StandardMovieFormat = resource.StandardMovieFormat, MovieFolderFormat = resource.MovieFolderFormat }; diff --git a/src/NzbDrone.Core/Datastore/Migration/109_add_movie_formats_to_naming_config.cs b/src/NzbDrone.Core/Datastore/Migration/109_add_movie_formats_to_naming_config.cs index a51232718..9617ed1c6 100644 --- a/src/NzbDrone.Core/Datastore/Migration/109_add_movie_formats_to_naming_config.cs +++ b/src/NzbDrone.Core/Datastore/Migration/109_add_movie_formats_to_naming_config.cs @@ -40,7 +40,7 @@ namespace NzbDrone.Core.Datastore.Migration // Output Settings var movieTitlePattern = ""; - var movieYearPattern = "({Release Year})"; + //var movieYearPattern = "({Release Year})"; var qualityFormat = " [{Quality Title}]"; if (replaceSpaces) @@ -55,11 +55,10 @@ namespace NzbDrone.Core.Datastore.Migration movieTitlePattern += separator; - var standardMovieFormat = string.Format("{0}{1}{2}", movieTitlePattern, - movieYearPattern, + var standardMovieFormat = string.Format("{0}{1}", movieTitlePattern, qualityFormat); - var movieFolderFormat = string.Format("{0}{1}", movieTitlePattern, movieYearPattern); + var movieFolderFormat = string.Format("{0}", movieTitlePattern); if (includeQuality) { diff --git a/src/NzbDrone.Core/Organizer/FileNameBuilder.cs b/src/NzbDrone.Core/Organizer/FileNameBuilder.cs index 53ed08998..96479e44b 100644 --- a/src/NzbDrone.Core/Organizer/FileNameBuilder.cs +++ b/src/NzbDrone.Core/Organizer/FileNameBuilder.cs @@ -24,7 +24,7 @@ namespace NzbDrone.Core.Organizer BasicNamingConfig GetBasicNamingConfig(NamingConfig nameSpec); string GetSeriesFolder(Series series, NamingConfig namingConfig = null); string GetSeasonFolder(Series series, int seasonNumber, NamingConfig namingConfig = null); - string GetMovieFolder(Movie movie); + string GetMovieFolder(Movie movie, NamingConfig namingConfig = null); } public class FileNameBuilder : IBuildFileNames @@ -79,6 +79,7 @@ namespace NzbDrone.Core.Organizer { _namingConfigService = namingConfigService; _qualityDefinitionService = qualityDefinitionService; + //_movieFormatCache = cacheManager.GetCache(GetType(), "movieFormat"); _episodeFormatCache = cacheManager.GetCache(GetType(), "episodeFormat"); _absoluteEpisodeFormatCache = cacheManager.GetCache(GetType(), "absoluteEpisodeFormat"); _logger = logger; @@ -154,52 +155,20 @@ namespace NzbDrone.Core.Organizer return GetOriginalTitle(movieFile); } - /*if (namingConfig.StandardEpisodeFormat.IsNullOrWhiteSpace() && series.SeriesType == SeriesTypes.Standard) - { - throw new NamingFormatException("Standard episode format cannot be empty"); - } - - if (namingConfig.DailyEpisodeFormat.IsNullOrWhiteSpace() && series.SeriesType == SeriesTypes.Daily) - { - throw new NamingFormatException("Daily episode format cannot be empty"); - } - - if (namingConfig.AnimeEpisodeFormat.IsNullOrWhiteSpace() && series.SeriesType == SeriesTypes.Anime) - { - throw new NamingFormatException("Anime episode format cannot be empty"); - }*/ - - /*var pattern = namingConfig.StandardEpisodeFormat; + //TODO: Update namingConfig for Movies! + var pattern = namingConfig.StandardMovieFormat; var tokenHandlers = new Dictionary>(FileNameBuilderTokenEqualityComparer.Instance); - episodes = episodes.OrderBy(e => e.SeasonNumber).ThenBy(e => e.EpisodeNumber).ToList(); - - if (series.SeriesType == SeriesTypes.Daily) - { - pattern = namingConfig.DailyEpisodeFormat; - } - - if (series.SeriesType == SeriesTypes.Anime && episodes.All(e => e.AbsoluteEpisodeNumber.HasValue)) - { - pattern = namingConfig.AnimeEpisodeFormat; - } - - pattern = AddSeasonEpisodeNumberingTokens(pattern, tokenHandlers, episodes, namingConfig); - pattern = AddAbsoluteNumberingTokens(pattern, tokenHandlers, series, episodes, namingConfig); - - AddSeriesTokens(tokenHandlers, series); - AddEpisodeTokens(tokenHandlers, episodes); - AddEpisodeFileTokens(tokenHandlers, episodeFile); - AddQualityTokens(tokenHandlers, series, episodeFile); - AddMediaInfoTokens(tokenHandlers, episodeFile); + AddMovieTokens(tokenHandlers, movie); + //AddReleaseDateTokens(tokenHandlers, movie.Year); //In case we want to separate the year + AddQualityTokens(tokenHandlers, movie, movieFile); + AddMediaInfoTokens(tokenHandlers, movieFile); var fileName = ReplaceTokens(pattern, tokenHandlers, namingConfig).Trim(); fileName = FileNameCleanupRegex.Replace(fileName, match => match.Captures[0].Value[0].ToString()); - fileName = TrimSeparatorsRegex.Replace(fileName, string.Empty);*/ - - //TODO: Update namingConfig for Movies! + fileName = TrimSeparatorsRegex.Replace(fileName, string.Empty); - return GetOriginalTitle(movieFile); + return fileName; } public string BuildFilePath(Series series, int seasonNumber, string fileName, string extension) @@ -318,9 +287,18 @@ namespace NzbDrone.Core.Organizer return CleanFolderName(ReplaceTokens(namingConfig.SeasonFolderFormat, tokenHandlers, namingConfig)); } - public string GetMovieFolder(Movie movie) + public string GetMovieFolder(Movie movie, NamingConfig namingConfig = null) { - return CleanFolderName(movie.Title); + if(namingConfig == null) + { + namingConfig = _namingConfigService.GetConfig(); + } + + var tokenHandlers = new Dictionary>(FileNameBuilderTokenEqualityComparer.Instance); + + AddMovieTokens(tokenHandlers, movie); + + return CleanFolderName(ReplaceTokens(namingConfig.MovieFolderFormat, tokenHandlers, namingConfig)); } public static string CleanTitle(string title) @@ -484,6 +462,17 @@ namespace NzbDrone.Core.Organizer return pattern; } + private void AddMovieTokens(Dictionary> tokenHandlers, Movie movie) + { + tokenHandlers["{Movie Title}"] = m => movie.Title; + tokenHandlers["{Movie CleanTitle}"] = m => CleanTitle(movie.Title); + } + + private void AddReleaseDateTokens(Dictionary> tokenHandlers, int releaseYear) + { + tokenHandlers["{Release Year}"] = m => string.Format("({0})", releaseYear.ToString()); //Do I need m.CustomFormat? + } + private void AddSeasonTokens(Dictionary> tokenHandlers, int seasonNumber) { tokenHandlers["{Season}"] = m => seasonNumber.ToString(m.CustomFormat); @@ -523,6 +512,18 @@ namespace NzbDrone.Core.Organizer tokenHandlers["{Quality Real}"] = m => qualityReal; } + private void AddQualityTokens(Dictionary> tokenHandlers, Movie movie, MovieFile movieFile) + { + var qualityTitle = _qualityDefinitionService.Get(movieFile.Quality.Quality).Title; + var qualityProper = GetQualityProper(movie, movieFile.Quality); + var qualityReal = GetQualityReal(movie, movieFile.Quality); + + tokenHandlers["{Quality Full}"] = m => String.Format("{0} {1} {2}", qualityTitle, qualityProper, qualityReal); + tokenHandlers["{Quality Title}"] = m => qualityTitle; + tokenHandlers["{Quality Proper}"] = m => qualityProper; + tokenHandlers["{Quality Real}"] = m => qualityReal; + } + private void AddMediaInfoTokens(Dictionary> tokenHandlers, EpisodeFile episodeFile) { if (episodeFile.MediaInfo == null) return; @@ -627,6 +628,110 @@ namespace NzbDrone.Core.Organizer tokenHandlers["{MediaInfo Full}"] = m => string.Format("{0} {1}{2} {3}", videoCodec, audioCodec, mediaInfoAudioLanguages, mediaInfoSubtitleLanguages); } + private void AddMediaInfoTokens(Dictionary> tokenHandlers, MovieFile movieFile) + { + if (movieFile.MediaInfo == null) return; + + string videoCodec; + switch (movieFile.MediaInfo.VideoCodec) + { + case "AVC": + if (movieFile.SceneName.IsNotNullOrWhiteSpace() && Path.GetFileNameWithoutExtension(movieFile.SceneName).Contains("h264")) + { + videoCodec = "h264"; + } + else + { + videoCodec = "x264"; + } + break; + + case "V_MPEGH/ISO/HEVC": + if (movieFile.SceneName.IsNotNullOrWhiteSpace() && Path.GetFileNameWithoutExtension(movieFile.SceneName).Contains("h265")) + { + videoCodec = "h265"; + } + else + { + videoCodec = "x265"; + } + break; + + case "MPEG-2 Video": + videoCodec = "MPEG2"; + break; + + default: + videoCodec = movieFile.MediaInfo.VideoCodec; + break; + } + + string audioCodec; + switch (movieFile.MediaInfo.AudioFormat) + { + case "AC-3": + audioCodec = "AC3"; + break; + + case "E-AC-3": + audioCodec = "EAC3"; + break; + + case "MPEG Audio": + if (movieFile.MediaInfo.AudioProfile == "Layer 3") + { + audioCodec = "MP3"; + } + else + { + audioCodec = movieFile.MediaInfo.AudioFormat; + } + break; + + case "DTS": + audioCodec = movieFile.MediaInfo.AudioFormat; + break; + + default: + audioCodec = movieFile.MediaInfo.AudioFormat; + break; + } + + var mediaInfoAudioLanguages = GetLanguagesToken(movieFile.MediaInfo.AudioLanguages); + if (!mediaInfoAudioLanguages.IsNullOrWhiteSpace()) + { + mediaInfoAudioLanguages = string.Format("[{0}]", mediaInfoAudioLanguages); + } + + if (mediaInfoAudioLanguages == "[EN]") + { + mediaInfoAudioLanguages = string.Empty; + } + + var mediaInfoSubtitleLanguages = GetLanguagesToken(movieFile.MediaInfo.Subtitles); + if (!mediaInfoSubtitleLanguages.IsNullOrWhiteSpace()) + { + mediaInfoSubtitleLanguages = string.Format("[{0}]", mediaInfoSubtitleLanguages); + } + + var videoBitDepth = movieFile.MediaInfo.VideoBitDepth > 0 ? movieFile.MediaInfo.VideoBitDepth.ToString() : string.Empty; + var audioChannels = movieFile.MediaInfo.FormattedAudioChannels > 0 ? + movieFile.MediaInfo.FormattedAudioChannels.ToString("F1", CultureInfo.InvariantCulture) : + string.Empty; + + tokenHandlers["{MediaInfo Video}"] = m => videoCodec; + tokenHandlers["{MediaInfo VideoCodec}"] = m => videoCodec; + tokenHandlers["{MediaInfo VideoBitDepth}"] = m => videoBitDepth; + + tokenHandlers["{MediaInfo Audio}"] = m => audioCodec; + tokenHandlers["{MediaInfo AudioCodec}"] = m => audioCodec; + tokenHandlers["{MediaInfo AudioChannels}"] = m => audioChannels; + + tokenHandlers["{MediaInfo Simple}"] = m => string.Format("{0} {1}", videoCodec, audioCodec); + + tokenHandlers["{MediaInfo Full}"] = m => string.Format("{0} {1}{2} {3}", videoCodec, audioCodec, mediaInfoAudioLanguages, mediaInfoSubtitleLanguages); + } + private string GetLanguagesToken(string mediaInfoLanguages) { List tokens = new List(); @@ -806,6 +911,16 @@ namespace NzbDrone.Core.Organizer return MultiPartCleanupRegex.Replace(title, string.Empty).Trim(); } + private string GetQualityProper(Movie movie, QualityModel quality) + { + if (quality.Revision.Version > 1) + { + return "Proper"; + } + + return String.Empty; + } + private string GetQualityProper(Series series, QualityModel quality) { if (quality.Revision.Version > 1) @@ -831,6 +946,16 @@ namespace NzbDrone.Core.Organizer return string.Empty; } + private string GetQualityReal(Movie movie, QualityModel quality) + { + if (quality.Revision.Real > 0) + { + return "REAL"; + } + + return string.Empty; + } + private string GetOriginalTitle(EpisodeFile episodeFile) { if (episodeFile.SceneName.IsNullOrWhiteSpace()) diff --git a/src/NzbDrone.Core/Organizer/FileNameSampleService.cs b/src/NzbDrone.Core/Organizer/FileNameSampleService.cs index 966061fb3..2305acc4b 100644 --- a/src/NzbDrone.Core/Organizer/FileNameSampleService.cs +++ b/src/NzbDrone.Core/Organizer/FileNameSampleService.cs @@ -3,6 +3,7 @@ using NzbDrone.Core.MediaFiles; using NzbDrone.Core.Qualities; using NzbDrone.Core.Tv; using NzbDrone.Core.MediaFiles.MediaInfo; +using System; namespace NzbDrone.Core.Organizer { @@ -13,8 +14,10 @@ namespace NzbDrone.Core.Organizer SampleResult GetDailySample(NamingConfig nameSpec); SampleResult GetAnimeSample(NamingConfig nameSpec); SampleResult GetAnimeMultiEpisodeSample(NamingConfig nameSpec); + SampleResult GetMovieSample(NamingConfig nameSpec); string GetSeriesFolderSample(NamingConfig nameSpec); string GetSeasonFolderSample(NamingConfig nameSpec); + string GetMovieFolderSample(NamingConfig nameSpec); } public class FileNameSampleService : IFilenameSampleService @@ -34,10 +37,18 @@ namespace NzbDrone.Core.Organizer private static EpisodeFile _animeEpisodeFile; private static EpisodeFile _animeMultiEpisodeFile; + private static MovieFile _movieFile; + private static Movie _movie; + public FileNameSampleService(IBuildFileNames buildFileNames) { _buildFileNames = buildFileNames; + _movie = new Movie + { + Title = "Movie Title (2010)" + }; + _standardSeries = new Series { SeriesType = SeriesTypes.Standard, @@ -106,6 +117,15 @@ namespace NzbDrone.Core.Organizer Subtitles = "Japanese/English" }; + _movieFile = new MovieFile + { + Quality = new QualityModel(Quality.Bluray1080p, new Revision(2)), + RelativePath = "Movie.Title.2010.1080p.BluRay.DTS.x264-EVOLVE.mkv", + SceneName = "Movie.Title.2010.1080p.BluRay.DTS.x264-EVOLVE", + ReleaseGroup = "RlsGrp", + MediaInfo = mediaInfo + }; + _singleEpisodeFile = new EpisodeFile { Quality = new QualityModel(Quality.HDTV720p, new Revision(2)), @@ -217,6 +237,16 @@ namespace NzbDrone.Core.Organizer return result; } + public SampleResult GetMovieSample(NamingConfig nameSpec) + { + var result = new SampleResult + { + FileName = BuildSample(_movie, _movieFile, nameSpec), + }; + + return result; + } + public string GetSeriesFolderSample(NamingConfig nameSpec) { return _buildFileNames.GetSeriesFolder(_standardSeries, nameSpec); @@ -227,6 +257,11 @@ namespace NzbDrone.Core.Organizer return _buildFileNames.GetSeasonFolder(_standardSeries, _episode1.SeasonNumber, nameSpec); } + public string GetMovieFolderSample(NamingConfig nameSpec) + { + return _buildFileNames.GetMovieFolder(_movie, nameSpec); + } + private string BuildSample(List episodes, Series series, EpisodeFile episodeFile, NamingConfig nameSpec) { try @@ -238,5 +273,17 @@ namespace NzbDrone.Core.Organizer return string.Empty; } } + + private string BuildSample(Movie movie, MovieFile movieFile, NamingConfig nameSpec) + { + try + { + return _buildFileNames.BuildFileName(movie, movieFile, nameSpec); + } + catch (NamingFormatException) + { + return string.Empty; + } + } } } diff --git a/src/NzbDrone.Core/Organizer/FileNameValidationService.cs b/src/NzbDrone.Core/Organizer/FileNameValidationService.cs index 9367c11d8..697f72bbb 100644 --- a/src/NzbDrone.Core/Organizer/FileNameValidationService.cs +++ b/src/NzbDrone.Core/Organizer/FileNameValidationService.cs @@ -11,12 +11,26 @@ namespace NzbDrone.Core.Organizer ValidationFailure ValidateStandardFilename(SampleResult sampleResult); ValidationFailure ValidateDailyFilename(SampleResult sampleResult); ValidationFailure ValidateAnimeFilename(SampleResult sampleResult); + ValidationFailure ValidateMovieFilename(SampleResult sampleResult); } public class FileNameValidationService : IFilenameValidationService { private const string ERROR_MESSAGE = "Produces invalid file names"; + public ValidationFailure ValidateMovieFilename(SampleResult sampleResult) + { + var validationFailure = new ValidationFailure("MovieFormat", ERROR_MESSAGE); + var parsedMovieInfo = Parser.Parser.ParseMovieTitle(sampleResult.FileName); + + if(parsedMovieInfo == null) + { + return validationFailure; + } + + return null; + } + public ValidationFailure ValidateStandardFilename(SampleResult sampleResult) { var validationFailure = new ValidationFailure("StandardEpisodeFormat", ERROR_MESSAGE); diff --git a/src/UI/Settings/MediaManagement/FileManagement/FileManagementViewTemplate.hbs b/src/UI/Settings/MediaManagement/FileManagement/FileManagementViewTemplate.hbs index 6d0652fa3..9fd640ec0 100644 --- a/src/UI/Settings/MediaManagement/FileManagement/FileManagementViewTemplate.hbs +++ b/src/UI/Settings/MediaManagement/FileManagement/FileManagementViewTemplate.hbs @@ -2,7 +2,7 @@ File Management
- +
@@ -17,7 +17,7 @@ - +
diff --git a/src/UI/Settings/MediaManagement/Naming/NamingView.js b/src/UI/Settings/MediaManagement/Naming/NamingView.js index 71e4df4f8..5496fb784 100644 --- a/src/UI/Settings/MediaManagement/Naming/NamingView.js +++ b/src/UI/Settings/MediaManagement/Naming/NamingView.js @@ -19,7 +19,9 @@ module.exports = (function() { namingTokenHelper : '.x-naming-token-helper', multiEpisodeStyle : '.x-multi-episode-style', seriesFolderExample : '.x-series-folder-example', - seasonFolderExample : '.x-season-folder-example' + seasonFolderExample : '.x-season-folder-example', + movieExample : '.x-movie-example', + movieFolderExample : '.x-movie-folder-example' }, events : { "change .x-rename-episodes" : '_setFailedDownloadOptionsVisibility', @@ -58,6 +60,8 @@ module.exports = (function() { this.ui.animeMultiEpisodeExample.html(this.namingSampleModel.get('animeMultiEpisodeExample')); this.ui.seriesFolderExample.html(this.namingSampleModel.get('seriesFolderExample')); this.ui.seasonFolderExample.html(this.namingSampleModel.get('seasonFolderExample')); + this.ui.movieExample.html(this.namingSampleModel.get('movieExample')); + this.ui.movieFolderExample.html(this.namingSampleModel.get('movieFolderExample')); }, _addToken : function(e) { e.preventDefault(); diff --git a/src/UI/Settings/MediaManagement/Naming/NamingViewTemplate.hbs b/src/UI/Settings/MediaManagement/Naming/NamingViewTemplate.hbs index 1b0e34c2f..ccd233d84 100644 --- a/src/UI/Settings/MediaManagement/Naming/NamingViewTemplate.hbs +++ b/src/UI/Settings/MediaManagement/Naming/NamingViewTemplate.hbs @@ -67,7 +67,7 @@
@@ -208,7 +208,7 @@
-

+

@@ -247,7 +247,7 @@
-

+