From ebe23104d4b29a3c900a982fb84e75c27ed531ab Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Fri, 6 Dec 2024 20:27:11 -0800 Subject: [PATCH] Fixed: Custom Format score bypassing upgrades not being allowed --- .../UpgradeDiskSpecificationFixture.cs | 38 +++++++++++++++++++ .../UpgradeSpecificationFixture.cs | 4 +- .../DecisionEngine/DownloadRejectionReason.cs | 4 +- .../Specifications/QueueSpecification.cs | 12 +----- .../RssSync/HistorySpecification.cs | 3 ++ .../Specifications/UpgradableSpecification.cs | 9 ++++- .../UpgradeDiskSpecification.cs | 3 ++ .../DecisionEngine/UpgradeableRejectReason.cs | 3 +- 8 files changed, 61 insertions(+), 15 deletions(-) diff --git a/src/NzbDrone.Core.Test/DecisionEngineTests/UpgradeDiskSpecificationFixture.cs b/src/NzbDrone.Core.Test/DecisionEngineTests/UpgradeDiskSpecificationFixture.cs index 658810bbc..c560368dc 100644 --- a/src/NzbDrone.Core.Test/DecisionEngineTests/UpgradeDiskSpecificationFixture.cs +++ b/src/NzbDrone.Core.Test/DecisionEngineTests/UpgradeDiskSpecificationFixture.cs @@ -5,6 +5,7 @@ using Moq; using NUnit.Framework; using NzbDrone.Common.Serializer; +using NzbDrone.Core.Configuration; using NzbDrone.Core.CustomFormats; using NzbDrone.Core.DecisionEngine.Specifications; using NzbDrone.Core.Languages; @@ -399,5 +400,42 @@ public void should_return_false_if_quality_profile_does_not_allow_upgrades_but_f Subject.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeFalse(); } + + [Test] + public void should_return_false_if_quality_profile_does_not_allow_upgrades_but_format_cutoff_is_above_current_score_and_is_revision_upgrade() + { + var customFormat = new CustomFormat("My Format", new ResolutionSpecification { Value = (int)Resolution.R1080p }) { Id = 1 }; + + Mocker.GetMock() + .SetupGet(s => s.DownloadPropersAndRepacks) + .Returns(ProperDownloadTypes.DoNotPrefer); + + GivenProfile(new QualityProfile + { + Cutoff = Quality.SDTV.Id, + MinFormatScore = 0, + CutoffFormatScore = 10000, + Items = Qualities.QualityFixture.GetDefaultQualities(), + FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems("My Format"), + UpgradeAllowed = false + }); + + _parseResultSingle.Series.QualityProfile.Value.FormatItems = new List + { + new ProfileFormatItem + { + Format = customFormat, + Score = 50 + } + }; + + GivenFileQuality(new QualityModel(Quality.WEBDL1080p, new Revision(version: 1))); + GivenNewQuality(new QualityModel(Quality.WEBDL1080p, new Revision(version: 2))); + + GivenOldCustomFormats(new List()); + GivenNewCustomFormats(new List { customFormat }); + + Subject.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeFalse(); + } } } diff --git a/src/NzbDrone.Core.Test/DecisionEngineTests/UpgradeSpecificationFixture.cs b/src/NzbDrone.Core.Test/DecisionEngineTests/UpgradeSpecificationFixture.cs index e3a7a71ee..e04d603da 100644 --- a/src/NzbDrone.Core.Test/DecisionEngineTests/UpgradeSpecificationFixture.cs +++ b/src/NzbDrone.Core.Test/DecisionEngineTests/UpgradeSpecificationFixture.cs @@ -90,7 +90,7 @@ public void should_return_false_if_proper_and_autoDownloadPropers_is_do_not_pref new List(), new QualityModel(Quality.DVD, new Revision(version: 2)), new List()) - .Should().Be(UpgradeableRejectReason.CustomFormatScore); + .Should().Be(UpgradeableRejectReason.UpgradesNotAllowed); } [Test] @@ -107,7 +107,7 @@ public void should_return_false_if_release_and_existing_file_are_the_same() new List(), new QualityModel(Quality.HDTV720p, new Revision(version: 1)), new List()) - .Should().Be(UpgradeableRejectReason.CustomFormatScore); + .Should().Be(UpgradeableRejectReason.UpgradesNotAllowed); } [Test] diff --git a/src/NzbDrone.Core/DecisionEngine/DownloadRejectionReason.cs b/src/NzbDrone.Core/DecisionEngine/DownloadRejectionReason.cs index 72e83b93f..09b21dcd2 100644 --- a/src/NzbDrone.Core/DecisionEngine/DownloadRejectionReason.cs +++ b/src/NzbDrone.Core/DecisionEngine/DownloadRejectionReason.cs @@ -20,6 +20,7 @@ public enum DownloadRejectionReason HistoryCustomFormatCutoffMet, HistoryCustomFormatScore, HistoryCustomFormatScoreIncrement, + HistoryUpgradesNotAllowed, NoMatchingTag, PropersDisabled, ProperForOldFile, @@ -53,7 +54,7 @@ public enum DownloadRejectionReason QueueCustomFormatCutoffMet, QueueCustomFormatScore, QueueCustomFormatScoreIncrement, - QueueNoUpgrades, + QueueUpgradesNotAllowed, QueuePropersDisabled, Raw, MustContainMissing, @@ -72,4 +73,5 @@ public enum DownloadRejectionReason DiskCustomFormatCutoffMet, DiskCustomFormatScore, DiskCustomFormatScoreIncrement, + DiskUpgradesNotAllowed } diff --git a/src/NzbDrone.Core/DecisionEngine/Specifications/QueueSpecification.cs b/src/NzbDrone.Core/DecisionEngine/Specifications/QueueSpecification.cs index 66160260e..a51cfe3bf 100644 --- a/src/NzbDrone.Core/DecisionEngine/Specifications/QueueSpecification.cs +++ b/src/NzbDrone.Core/DecisionEngine/Specifications/QueueSpecification.cs @@ -95,17 +95,9 @@ public DownloadSpecDecision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaB case UpgradeableRejectReason.MinCustomFormatScore: return DownloadSpecDecision.Reject(DownloadRejectionReason.QueueCustomFormatScoreIncrement, "Release in queue has Custom Format score within Custom Format score increment: {0}", qualityProfile.MinUpgradeFormatScore); - } - _logger.Debug("Checking if profiles allow upgrading. Queued: {0}", remoteEpisode.ParsedEpisodeInfo.Quality); - - if (!_upgradableSpecification.IsUpgradeAllowed(subject.Series.QualityProfile, - remoteEpisode.ParsedEpisodeInfo.Quality, - queuedItemCustomFormats, - subject.ParsedEpisodeInfo.Quality, - subject.CustomFormats)) - { - return DownloadSpecDecision.Reject(DownloadRejectionReason.QueueNoUpgrades, "Another release is queued and the Quality profile does not allow upgrades"); + case UpgradeableRejectReason.UpgradesNotAllowed: + return DownloadSpecDecision.Reject(DownloadRejectionReason.QueueUpgradesNotAllowed, "Release in queue and Quality Profile '{0}' does not allow upgrades", qualityProfile.Name); } if (_upgradableSpecification.IsRevisionUpgrade(remoteEpisode.ParsedEpisodeInfo.Quality, subject.ParsedEpisodeInfo.Quality)) diff --git a/src/NzbDrone.Core/DecisionEngine/Specifications/RssSync/HistorySpecification.cs b/src/NzbDrone.Core/DecisionEngine/Specifications/RssSync/HistorySpecification.cs index f063c5e28..a8ce354f7 100644 --- a/src/NzbDrone.Core/DecisionEngine/Specifications/RssSync/HistorySpecification.cs +++ b/src/NzbDrone.Core/DecisionEngine/Specifications/RssSync/HistorySpecification.cs @@ -111,6 +111,9 @@ public virtual DownloadSpecDecision IsSatisfiedBy(RemoteEpisode subject, SearchC case UpgradeableRejectReason.MinCustomFormatScore: return DownloadSpecDecision.Reject(DownloadRejectionReason.HistoryCustomFormatScoreIncrement, "{0} grab event in history has Custom Format score within Custom Format score increment: {1}", rejectionSubject, qualityProfile.MinUpgradeFormatScore); + + case UpgradeableRejectReason.UpgradesNotAllowed: + return DownloadSpecDecision.Reject(DownloadRejectionReason.HistoryUpgradesNotAllowed, "{0} grab event in history and Quality Profile '{1}' does not allow upgrades", rejectionSubject, qualityProfile.Name); } } } diff --git a/src/NzbDrone.Core/DecisionEngine/Specifications/UpgradableSpecification.cs b/src/NzbDrone.Core/DecisionEngine/Specifications/UpgradableSpecification.cs index ceaf3815c..f2b1028c2 100644 --- a/src/NzbDrone.Core/DecisionEngine/Specifications/UpgradableSpecification.cs +++ b/src/NzbDrone.Core/DecisionEngine/Specifications/UpgradableSpecification.cs @@ -57,6 +57,13 @@ public UpgradeableRejectReason IsUpgradable(QualityProfile qualityProfile, Quali return UpgradeableRejectReason.None; } + if (!qualityProfile.UpgradeAllowed) + { + _logger.Debug("Quality profile '{0}' does not allow upgrading. Skipping.", qualityProfile.Name); + + return UpgradeableRejectReason.UpgradesNotAllowed; + } + // Reject unless the user does not prefer propers/repacks and it's a revision downgrade. if (downloadPropersAndRepacks != ProperDownloadTypes.DoNotPrefer && qualityRevisionCompare < 0) @@ -86,7 +93,7 @@ public UpgradeableRejectReason IsUpgradable(QualityProfile qualityProfile, Quali return UpgradeableRejectReason.CustomFormatScore; } - if (qualityProfile.UpgradeAllowed && currentFormatScore >= qualityProfile.CutoffFormatScore) + if (currentFormatScore >= qualityProfile.CutoffFormatScore) { _logger.Debug("Existing item meets cut-off for custom formats, skipping. Existing: [{0}] ({1}). Cutoff score: {2}", currentCustomFormats.ConcatToString(), diff --git a/src/NzbDrone.Core/DecisionEngine/Specifications/UpgradeDiskSpecification.cs b/src/NzbDrone.Core/DecisionEngine/Specifications/UpgradeDiskSpecification.cs index 0185d4d87..87937b762 100644 --- a/src/NzbDrone.Core/DecisionEngine/Specifications/UpgradeDiskSpecification.cs +++ b/src/NzbDrone.Core/DecisionEngine/Specifications/UpgradeDiskSpecification.cs @@ -81,6 +81,9 @@ public virtual DownloadSpecDecision IsSatisfiedBy(RemoteEpisode subject, SearchC case UpgradeableRejectReason.MinCustomFormatScore: return DownloadSpecDecision.Reject(DownloadRejectionReason.DiskCustomFormatScoreIncrement, "Existing file on disk has Custom Format score within Custom Format score increment: {0}", qualityProfile.MinUpgradeFormatScore); + + case UpgradeableRejectReason.UpgradesNotAllowed: + return DownloadSpecDecision.Reject(DownloadRejectionReason.DiskUpgradesNotAllowed, "Existing file on disk and Quality Profile '{0}' does not allow upgrades", qualityProfile.Name); } } diff --git a/src/NzbDrone.Core/DecisionEngine/UpgradeableRejectReason.cs b/src/NzbDrone.Core/DecisionEngine/UpgradeableRejectReason.cs index 2b1b1cfe9..ccf696d82 100644 --- a/src/NzbDrone.Core/DecisionEngine/UpgradeableRejectReason.cs +++ b/src/NzbDrone.Core/DecisionEngine/UpgradeableRejectReason.cs @@ -8,6 +8,7 @@ public enum UpgradeableRejectReason QualityCutoff, CustomFormatScore, CustomFormatCutoff, - MinCustomFormatScore + MinCustomFormatScore, + UpgradesNotAllowed } }