diff --git a/frontend/src/Settings/MediaManagement/Naming/NamingModal.js b/frontend/src/Settings/MediaManagement/Naming/NamingModal.js index f5dd5564e..6b13bbad7 100644 --- a/frontend/src/Settings/MediaManagement/Naming/NamingModal.js +++ b/frontend/src/Settings/MediaManagement/Naming/NamingModal.js @@ -123,7 +123,9 @@ class NamingModal extends Component { { token: '{Album CleanTitle}', example: 'Album Title' }, { token: '{Album.CleanTitle}', example: 'Album.Title' }, - { token: '{Album_CleanTitle}', example: 'Album_Title' } + { token: '{Album_CleanTitle}', example: 'Album_Title' }, + + { token: '{Album Type}', example: 'Album Type' } ]; const mediumTokens = [ diff --git a/src/NzbDrone.Core/Organizer/FileNameBuilder.cs b/src/NzbDrone.Core/Organizer/FileNameBuilder.cs index 9e1be9150..9a0e68d85 100644 --- a/src/NzbDrone.Core/Organizer/FileNameBuilder.cs +++ b/src/NzbDrone.Core/Organizer/FileNameBuilder.cs @@ -36,7 +36,7 @@ namespace NzbDrone.Core.Organizer private static readonly Regex TitleRegex = new Regex(@"\{(?[- ._\[(]*)(?(?:[a-z0-9]+)(?:(?[- ._]+)(?:[a-z0-9]+))?)(?::(?[a-z0-9]+))?(?[- ._)\]]*)\}", RegexOptions.Compiled | RegexOptions.IgnoreCase); - private static readonly Regex TrackRegex = new Regex(@"(?\{track(?:\:0+)?})", + public static readonly Regex TrackRegex = new Regex(@"(?\{track(?:\:0+)?})", RegexOptions.Compiled | RegexOptions.IgnoreCase); private static readonly Regex MediumRegex = new Regex(@"(?\{medium(?:\:0+)?})", @@ -45,7 +45,7 @@ namespace NzbDrone.Core.Organizer public static readonly Regex SeasonEpisodePatternRegex = new Regex(@"(?(?<=})[- ._]+?)?(?s?{season(?:\:0+)?}(?[- ._]?[ex])(?{episode(?:\:0+)?}))(?[- ._]+?(?={))?", RegexOptions.Compiled | RegexOptions.IgnoreCase); - public static readonly Regex AirDateRegex = new Regex(@"\{Air(\s|\W|_)Date\}", RegexOptions.Compiled | RegexOptions.IgnoreCase); + public static readonly Regex ReleaseDateRegex = new Regex(@"\{Release(\s|\W|_)Year\}", RegexOptions.Compiled | RegexOptions.IgnoreCase); public static readonly Regex ArtistNameRegex = new Regex(@"(?\{(?:Artist)(?[- ._])(Clean)?Name(The)?\})", RegexOptions.Compiled | RegexOptions.IgnoreCase); @@ -53,6 +53,9 @@ namespace NzbDrone.Core.Organizer public static readonly Regex AlbumTitleRegex = new Regex(@"(?\{(?:Album)(?[- ._])(Clean)?Title(The)?\})", RegexOptions.Compiled | RegexOptions.IgnoreCase); + public static readonly Regex TrackTitleRegex = new Regex(@"(?\{(?:Track)(?[- ._])(Clean)?Title(The)?\})", + RegexOptions.Compiled | RegexOptions.IgnoreCase); + private static readonly Regex FileNameCleanupRegex = new Regex(@"([- ._])(\1)+", RegexOptions.Compiled); private static readonly Regex TrimSeparatorsRegex = new Regex(@"[- ._]$", RegexOptions.Compiled); @@ -265,6 +268,7 @@ namespace NzbDrone.Core.Organizer tokenHandlers["{Album Title}"] = m => album.Title; tokenHandlers["{Album CleanTitle}"] = m => CleanTitle(album.Title); tokenHandlers["{Album TitleThe}"] = m => TitleThe(album.Title); + tokenHandlers["{Album Type}"] = m => album.AlbumType; if (album.ReleaseDate.HasValue) { tokenHandlers["{Release Year}"] = m => album.ReleaseDate.Value.Year.ToString(); diff --git a/src/NzbDrone.Core/Organizer/FileNameSampleService.cs b/src/NzbDrone.Core/Organizer/FileNameSampleService.cs index 430a777e1..f11d1785c 100644 --- a/src/NzbDrone.Core/Organizer/FileNameSampleService.cs +++ b/src/NzbDrone.Core/Organizer/FileNameSampleService.cs @@ -37,6 +37,7 @@ namespace NzbDrone.Core.Organizer { Title = "The Album Title", ReleaseDate = System.DateTime.Today, + AlbumType = "Album", Media = new List { new Medium diff --git a/src/NzbDrone.Core/Organizer/FileNameValidation.cs b/src/NzbDrone.Core/Organizer/FileNameValidation.cs index fe20efd31..622472787 100644 --- a/src/NzbDrone.Core/Organizer/FileNameValidation.cs +++ b/src/NzbDrone.Core/Organizer/FileNameValidation.cs @@ -24,22 +24,31 @@ namespace NzbDrone.Core.Organizer public static IRuleBuilderOptions ValidAlbumFolderFormat(this IRuleBuilder ruleBuilder) { ruleBuilder.SetValidator(new NotEmptyValidator(null)); - return ruleBuilder.SetValidator(new RegularExpressionValidator(FileNameBuilder.AlbumTitleRegex)).WithMessage("Must contain Album title"); + return ruleBuilder.SetValidator(new RegularExpressionValidator(FileNameBuilder.AlbumTitleRegex)).WithMessage("Must contain Album title") + .SetValidator(new RegularExpressionValidator(FileNameBuilder.ReleaseDateRegex)).WithMessage("Must contain Release year"); } } public class ValidStandardTrackFormatValidator : PropertyValidator { public ValidStandardTrackFormatValidator() - : base("Must contain Album Title and Track numbers OR Original Title") + : base("Must contain Track Title and Track numbers OR Original Title") { } protected override bool IsValid(PropertyValidatorContext context) { + var value = context.PropertyValue as string; - return true; //TODO Add Logic here + if (!(FileNameBuilder.TrackTitleRegex.IsMatch(value) && + FileNameBuilder.TrackRegex.IsMatch(value)) && + !FileNameValidation.OriginalTokenRegex.IsMatch(value)) + { + return false; + } + + return true; } } }