From 33b44a8a53ba69bf59c3e42e66ec98bcb609c04a Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Fri, 23 Feb 2024 21:03:42 -0800 Subject: [PATCH] New: Option to sync season monitoring state when importing from another Sonarr instance Closes #6542 --- .../ImportLists/ImportListSyncService.cs | 5 ++++- .../ImportLists/Sonarr/SonarrAPIResource.cs | 7 +++++++ .../ImportLists/Sonarr/SonarrImport.cs | 16 ++++++++++++++-- .../ImportLists/Sonarr/SonarrSettings.cs | 13 ++++++++----- src/NzbDrone.Core/Localization/Core/en.json | 2 ++ .../Parser/Model/ImportListItemInfo.cs | 8 ++++++++ src/NzbDrone.Core/Tv/EpisodeMonitoredService.cs | 6 ++++++ src/NzbDrone.Core/Tv/MonitoringOptions.cs | 3 ++- 8 files changed, 51 insertions(+), 9 deletions(-) diff --git a/src/NzbDrone.Core/ImportLists/ImportListSyncService.cs b/src/NzbDrone.Core/ImportLists/ImportListSyncService.cs index 1c4c9ea7a..2c51ea6c0 100644 --- a/src/NzbDrone.Core/ImportLists/ImportListSyncService.cs +++ b/src/NzbDrone.Core/ImportLists/ImportListSyncService.cs @@ -222,11 +222,14 @@ namespace NzbDrone.Core.ImportLists QualityProfileId = importList.QualityProfileId, SeriesType = importList.SeriesType, SeasonFolder = importList.SeasonFolder, + Seasons = item.Seasons, Tags = importList.Tags, AddOptions = new AddSeriesOptions { SearchForMissingEpisodes = importList.SearchForMissingEpisodes, - Monitor = importList.ShouldMonitor + + // If seasons are provided use them for syncing monitored status, otherwise use the list setting. + Monitor = item.Seasons.Any() ? MonitorTypes.Skip : importList.ShouldMonitor } }); } diff --git a/src/NzbDrone.Core/ImportLists/Sonarr/SonarrAPIResource.cs b/src/NzbDrone.Core/ImportLists/Sonarr/SonarrAPIResource.cs index 884d1247c..363964626 100644 --- a/src/NzbDrone.Core/ImportLists/Sonarr/SonarrAPIResource.cs +++ b/src/NzbDrone.Core/ImportLists/Sonarr/SonarrAPIResource.cs @@ -15,6 +15,7 @@ namespace NzbDrone.Core.ImportLists.Sonarr public int QualityProfileId { get; set; } public int LanguageProfileId { get; set; } public string RootFolderPath { get; set; } + public List Seasons { get; set; } public HashSet Tags { get; set; } } @@ -35,4 +36,10 @@ namespace NzbDrone.Core.ImportLists.Sonarr public string Path { get; set; } public int Id { get; set; } } + + public class SonarrSeason + { + public int SeasonNumber { get; set; } + public bool Monitored { get; set; } + } } diff --git a/src/NzbDrone.Core/ImportLists/Sonarr/SonarrImport.cs b/src/NzbDrone.Core/ImportLists/Sonarr/SonarrImport.cs index 3a35ecf6d..d06b294f2 100644 --- a/src/NzbDrone.Core/ImportLists/Sonarr/SonarrImport.cs +++ b/src/NzbDrone.Core/ImportLists/Sonarr/SonarrImport.cs @@ -8,6 +8,7 @@ using NzbDrone.Core.Configuration; using NzbDrone.Core.Localization; using NzbDrone.Core.Parser; using NzbDrone.Core.Parser.Model; +using NzbDrone.Core.Tv; using NzbDrone.Core.Validation; namespace NzbDrone.Core.ImportLists.Sonarr @@ -61,11 +62,22 @@ namespace NzbDrone.Core.ImportLists.Sonarr continue; } - series.Add(new ImportListItemInfo + var info = new ImportListItemInfo { TvdbId = item.TvdbId, Title = item.Title - }); + }; + + if (Settings.SyncSeasonMonitoring) + { + info.Seasons = item.Seasons.Select(s => new Season + { + SeasonNumber = s.SeasonNumber, + Monitored = s.Monitored + }).ToList(); + } + + series.Add(info); } _importListStatusService.RecordSuccess(Definition.Id); diff --git a/src/NzbDrone.Core/ImportLists/Sonarr/SonarrSettings.cs b/src/NzbDrone.Core/ImportLists/Sonarr/SonarrSettings.cs index 8037a4efa..77772f003 100644 --- a/src/NzbDrone.Core/ImportLists/Sonarr/SonarrSettings.cs +++ b/src/NzbDrone.Core/ImportLists/Sonarr/SonarrSettings.cs @@ -35,12 +35,11 @@ namespace NzbDrone.Core.ImportLists.Sonarr [FieldDefinition(1, Label = "ApiKey", HelpText = "ImportListsSonarrSettingsApiKeyHelpText")] public string ApiKey { get; set; } - [FieldDefinition(2, Type = FieldType.Select, SelectOptionsProviderAction = "getProfiles", Label = "QualityProfiles", HelpText = "ImportListsSonarrSettingsQualityProfilesHelpText")] - public IEnumerable ProfileIds { get; set; } + [FieldDefinition(2, Label = "ImportListsSonarrSettingsSyncSeasonMonitoring", HelpText = "ImportListsSonarrSettingsSyncSeasonMonitoringHelpText", Type = FieldType.Checkbox)] + public bool SyncSeasonMonitoring { get; set; } - // TODO: Remove this eventually, no translation added as deprecated - [FieldDefinition(3, Type = FieldType.Select, SelectOptionsProviderAction = "getLanguageProfiles", Label = "Language Profiles", HelpText = "Language Profiles from the source instance to import from")] - public IEnumerable LanguageProfileIds { get; set; } + [FieldDefinition(3, Type = FieldType.Select, SelectOptionsProviderAction = "getProfiles", Label = "QualityProfiles", HelpText = "ImportListsSonarrSettingsQualityProfilesHelpText")] + public IEnumerable ProfileIds { get; set; } [FieldDefinition(4, Type = FieldType.Select, SelectOptionsProviderAction = "getTags", Label = "Tags", HelpText = "ImportListsSonarrSettingsTagsHelpText")] public IEnumerable TagIds { get; set; } @@ -48,6 +47,10 @@ namespace NzbDrone.Core.ImportLists.Sonarr [FieldDefinition(5, Type = FieldType.Select, SelectOptionsProviderAction = "getRootFolders", Label = "RootFolders", HelpText = "ImportListsSonarrSettingsRootFoldersHelpText")] public IEnumerable RootFolderPaths { get; set; } + // TODO: Remove this eventually, no translation added as deprecated + [FieldDefinition(6, Type = FieldType.Select, SelectOptionsProviderAction = "getLanguageProfiles", Label = "Language Profiles", HelpText = "Language Profiles from the source instance to import from")] + public IEnumerable LanguageProfileIds { get; set; } + public NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index 3f2cb75ee..8bc21c8e8 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -851,6 +851,8 @@ "ImportListsSimklSettingsUserListTypePlanToWatch": "Plan To Watch", "ImportListsSimklSettingsUserListTypeWatching": "Watching", "ImportListsSonarrSettingsApiKeyHelpText": "API Key of the {appName} instance to import from", + "ImportListsSonarrSettingsSyncSeasonMonitoring": "Sync Season Monitoring", + "ImportListsSonarrSettingsSyncSeasonMonitoringHelpText": "Sync season monitoring from {appName} instance, if enabled 'Monitor' will be ignored", "ImportListsSonarrSettingsFullUrl": "Full URL", "ImportListsSonarrSettingsFullUrlHelpText": "URL, including port, of the {appName} instance to import from", "ImportListsSonarrSettingsQualityProfilesHelpText": "Quality Profiles from the source instance to import from", diff --git a/src/NzbDrone.Core/Parser/Model/ImportListItemInfo.cs b/src/NzbDrone.Core/Parser/Model/ImportListItemInfo.cs index 8d0e37534..34f1c3bce 100644 --- a/src/NzbDrone.Core/Parser/Model/ImportListItemInfo.cs +++ b/src/NzbDrone.Core/Parser/Model/ImportListItemInfo.cs @@ -1,10 +1,17 @@ using System; +using System.Collections.Generic; using NzbDrone.Core.Datastore; +using NzbDrone.Core.Tv; namespace NzbDrone.Core.Parser.Model { public class ImportListItemInfo : ModelBase { + public ImportListItemInfo() + { + Seasons = new List(); + } + public int ImportListId { get; set; } public string ImportList { get; set; } public string Title { get; set; } @@ -15,6 +22,7 @@ namespace NzbDrone.Core.Parser.Model public int MalId { get; set; } public int AniListId { get; set; } public DateTime ReleaseDate { get; set; } + public List Seasons { get; set; } public override string ToString() { diff --git a/src/NzbDrone.Core/Tv/EpisodeMonitoredService.cs b/src/NzbDrone.Core/Tv/EpisodeMonitoredService.cs index 3f2acf9bf..c28c1d522 100644 --- a/src/NzbDrone.Core/Tv/EpisodeMonitoredService.cs +++ b/src/NzbDrone.Core/Tv/EpisodeMonitoredService.cs @@ -40,6 +40,12 @@ namespace NzbDrone.Core.Tv return; } + // Skip episode level monitoring and use season information when series was added + if (monitoringOptions.Monitor == MonitorTypes.Skip) + { + return; + } + var firstSeason = series.Seasons.Select(s => s.SeasonNumber).Where(s => s > 0).MinOrDefault(); var lastSeason = series.Seasons.Select(s => s.SeasonNumber).MaxOrDefault(); var episodes = _episodeService.GetEpisodeBySeries(series.Id); diff --git a/src/NzbDrone.Core/Tv/MonitoringOptions.cs b/src/NzbDrone.Core/Tv/MonitoringOptions.cs index b49a5ee6a..82983a26c 100644 --- a/src/NzbDrone.Core/Tv/MonitoringOptions.cs +++ b/src/NzbDrone.Core/Tv/MonitoringOptions.cs @@ -27,7 +27,8 @@ namespace NzbDrone.Core.Tv Recent, MonitorSpecials, UnmonitorSpecials, - None + None, + Skip } public enum NewItemMonitorTypes