diff --git a/frontend/src/Settings/MediaManagement/Naming/Naming.tsx b/frontend/src/Settings/MediaManagement/Naming/Naming.tsx index 771afd792b..1ed3ab9e5c 100644 --- a/frontend/src/Settings/MediaManagement/Naming/Naming.tsx +++ b/frontend/src/Settings/MediaManagement/Naming/Naming.tsx @@ -249,6 +249,9 @@ function Naming() { translate('MovieFolderFormatHelpText'), ...movieFolderFormatHelpTexts, ]} + helpTextWarning={translate( + 'MovieFolderFormatHelpTextDeprecatedWarning' + )} errors={[ ...movieFolderFormatErrors, ...settings.movieFolderFormat.errors, diff --git a/src/NzbDrone.Core/HealthCheck/Checks/NamingConfigCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/NamingConfigCheck.cs new file mode 100644 index 0000000000..239e9d9e19 --- /dev/null +++ b/src/NzbDrone.Core/HealthCheck/Checks/NamingConfigCheck.cs @@ -0,0 +1,45 @@ +using System.Collections.Generic; +using System.Linq; +using NzbDrone.Common.Extensions; +using NzbDrone.Core.Datastore.Events; +using NzbDrone.Core.Localization; +using NzbDrone.Core.Organizer; + +namespace NzbDrone.Core.HealthCheck.Checks +{ + [CheckOn(typeof(ModelEvent))] + public class NamingConfigCheck : HealthCheckBase, IProvideHealthCheck + { + private readonly INamingConfigService _namingConfigService; + + public NamingConfigCheck(INamingConfigService namingConfigService, ILocalizationService localizationService) + : base(localizationService) + { + _namingConfigService = namingConfigService; + } + + public override HealthCheck Check() + { + var namingConfig = _namingConfigService.GetConfig(); + + if (namingConfig.MovieFolderFormat.IsNotNullOrWhiteSpace()) + { + var match = FileNameValidation.DeprecatedMovieFolderTokensRegex.Matches(namingConfig.MovieFolderFormat); + + if (match.Any()) + { + return new HealthCheck( + GetType(), + HealthCheckResult.Warning, + _localizationService.GetLocalizedString( + "NamingConfigMovieFolderFormatDeprecatedHealthCheckMessage", new Dictionary + { + { "tokens", string.Join(", ", match.Select(c => c.Value).ToArray()) }, + })); + } + } + + return new HealthCheck(GetType()); + } + } +} diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index 8484570c50..5392603c72 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -1134,6 +1134,7 @@ "MovieFilesTotaling": "Movie Files Totaling", "MovieFolderFormat": "Movie Folder Format", "MovieFolderFormatHelpText": "Used when adding a new movie or moving movies via the movie editor", + "MovieFolderFormatHelpTextDeprecatedWarning": "Tokens associated with movie file properties have been deprecated and will no longer be supported in future major versions.", "MovieFolderImportedTooltip": "Movie imported from movie folder", "MovieFootNote": "Optionally control truncation to a maximum number of bytes including ellipsis (`...`). Truncating from the end (e.g. `{Movie Title:30}`) or the beginning (e.g. `{Movie Title:-30}`) are both supported.", "MovieGrabbedTooltip": "Movie grabbed from {indexer} and sent to {downloadClient}", @@ -1173,6 +1174,7 @@ "MustNotContainHelpText": "The release will be rejected if it contains one or more of terms (case insensitive)", "MyComputer": "My Computer", "Name": "Name", + "NamingConfigMovieFolderFormatDeprecatedHealthCheckMessage": "Movie Folder Format must not contain deprecated file related tokens: {tokens}", "NamingSettings": "Naming Settings", "NamingSettingsLoadError": "Unable to load Naming settings", "Negate": "Negate", diff --git a/src/NzbDrone.Core/Organizer/FileNameBuilder.cs b/src/NzbDrone.Core/Organizer/FileNameBuilder.cs index be6e1f43dd..1963705330 100644 --- a/src/NzbDrone.Core/Organizer/FileNameBuilder.cs +++ b/src/NzbDrone.Core/Organizer/FileNameBuilder.cs @@ -172,16 +172,17 @@ public string GetMovieFolder(Movie movie, NamingConfig namingConfig = null) namingConfig = _namingConfigService.GetConfig(); } - var movieFile = movie.MovieFile; - var pattern = namingConfig.MovieFolderFormat; - var tokenHandlers = new Dictionary>(FileNameBuilderTokenEqualityComparer.Instance); var multipleTokens = TitleRegex.Matches(pattern).Count > 1; + var tokenHandlers = new Dictionary>(FileNameBuilderTokenEqualityComparer.Instance); + AddMovieTokens(tokenHandlers, movie); AddReleaseDateTokens(tokenHandlers, movie.Year); AddIdTokens(tokenHandlers, movie); + var movieFile = movie.MovieFile; + if (movie.MovieFile != null) { AddQualityTokens(tokenHandlers, movie, movieFile); diff --git a/src/NzbDrone.Core/Organizer/FileNameSampleService.cs b/src/NzbDrone.Core/Organizer/FileNameSampleService.cs index c8e70e6850..c04d036056 100644 --- a/src/NzbDrone.Core/Organizer/FileNameSampleService.cs +++ b/src/NzbDrone.Core/Organizer/FileNameSampleService.cs @@ -19,14 +19,13 @@ public class FileNameSampleService : IFilenameSampleService private static MovieFile _movieFile; private static Movie _movie; - private static MovieMetadata _movieMetadata; private static List _customFormats; public FileNameSampleService(IBuildFileNames buildFileNames) { _buildFileNames = buildFileNames; - var mediaInfo = new MediaInfoModel() + var mediaInfo = new MediaInfoModel { VideoFormat = "AVC", VideoBitDepth = 10, @@ -50,23 +49,19 @@ public FileNameSampleService(IBuildFileNames buildFileNames) Edition = "Ultimate extended edition", }; - _movieMetadata = new MovieMetadata - { - Title = "The Movie: Title", - OriginalTitle = "The Original Movie Title", - CollectionTitle = "The Movie Collection", - CollectionTmdbId = 123654, - Certification = "R", - Year = 2010, - ImdbId = "tt0066921", - TmdbId = 345691 - }; - _movie = new Movie { - MovieFile = _movieFile, - MovieFileId = 1, - MovieMetadata = _movieMetadata, + MovieMetadata = new MovieMetadata + { + Title = "The Movie: Title", + OriginalTitle = "The Original Movie Title", + CollectionTitle = "The Movie Collection", + CollectionTmdbId = 123654, + Certification = "R", + Year = 2010, + ImdbId = "tt0066921", + TmdbId = 345691 + }, MovieMetadataId = 1 }; diff --git a/src/NzbDrone.Core/Organizer/FileNameValidation.cs b/src/NzbDrone.Core/Organizer/FileNameValidation.cs index fe49d9f317..d4c667dd9a 100644 --- a/src/NzbDrone.Core/Organizer/FileNameValidation.cs +++ b/src/NzbDrone.Core/Organizer/FileNameValidation.cs @@ -9,6 +9,9 @@ namespace NzbDrone.Core.Organizer { public static class FileNameValidation { + public static readonly Regex DeprecatedMovieFolderTokensRegex = new (@"(\{[- ._\[\(]?(?:Original[- ._](?:Title|Filename)|Release[- ._]Group|Edition[- ._]Tags|Quality[- ._](?:Full|Title|Proper|Real)|MediaInfo[- ._](?:Video|VideoCodec|VideoBitDepth|Audio|AudioCodec|AudioChannels|AudioLanguages|AudioLanguagesAll|SubtitleLanguages|SubtitleLanguagesAll|3D|Simple|Full|VideoDynamicRange|VideoDynamicRangeType))[- ._\]\)]?\})", + RegexOptions.Compiled | RegexOptions.IgnoreCase); + internal static readonly Regex OriginalTokenRegex = new (@"(\{Original[- ._](?:Title|Filename)\})", RegexOptions.Compiled | RegexOptions.IgnoreCase); diff --git a/src/NzbDrone.Core/Organizer/NamingConfigRepository.cs b/src/NzbDrone.Core/Organizer/NamingConfigRepository.cs index ca0138b678..fa72f21a93 100644 --- a/src/NzbDrone.Core/Organizer/NamingConfigRepository.cs +++ b/src/NzbDrone.Core/Organizer/NamingConfigRepository.cs @@ -9,6 +9,8 @@ public interface INamingConfigRepository : IBasicRepository public class NamingConfigRepository : BasicRepository, INamingConfigRepository { + protected override bool PublishModelEvents => true; + public NamingConfigRepository(IMainDatabase database, IEventAggregator eventAggregator) : base(database, eventAggregator) {