diff --git a/frontend/src/Settings/Profiles/Delay/EditDelayProfileModalContent.js b/frontend/src/Settings/Profiles/Delay/EditDelayProfileModalContent.js index eb9b03ce3..2df953529 100644 --- a/frontend/src/Settings/Profiles/Delay/EditDelayProfileModalContent.js +++ b/frontend/src/Settings/Profiles/Delay/EditDelayProfileModalContent.js @@ -46,6 +46,8 @@ function EditDelayProfileModalContent(props) { usenetDelay, torrentDelay, bypassIfHighestQuality, + bypassIfAboveCustomFormatScore, + minimumCustomFormatScore, tags } = item; @@ -85,7 +87,7 @@ function EditDelayProfileModalContent(props) { { - enableUsenet.value && + enableUsenet.value ? Usenet Delay @@ -97,11 +99,12 @@ function EditDelayProfileModalContent(props) { helpText="Delay in minutes to wait before grabbing a release from Usenet" onChange={onInputChange} /> - + : + null } { - enableTorrent.value && + enableTorrent.value ? Torrent Delay @@ -113,21 +116,48 @@ function EditDelayProfileModalContent(props) { helpText="Delay in minutes to wait before grabbing a torrent" onChange={onInputChange} /> - + : + null } - { - - Bypass if Highest Quality + + Bypass if Highest Quality - - + + + + + Bypass if Above Custom Format Score + + + + + { + bypassIfAboveCustomFormatScore.value ? + + Minimum Custom Format Score + + + : + null } { diff --git a/src/NzbDrone.Core.Test/DecisionEngineTests/RssSync/DelaySpecificationFixture.cs b/src/NzbDrone.Core.Test/DecisionEngineTests/RssSync/DelaySpecificationFixture.cs index 11a6c3bbb..4a8ba8a6d 100644 --- a/src/NzbDrone.Core.Test/DecisionEngineTests/RssSync/DelaySpecificationFixture.cs +++ b/src/NzbDrone.Core.Test/DecisionEngineTests/RssSync/DelaySpecificationFixture.cs @@ -117,17 +117,22 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync [Test] public void should_be_false_when_quality_and_language_is_last_allowed_in_profile_and_bypass_disabled() { + _remoteEpisode.Release.PublishDate = DateTime.UtcNow; _remoteEpisode.ParsedEpisodeInfo.Quality = new QualityModel(Quality.Bluray720p); _remoteEpisode.ParsedEpisodeInfo.Languages = new List { Language.French }; - Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue(); + _delayProfile.UsenetDelay = 720; + + Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse(); } [Test] public void should_be_true_when_quality_and_language_is_last_allowed_in_profile_and_bypass_enabled() { + _delayProfile.UsenetDelay = 720; _delayProfile.BypassIfHighestQuality = true; + _remoteEpisode.Release.PublishDate = DateTime.UtcNow; _remoteEpisode.ParsedEpisodeInfo.Quality = new QualityModel(Quality.Bluray720p); _remoteEpisode.ParsedEpisodeInfo.Languages = new List { Language.French }; @@ -204,5 +209,43 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse(); } + + [Test] + public void should_be_false_when_custom_format_score_is_above_minimum_but_bypass_disabled() + { + _remoteEpisode.Release.PublishDate = DateTime.UtcNow; + _remoteEpisode.CustomFormatScore = 100; + + _delayProfile.UsenetDelay = 720; + _delayProfile.MinimumCustomFormatScore = 50; + + Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse(); + } + + [Test] + public void should_be_false_when_custom_format_score_is_above_minimum_and_bypass_enabled_but_under_minimum() + { + _remoteEpisode.Release.PublishDate = DateTime.UtcNow; + _remoteEpisode.CustomFormatScore = 5; + + _delayProfile.UsenetDelay = 720; + _delayProfile.BypassIfAboveCustomFormatScore = true; + _delayProfile.MinimumCustomFormatScore = 50; + + Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse(); + } + + [Test] + public void should_be_true_when_custom_format_score_is_above_minimum_and_bypass_enabled() + { + _remoteEpisode.Release.PublishDate = DateTime.UtcNow; + _remoteEpisode.CustomFormatScore = 100; + + _delayProfile.UsenetDelay = 720; + _delayProfile.BypassIfAboveCustomFormatScore = true; + _delayProfile.MinimumCustomFormatScore = 50; + + Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue(); + } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/182_add_bypass_to_delay_profile.cs b/src/NzbDrone.Core/Datastore/Migration/182_add_bypass_to_delay_profile.cs new file mode 100644 index 000000000..696140437 --- /dev/null +++ b/src/NzbDrone.Core/Datastore/Migration/182_add_bypass_to_delay_profile.cs @@ -0,0 +1,15 @@ +using FluentMigrator; +using NzbDrone.Core.Datastore.Migration.Framework; + +namespace NzbDrone.Core.Datastore.Migration +{ + [Migration(182)] + 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 e0954f166..07dce7b5c 100644 --- a/src/NzbDrone.Core/DecisionEngine/Specifications/RssSync/DelaySpecification.cs +++ b/src/NzbDrone.Core/DecisionEngine/Specifications/RssSync/DelaySpecification.cs @@ -76,6 +76,19 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync } } + // 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 episodeIds = subject.Episodes.Select(e => e.Id); var oldest = _pendingReleaseService.OldestPendingRelease(subject.Series.Id, episodeIds.ToArray()); diff --git a/src/NzbDrone.Core/Profiles/Delay/DelayProfile.cs b/src/NzbDrone.Core/Profiles/Delay/DelayProfile.cs index 81100d6f5..928d5fdbc 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 @@ namespace NzbDrone.Core.Profiles.Delay 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/Sonarr.Api.V3/Profiles/Delay/DelayProfileResource.cs b/src/Sonarr.Api.V3/Profiles/Delay/DelayProfileResource.cs index f2e2f38a2..355e953ec 100644 --- a/src/Sonarr.Api.V3/Profiles/Delay/DelayProfileResource.cs +++ b/src/Sonarr.Api.V3/Profiles/Delay/DelayProfileResource.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using NzbDrone.Core.Indexers; using NzbDrone.Core.Profiles.Delay; @@ -14,6 +14,8 @@ namespace Sonarr.Api.V3.Profiles.Delay 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 @@ namespace Sonarr.Api.V3.Profiles.Delay 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 @@ namespace Sonarr.Api.V3.Profiles.Delay UsenetDelay = resource.UsenetDelay, TorrentDelay = resource.TorrentDelay, BypassIfHighestQuality = resource.BypassIfHighestQuality, + BypassIfAboveCustomFormatScore = resource.BypassIfAboveCustomFormatScore, + MinimumCustomFormatScore = resource.MinimumCustomFormatScore, Order = resource.Order, Tags = new HashSet(resource.Tags) };