From 1f8877d192ebc1c5a364401e2d53ebe513ad4f07 Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Fri, 13 Jan 2023 17:40:49 -0800 Subject: [PATCH] New: Add bypass if above Custom Format Score to Delay Profile (cherry picked from commit 4ed4ca4804ce973c1b88c1c4ede8ae00547ac834) --- .../Delay/EditDelayProfileModalContent.js | 60 ++++++++++++++----- .../RssSync/DelaySpecificationFixture.cs | 43 ++++++++++++- .../228_add_bypass_to_delay_profile.cs | 15 +++++ .../RssSync/DelaySpecification.cs | 13 ++++ src/NzbDrone.Core/Localization/Core/en.json | 4 ++ .../Profiles/Delay/DelayProfile.cs | 4 +- .../Profiles/Delay/DelayProfileResource.cs | 6 ++ 7 files changed, 128 insertions(+), 17 deletions(-) create mode 100644 src/NzbDrone.Core/Datastore/Migration/228_add_bypass_to_delay_profile.cs diff --git a/frontend/src/Settings/Profiles/Delay/EditDelayProfileModalContent.js b/frontend/src/Settings/Profiles/Delay/EditDelayProfileModalContent.js index 28d92124b7..6d16e392a5 100644 --- a/frontend/src/Settings/Profiles/Delay/EditDelayProfileModalContent.js +++ b/frontend/src/Settings/Profiles/Delay/EditDelayProfileModalContent.js @@ -67,6 +67,8 @@ function EditDelayProfileModalContent(props) { usenetDelay, torrentDelay, bypassIfHighestQuality, + bypassIfAboveCustomFormatScore, + minimumCustomFormatScore, tags } = item; @@ -108,7 +110,7 @@ function EditDelayProfileModalContent(props) { { - enableUsenet.value && + enableUsenet.value ? {translate('UsenetDelay')} @@ -120,11 +122,12 @@ function EditDelayProfileModalContent(props) { helpText={translate('UsenetDelayHelpText')} onChange={onInputChange} /> - + : + null } { - enableTorrent.value && + enableTorrent.value ? {translate('TorrentDelay')} @@ -136,21 +139,48 @@ function EditDelayProfileModalContent(props) { helpText={translate('TorrentDelayHelpText')} onChange={onInputChange} /> - + : + null } - { - - {translate('BypassDelayIfHighestQuality')} + + {translate('BypassDelayIfHighestQuality')} - - + + + + + {translate('BypassDelayIfAboveCustomFormatScore')} + + + + + { + bypassIfAboveCustomFormatScore.value ? + + {translate('BypassDelayIfAboveCustomFormatScoreMinimumScore')} + + + : + null } { diff --git a/src/NzbDrone.Core.Test/DecisionEngineTests/RssSync/DelaySpecificationFixture.cs b/src/NzbDrone.Core.Test/DecisionEngineTests/RssSync/DelaySpecificationFixture.cs index a7fd1a0e67..71a6654e80 100644 --- a/src/NzbDrone.Core.Test/DecisionEngineTests/RssSync/DelaySpecificationFixture.cs +++ b/src/NzbDrone.Core.Test/DecisionEngineTests/RssSync/DelaySpecificationFixture.cs @@ -106,9 +106,10 @@ public void should_be_true_when_profile_does_not_have_a_delay() [Test] public void should_be_false_when_quality_is_last_allowed_in_profile_and_bypass_disabled() { + _remoteMovie.Release.PublishDate = DateTime.UtcNow; _remoteMovie.ParsedMovieInfo.Quality = new QualityModel(Quality.Bluray720p); - _remoteMovie.Release.PublishDate = DateTime.UtcNow; + _delayProfile.UsenetDelay = 720; Subject.IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeFalse(); } @@ -116,8 +117,10 @@ public void should_be_false_when_quality_is_last_allowed_in_profile_and_bypass_d [Test] public void should_be_true_when_quality_is_last_allowed_in_profile_and_bypass_enabled() { + _delayProfile.UsenetDelay = 720; _delayProfile.BypassIfHighestQuality = true; + _remoteMovie.Release.PublishDate = DateTime.UtcNow; _remoteMovie.ParsedMovieInfo.Quality = new QualityModel(Quality.Bluray720p); Subject.IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeTrue(); @@ -193,5 +196,43 @@ public void should_be_false_when_release_is_proper_for_existing_movie_of_differe Subject.IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeFalse(); } + + [Test] + public void should_be_false_when_custom_format_score_is_above_minimum_but_bypass_disabled() + { + _remoteMovie.Release.PublishDate = DateTime.UtcNow; + _remoteMovie.CustomFormatScore = 100; + + _delayProfile.UsenetDelay = 720; + _delayProfile.MinimumCustomFormatScore = 50; + + Subject.IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeFalse(); + } + + [Test] + public void should_be_false_when_custom_format_score_is_above_minimum_and_bypass_enabled_but_under_minimum() + { + _remoteMovie.Release.PublishDate = DateTime.UtcNow; + _remoteMovie.CustomFormatScore = 5; + + _delayProfile.UsenetDelay = 720; + _delayProfile.BypassIfAboveCustomFormatScore = true; + _delayProfile.MinimumCustomFormatScore = 50; + + Subject.IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeFalse(); + } + + [Test] + public void should_be_true_when_custom_format_score_is_above_minimum_and_bypass_enabled() + { + _remoteMovie.Release.PublishDate = DateTime.UtcNow; + _remoteMovie.CustomFormatScore = 100; + + _delayProfile.UsenetDelay = 720; + _delayProfile.BypassIfAboveCustomFormatScore = true; + _delayProfile.MinimumCustomFormatScore = 50; + + Subject.IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeTrue(); + } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/228_add_bypass_to_delay_profile.cs b/src/NzbDrone.Core/Datastore/Migration/228_add_bypass_to_delay_profile.cs new file mode 100644 index 0000000000..8562e50ab3 --- /dev/null +++ b/src/NzbDrone.Core/Datastore/Migration/228_add_bypass_to_delay_profile.cs @@ -0,0 +1,15 @@ +using FluentMigrator; +using NzbDrone.Core.Datastore.Migration.Framework; + +namespace NzbDrone.Core.Datastore.Migration +{ + [Migration(228)] + public class add_custom_format_score_bypass_to_delay_profile : NzbDroneMigrationBase + { + protected override void MainDbUpgrade() + { + Alter.Table("DelayProfiles").AddColumn("BypassIfAboveCustomFormatScore").AsBoolean().WithDefaultValue(false); + Alter.Table("DelayProfiles").AddColumn("MinimumCustomFormatScore").AsInt32().Nullable(); + } + } +} diff --git a/src/NzbDrone.Core/DecisionEngine/Specifications/RssSync/DelaySpecification.cs b/src/NzbDrone.Core/DecisionEngine/Specifications/RssSync/DelaySpecification.cs index b649498797..e43f746696 100644 --- a/src/NzbDrone.Core/DecisionEngine/Specifications/RssSync/DelaySpecification.cs +++ b/src/NzbDrone.Core/DecisionEngine/Specifications/RssSync/DelaySpecification.cs @@ -89,6 +89,19 @@ public virtual Decision IsSatisfiedBy(RemoteMovie subject, SearchCriteriaBase se } } + // If quality meets or exceeds the best allowed quality in the profile accept it immediately + if (delayProfile.BypassIfAboveCustomFormatScore) + { + var score = subject.CustomFormatScore; + var minimum = delayProfile.MinimumCustomFormatScore; + + if (score >= minimum && isPreferredProtocol) + { + _logger.Debug("Custom format score ({0}) meets minimum ({1}) for preferred protocol, will not delay", score, minimum); + return Decision.Accept(); + } + } + var oldest = _pendingReleaseService.OldestPendingRelease(subject.Movie.Id); if (oldest != null && oldest.Release.AgeMinutes > delay) diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index f18d92681b..fd43f7cfb9 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -107,6 +107,10 @@ "BranchUpdate": "Branch to use to update Radarr", "BranchUpdateMechanism": "Branch used by external update mechanism", "BuiltIn": "Built In", + "BypassDelayIfAboveCustomFormatScore": "Bypass if Above Custom Format Score", + "BypassDelayIfAboveCustomFormatScoreHelpText": "Enable bypass when release has a score higher than the configured minimum custom format score", + "BypassDelayIfAboveCustomFormatScoreMinimumScore": "Minimum Custom Format Score", + "BypassDelayIfAboveCustomFormatScoreMinimumScoreHelpText": "Minimum Custom Format Score required to bypass delay for the preferred protocol", "BypassDelayIfHighestQuality": "Bypass if Highest Quality", "BypassDelayIfHighestQualityHelpText": "Bypass delay when release has the highest enabled quality in the quality profile with the preferred protocol", "BypassProxyForLocalAddresses": "Bypass Proxy for Local Addresses", diff --git a/src/NzbDrone.Core/Profiles/Delay/DelayProfile.cs b/src/NzbDrone.Core/Profiles/Delay/DelayProfile.cs index 81100d6f59..928d5fdbc0 100644 --- a/src/NzbDrone.Core/Profiles/Delay/DelayProfile.cs +++ b/src/NzbDrone.Core/Profiles/Delay/DelayProfile.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using NzbDrone.Core.Datastore; using NzbDrone.Core.Indexers; @@ -13,6 +13,8 @@ public class DelayProfile : ModelBase public int TorrentDelay { get; set; } public int Order { get; set; } public bool BypassIfHighestQuality { get; set; } + public bool BypassIfAboveCustomFormatScore { get; set; } + public int MinimumCustomFormatScore { get; set; } public HashSet Tags { get; set; } public DelayProfile() diff --git a/src/Radarr.Api.V3/Profiles/Delay/DelayProfileResource.cs b/src/Radarr.Api.V3/Profiles/Delay/DelayProfileResource.cs index 7579e0c817..12c183221c 100644 --- a/src/Radarr.Api.V3/Profiles/Delay/DelayProfileResource.cs +++ b/src/Radarr.Api.V3/Profiles/Delay/DelayProfileResource.cs @@ -14,6 +14,8 @@ public class DelayProfileResource : RestResource public int UsenetDelay { get; set; } public int TorrentDelay { get; set; } public bool BypassIfHighestQuality { get; set; } + public bool BypassIfAboveCustomFormatScore { get; set; } + public int MinimumCustomFormatScore { get; set; } public int Order { get; set; } public HashSet Tags { get; set; } } @@ -37,6 +39,8 @@ public static DelayProfileResource ToResource(this DelayProfile model) UsenetDelay = model.UsenetDelay, TorrentDelay = model.TorrentDelay, BypassIfHighestQuality = model.BypassIfHighestQuality, + BypassIfAboveCustomFormatScore = model.BypassIfAboveCustomFormatScore, + MinimumCustomFormatScore = model.MinimumCustomFormatScore, Order = model.Order, Tags = new HashSet(model.Tags) }; @@ -59,6 +63,8 @@ public static DelayProfile ToModel(this DelayProfileResource resource) UsenetDelay = resource.UsenetDelay, TorrentDelay = resource.TorrentDelay, BypassIfHighestQuality = resource.BypassIfHighestQuality, + BypassIfAboveCustomFormatScore = resource.BypassIfAboveCustomFormatScore, + MinimumCustomFormatScore = resource.MinimumCustomFormatScore, Order = resource.Order, Tags = new HashSet(resource.Tags) };