mirror of
https://github.com/Readarr/Readarr.git
synced 2026-04-24 22:35:39 -04:00
New: Custom Formats
Co-Authored-By: ta264 <ta264@users.noreply.github.com>
This commit is contained in:
@@ -28,7 +28,7 @@ namespace NzbDrone.Core.DecisionEngine
|
||||
var comparers = new List<CompareDelegate>
|
||||
{
|
||||
CompareQuality,
|
||||
ComparePreferredWordScore,
|
||||
CompareCustomFormatScore,
|
||||
CompareProtocol,
|
||||
CompareIndexerPriority,
|
||||
ComparePeersIfTorrent,
|
||||
@@ -76,9 +76,9 @@ namespace NzbDrone.Core.DecisionEngine
|
||||
CompareBy(x.RemoteBook, y.RemoteBook, remoteBook => remoteBook.ParsedBookInfo.Quality.Revision));
|
||||
}
|
||||
|
||||
private int ComparePreferredWordScore(DownloadDecision x, DownloadDecision y)
|
||||
private int CompareCustomFormatScore(DownloadDecision x, DownloadDecision y)
|
||||
{
|
||||
return CompareBy(x.RemoteBook, y.RemoteBook, remoteBook => remoteBook.PreferredWordScore);
|
||||
return CompareBy(x.RemoteBook, y.RemoteBook, remoteBook => remoteBook.CustomFormatScore);
|
||||
}
|
||||
|
||||
private int CompareProtocol(DownloadDecision x, DownloadDecision y)
|
||||
|
||||
@@ -5,6 +5,7 @@ using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Common.Instrumentation.Extensions;
|
||||
using NzbDrone.Common.Serializer;
|
||||
using NzbDrone.Core.CustomFormats;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
using NzbDrone.Core.Download.Aggregation;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
@@ -23,17 +24,20 @@ namespace NzbDrone.Core.DecisionEngine
|
||||
public class DownloadDecisionMaker : IMakeDownloadDecision
|
||||
{
|
||||
private readonly IEnumerable<IDecisionEngineSpecification> _specifications;
|
||||
private readonly ICustomFormatCalculationService _formatCalculator;
|
||||
private readonly IParsingService _parsingService;
|
||||
private readonly IRemoteBookAggregationService _aggregationService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public DownloadDecisionMaker(IEnumerable<IDecisionEngineSpecification> specifications,
|
||||
IParsingService parsingService,
|
||||
ICustomFormatCalculationService formatService,
|
||||
IRemoteBookAggregationService aggregationService,
|
||||
Logger logger)
|
||||
{
|
||||
_specifications = specifications;
|
||||
_parsingService = parsingService;
|
||||
_formatCalculator = formatService;
|
||||
_aggregationService = aggregationService;
|
||||
_logger = logger;
|
||||
}
|
||||
@@ -89,6 +93,9 @@ namespace NzbDrone.Core.DecisionEngine
|
||||
if (parsedBookInfo != null && !parsedBookInfo.AuthorName.IsNullOrWhiteSpace())
|
||||
{
|
||||
var remoteBook = _parsingService.Map(parsedBookInfo, searchCriteria);
|
||||
remoteBook.Release = report;
|
||||
|
||||
_aggregationService.Augment(remoteBook);
|
||||
|
||||
// try parsing again using the search criteria, in case it parsed but parsed incorrectly
|
||||
if ((remoteBook.Author == null || remoteBook.Books.Empty()) && searchCriteria != null)
|
||||
@@ -134,6 +141,10 @@ namespace NzbDrone.Core.DecisionEngine
|
||||
else
|
||||
{
|
||||
_aggregationService.Augment(remoteBook);
|
||||
|
||||
remoteBook.CustomFormats = _formatCalculator.ParseCustomFormat(remoteBook, remoteBook.Release.Size);
|
||||
remoteBook.CustomFormatScore = remoteBook?.Author?.QualityProfile?.Value.CalculateCustomFormatScore(remoteBook.CustomFormats) ?? 0;
|
||||
|
||||
remoteBook.DownloadAllowed = remoteBook.Books.Any();
|
||||
decision = GetDecisionForReport(remoteBook, searchCriteria);
|
||||
}
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
{
|
||||
public class CustomFormatAllowedbyProfileSpecification : IDecisionEngineSpecification
|
||||
{
|
||||
public SpecificationPriority Priority => SpecificationPriority.Default;
|
||||
public RejectionType Type => RejectionType.Permanent;
|
||||
|
||||
public virtual Decision IsSatisfiedBy(RemoteBook subject, SearchCriteriaBase searchCriteria)
|
||||
{
|
||||
var minScore = subject.Author.QualityProfile.Value.MinFormatScore;
|
||||
var score = subject.CustomFormatScore;
|
||||
|
||||
if (score < minScore)
|
||||
{
|
||||
return Decision.Reject("Custom Formats {0} have score {1} below Author profile minimum {2}", subject.CustomFormats.ConcatToString(), score, minScore);
|
||||
}
|
||||
|
||||
return Decision.Accept();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.CustomFormats;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Profiles.Releases;
|
||||
@@ -13,14 +14,14 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
{
|
||||
private readonly UpgradableSpecification _upgradableSpecification;
|
||||
private readonly Logger _logger;
|
||||
private readonly IPreferredWordService _preferredWordServiceCalculator;
|
||||
private readonly ICustomFormatCalculationService _formatService;
|
||||
|
||||
public CutoffSpecification(UpgradableSpecification upgradableSpecification,
|
||||
IPreferredWordService preferredWordServiceCalculator,
|
||||
ICustomFormatCalculationService formatService,
|
||||
Logger logger)
|
||||
{
|
||||
_upgradableSpecification = upgradableSpecification;
|
||||
_preferredWordServiceCalculator = preferredWordServiceCalculator;
|
||||
_formatService = formatService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
@@ -38,11 +39,12 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
|
||||
_logger.Debug("Comparing file quality with report. Existing files contain {0}", currentQualities.ConcatToString());
|
||||
|
||||
var customFormats = _formatService.ParseCustomFormat(file);
|
||||
|
||||
if (!_upgradableSpecification.CutoffNotMet(qualityProfile,
|
||||
currentQualities,
|
||||
_preferredWordServiceCalculator.Calculate(subject.Author, file.GetSceneOrFileName(), subject.Release.IndexerId),
|
||||
subject.ParsedBookInfo.Quality,
|
||||
subject.PreferredWordScore))
|
||||
customFormats,
|
||||
subject.ParsedBookInfo.Quality))
|
||||
{
|
||||
_logger.Debug("Cutoff already met by existing files, rejecting.");
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Core.CustomFormats;
|
||||
using NzbDrone.Core.Download.TrackedDownloads;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
@@ -14,17 +15,17 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
{
|
||||
private readonly IQueueService _queueService;
|
||||
private readonly UpgradableSpecification _upgradableSpecification;
|
||||
private readonly IPreferredWordService _preferredWordServiceCalculator;
|
||||
private readonly ICustomFormatCalculationService _formatService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public QueueSpecification(IQueueService queueService,
|
||||
UpgradableSpecification upgradableSpecification,
|
||||
IPreferredWordService preferredWordServiceCalculator,
|
||||
Logger logger)
|
||||
UpgradableSpecification upgradableSpecification,
|
||||
ICustomFormatCalculationService formatService,
|
||||
Logger logger)
|
||||
{
|
||||
_queueService = queueService;
|
||||
_upgradableSpecification = upgradableSpecification;
|
||||
_preferredWordServiceCalculator = preferredWordServiceCalculator;
|
||||
_formatService = formatService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
@@ -54,13 +55,12 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
|
||||
_logger.Debug("Checking if existing release in queue meets cutoff. Queued quality is: {0}", remoteBook.ParsedBookInfo.Quality);
|
||||
|
||||
var queuedItemPreferredWordScore = _preferredWordServiceCalculator.Calculate(subject.Author, queueItem.Title, subject.Release?.IndexerId ?? 0);
|
||||
var queuedItemCustomFormats = _formatService.ParseCustomFormat(remoteBook, (long)queueItem.Size);
|
||||
|
||||
if (!_upgradableSpecification.CutoffNotMet(qualityProfile,
|
||||
new List<QualityModel> { remoteBook.ParsedBookInfo.Quality },
|
||||
queuedItemPreferredWordScore,
|
||||
subject.ParsedBookInfo.Quality,
|
||||
subject.PreferredWordScore))
|
||||
queuedItemCustomFormats,
|
||||
subject.ParsedBookInfo.Quality))
|
||||
{
|
||||
return Decision.Reject("Release in queue already meets cutoff: {0}", remoteBook.ParsedBookInfo.Quality);
|
||||
}
|
||||
@@ -69,9 +69,9 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
|
||||
if (!_upgradableSpecification.IsUpgradable(qualityProfile,
|
||||
remoteBook.ParsedBookInfo.Quality,
|
||||
queuedItemPreferredWordScore,
|
||||
queuedItemCustomFormats,
|
||||
subject.ParsedBookInfo.Quality,
|
||||
subject.PreferredWordScore))
|
||||
subject.CustomFormats))
|
||||
{
|
||||
return Decision.Reject("Release in queue is of equal or higher preference: {0}", remoteBook.ParsedBookInfo.Quality);
|
||||
}
|
||||
@@ -80,7 +80,9 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
|
||||
if (!_upgradableSpecification.IsUpgradeAllowed(qualityProfile,
|
||||
remoteBook.ParsedBookInfo.Quality,
|
||||
subject.ParsedBookInfo.Quality))
|
||||
queuedItemCustomFormats,
|
||||
subject.ParsedBookInfo.Quality,
|
||||
subject.CustomFormats))
|
||||
{
|
||||
return Decision.Reject("Another release is queued and the Quality profile does not allow upgrades");
|
||||
}
|
||||
|
||||
@@ -32,12 +32,12 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
var title = subject.Release.Title;
|
||||
var releaseProfiles = _releaseProfileService.EnabledForTags(subject.Author.Tags, subject.Release.IndexerId);
|
||||
|
||||
var required = releaseProfiles.Where(r => r.Required.IsNotNullOrWhiteSpace());
|
||||
var ignored = releaseProfiles.Where(r => r.Ignored.IsNotNullOrWhiteSpace());
|
||||
var required = releaseProfiles.Where(r => r.Required.Any());
|
||||
var ignored = releaseProfiles.Where(r => r.Ignored.Any());
|
||||
|
||||
foreach (var r in required)
|
||||
{
|
||||
var requiredTerms = r.Required.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList();
|
||||
var requiredTerms = r.Required;
|
||||
|
||||
var foundTerms = ContainsAny(requiredTerms, title);
|
||||
if (foundTerms.Empty())
|
||||
@@ -50,7 +50,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
|
||||
foreach (var r in ignored)
|
||||
{
|
||||
var ignoredTerms = r.Ignored.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList();
|
||||
var ignoredTerms = r.Ignored;
|
||||
|
||||
var foundTerms = ContainsAny(ignoredTerms, title);
|
||||
if (foundTerms.Any())
|
||||
|
||||
@@ -5,7 +5,6 @@ using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Profiles.Delay;
|
||||
using NzbDrone.Core.Profiles.Releases;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
||||
namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
|
||||
@@ -16,21 +15,18 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
|
||||
private readonly IUpgradableSpecification _upgradableSpecification;
|
||||
private readonly IDelayProfileService _delayProfileService;
|
||||
private readonly IMediaFileService _mediaFileService;
|
||||
private readonly IPreferredWordService _preferredWordServiceCalculator;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public DelaySpecification(IPendingReleaseService pendingReleaseService,
|
||||
IUpgradableSpecification qualityUpgradableSpecification,
|
||||
IDelayProfileService delayProfileService,
|
||||
IMediaFileService mediaFileService,
|
||||
IPreferredWordService preferredWordServiceCalculator,
|
||||
Logger logger)
|
||||
{
|
||||
_pendingReleaseService = pendingReleaseService;
|
||||
_upgradableSpecification = qualityUpgradableSpecification;
|
||||
_delayProfileService = delayProfileService;
|
||||
_mediaFileService = mediaFileService;
|
||||
_preferredWordServiceCalculator = preferredWordServiceCalculator;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
@@ -80,13 +76,29 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
|
||||
}
|
||||
|
||||
// If quality meets or exceeds the best allowed quality in the profile accept it immediately
|
||||
var bestQualityInProfile = qualityProfile.LastAllowedQuality();
|
||||
var isBestInProfile = qualityComparer.Compare(subject.ParsedBookInfo.Quality.Quality, bestQualityInProfile) >= 0;
|
||||
|
||||
if (isBestInProfile && isPreferredProtocol)
|
||||
if (delayProfile.BypassIfHighestQuality)
|
||||
{
|
||||
var bestQualityInProfile = qualityProfile.LastAllowedQuality();
|
||||
var isBestInProfile = qualityComparer.Compare(subject.ParsedBookInfo.Quality.Quality, bestQualityInProfile) >= 0;
|
||||
|
||||
if (isBestInProfile && isPreferredProtocol)
|
||||
{
|
||||
_logger.Debug("Quality is highest in profile for preferred protocol, will not delay");
|
||||
return Decision.Accept();
|
||||
}
|
||||
}
|
||||
|
||||
// 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 bookIds = subject.Books.Select(e => e.Id);
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.CustomFormats;
|
||||
using NzbDrone.Core.History;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
@@ -15,20 +16,20 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
|
||||
{
|
||||
private readonly IHistoryService _historyService;
|
||||
private readonly UpgradableSpecification _upgradableSpecification;
|
||||
private readonly ICustomFormatCalculationService _formatService;
|
||||
private readonly IConfigService _configService;
|
||||
private readonly IPreferredWordService _preferredWordServiceCalculator;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public HistorySpecification(IHistoryService historyService,
|
||||
UpgradableSpecification qualityUpgradableSpecification,
|
||||
IConfigService configService,
|
||||
IPreferredWordService preferredWordServiceCalculator,
|
||||
Logger logger)
|
||||
UpgradableSpecification upgradableSpecification,
|
||||
ICustomFormatCalculationService formatService,
|
||||
IConfigService configService,
|
||||
Logger logger)
|
||||
{
|
||||
_historyService = historyService;
|
||||
_upgradableSpecification = qualityUpgradableSpecification;
|
||||
_upgradableSpecification = upgradableSpecification;
|
||||
_formatService = formatService;
|
||||
_configService = configService;
|
||||
_preferredWordServiceCalculator = preferredWordServiceCalculator;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
@@ -60,23 +61,22 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
|
||||
continue;
|
||||
}
|
||||
|
||||
// The author will be the same as the one in history since it's the same book.
|
||||
// Instead of fetching the author from the DB reuse the known author.
|
||||
var preferredWordScore = _preferredWordServiceCalculator.Calculate(subject.Author, mostRecent.SourceTitle, subject.Release?.IndexerId ?? 0);
|
||||
var customFormats = _formatService.ParseCustomFormat(mostRecent, subject.Author);
|
||||
|
||||
// The series will be the same as the one in history since it's the same episode.
|
||||
// Instead of fetching the series from the DB reuse the known series.
|
||||
var cutoffUnmet = _upgradableSpecification.CutoffNotMet(
|
||||
subject.Author.QualityProfile,
|
||||
new List<QualityModel> { mostRecent.Quality },
|
||||
preferredWordScore,
|
||||
subject.ParsedBookInfo.Quality,
|
||||
subject.PreferredWordScore);
|
||||
customFormats,
|
||||
subject.ParsedBookInfo.Quality);
|
||||
|
||||
var upgradeable = _upgradableSpecification.IsUpgradable(
|
||||
subject.Author.QualityProfile,
|
||||
mostRecent.Quality,
|
||||
preferredWordScore,
|
||||
customFormats,
|
||||
subject.ParsedBookInfo.Quality,
|
||||
subject.PreferredWordScore);
|
||||
subject.CustomFormats);
|
||||
|
||||
if (!cutoffUnmet)
|
||||
{
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.CustomFormats;
|
||||
using NzbDrone.Core.Profiles.Qualities;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
||||
@@ -9,11 +11,11 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
{
|
||||
public interface IUpgradableSpecification
|
||||
{
|
||||
bool IsUpgradable(QualityProfile profile, QualityModel currentQualities, int currentScore, QualityModel newQuality, int newScore);
|
||||
bool IsUpgradable(QualityProfile profile, QualityModel currentQuality, List<CustomFormat> currentCustomFormats, QualityModel newQuality, List<CustomFormat> newCustomFormats);
|
||||
bool QualityCutoffNotMet(QualityProfile profile, QualityModel currentQuality, QualityModel newQuality = null);
|
||||
bool CutoffNotMet(QualityProfile profile, List<QualityModel> currentQualities, int currentScore, QualityModel newQuality = null, int newScore = 0);
|
||||
bool CutoffNotMet(QualityProfile profile, List<QualityModel> currentQualities, List<CustomFormat> currentFormats, QualityModel newQuality = null);
|
||||
bool IsRevisionUpgrade(QualityModel currentQuality, QualityModel newQuality);
|
||||
bool IsUpgradeAllowed(QualityProfile qualityProfile, QualityModel currentQuality, QualityModel newQuality);
|
||||
bool IsUpgradeAllowed(QualityProfile qualityProfile, QualityModel currentQuality, List<CustomFormat> currentCustomFormats, QualityModel newQuality, List<CustomFormat> newCustomFormats);
|
||||
}
|
||||
|
||||
public class UpgradableSpecification : IUpgradableSpecification
|
||||
@@ -61,14 +63,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
return ProfileComparisonResult.Upgrade;
|
||||
}
|
||||
|
||||
private bool IsPreferredWordUpgradable(int currentScore, int newScore)
|
||||
{
|
||||
_logger.Debug("Comparing preferred word score. Current: {0} New: {1}", currentScore, newScore);
|
||||
|
||||
return newScore > currentScore;
|
||||
}
|
||||
|
||||
public bool IsUpgradable(QualityProfile qualityProfile, QualityModel currentQualities, int currentScore, QualityModel newQuality, int newScore)
|
||||
public bool IsUpgradable(QualityProfile qualityProfile, QualityModel currentQualities, List<CustomFormat> currentCustomFormats, QualityModel newQuality, List<CustomFormat> newCustomFormats)
|
||||
{
|
||||
var qualityUpgrade = IsQualityUpgradable(qualityProfile, currentQualities, newQuality);
|
||||
|
||||
@@ -84,19 +79,26 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsPreferredWordUpgradable(currentScore, newScore))
|
||||
var currentFormatScore = qualityProfile.CalculateCustomFormatScore(currentCustomFormats);
|
||||
var newFormatScore = qualityProfile.CalculateCustomFormatScore(newCustomFormats);
|
||||
|
||||
if (newFormatScore <= currentFormatScore)
|
||||
{
|
||||
_logger.Debug("Existing item has a better preferred word score, skipping");
|
||||
_logger.Debug("New item's custom formats [{0}] do not improve on [{1}], skipping",
|
||||
newCustomFormats.ConcatToString(),
|
||||
currentCustomFormats.ConcatToString());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
_logger.Debug("New item has a better preferred word score");
|
||||
_logger.Debug("New item has a better custom format score");
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool QualityCutoffNotMet(QualityProfile profile, QualityModel currentQuality, QualityModel newQuality = null)
|
||||
{
|
||||
var cutoffCompare = new QualityModelComparer(profile).Compare(currentQuality.Quality.Id, profile.Cutoff);
|
||||
var cutoff = profile.UpgradeAllowed ? profile.Cutoff : profile.FirstAllowedQuality().Id;
|
||||
var cutoffCompare = new QualityModelComparer(profile).Compare(currentQuality.Quality.Id, cutoff);
|
||||
|
||||
if (cutoffCompare < 0)
|
||||
{
|
||||
@@ -111,7 +113,13 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool CutoffNotMet(QualityProfile profile, List<QualityModel> currentQualities, int currentScore, QualityModel newQuality = null, int newScore = 0)
|
||||
private bool CustomFormatCutoffNotMet(QualityProfile profile, List<CustomFormat> currentFormats)
|
||||
{
|
||||
var score = profile.CalculateCustomFormatScore(currentFormats);
|
||||
return score < profile.CutoffFormatScore;
|
||||
}
|
||||
|
||||
public bool CutoffNotMet(QualityProfile profile, List<QualityModel> currentQualities, List<CustomFormat> currentFormats, QualityModel newQuality = null)
|
||||
{
|
||||
foreach (var quality in currentQualities)
|
||||
{
|
||||
@@ -121,7 +129,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
}
|
||||
}
|
||||
|
||||
if (IsPreferredWordUpgradable(currentScore, newScore))
|
||||
if (CustomFormatCutoffNotMet(profile, currentFormats))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -145,16 +153,23 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool IsUpgradeAllowed(QualityProfile qualityProfile, QualityModel currentQuality, QualityModel newQuality)
|
||||
public bool IsUpgradeAllowed(QualityProfile qualityProfile, QualityModel currentQuality, List<CustomFormat> currentCustomFormats, QualityModel newQuality, List<CustomFormat> newCustomFormats)
|
||||
{
|
||||
var isQualityUpgrade = IsQualityUpgradable(qualityProfile, currentQuality, newQuality);
|
||||
var isCustomFormatUpgrade = qualityProfile.CalculateCustomFormatScore(newCustomFormats) > qualityProfile.CalculateCustomFormatScore(currentCustomFormats);
|
||||
|
||||
return CheckUpgradeAllowed(qualityProfile, isQualityUpgrade);
|
||||
return CheckUpgradeAllowed(qualityProfile, isQualityUpgrade, isCustomFormatUpgrade);
|
||||
}
|
||||
|
||||
private bool CheckUpgradeAllowed(QualityProfile qualityProfile, ProfileComparisonResult isQualityUpgrade)
|
||||
private bool CheckUpgradeAllowed(QualityProfile qualityProfile, ProfileComparisonResult isQualityUpgrade, bool isCustomFormatUpgrade)
|
||||
{
|
||||
if (isQualityUpgrade == ProfileComparisonResult.Upgrade && !qualityProfile.UpgradeAllowed)
|
||||
if ((isQualityUpgrade == ProfileComparisonResult.Upgrade || isCustomFormatUpgrade) && qualityProfile.UpgradeAllowed)
|
||||
{
|
||||
_logger.Debug("Quality profile allows upgrading");
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((isQualityUpgrade == ProfileComparisonResult.Upgrade || isCustomFormatUpgrade) && !qualityProfile.UpgradeAllowed)
|
||||
{
|
||||
_logger.Debug("Quality profile does not allow upgrades, skipping");
|
||||
return false;
|
||||
|
||||
@@ -2,6 +2,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.CustomFormats;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Qualities;
|
||||
@@ -11,12 +12,15 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
public class UpgradeAllowedSpecification : IDecisionEngineSpecification
|
||||
{
|
||||
private readonly UpgradableSpecification _upgradableSpecification;
|
||||
private readonly ICustomFormatCalculationService _formatService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public UpgradeAllowedSpecification(UpgradableSpecification upgradableSpecification,
|
||||
Logger logger)
|
||||
Logger logger,
|
||||
ICustomFormatCalculationService formatService)
|
||||
{
|
||||
_upgradableSpecification = upgradableSpecification;
|
||||
_formatService = formatService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
@@ -35,11 +39,14 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
continue;
|
||||
}
|
||||
|
||||
var fileCustomFormats = _formatService.ParseCustomFormat(file, subject.Author);
|
||||
_logger.Debug("Comparing file quality with report. Existing files contain {0}", file.Quality);
|
||||
|
||||
if (!_upgradableSpecification.IsUpgradeAllowed(qualityProfile,
|
||||
file.Quality,
|
||||
subject.ParsedBookInfo.Quality))
|
||||
fileCustomFormats,
|
||||
subject.ParsedBookInfo.Quality,
|
||||
subject.CustomFormats))
|
||||
{
|
||||
_logger.Debug("Upgrading is not allowed by the quality profile");
|
||||
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Cache;
|
||||
using NzbDrone.Core.CustomFormats;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Profiles.Releases;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
||||
namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
{
|
||||
public class UpgradeDiskSpecification : IDecisionEngineSpecification
|
||||
{
|
||||
private readonly UpgradableSpecification _upgradableSpecification;
|
||||
private readonly IPreferredWordService _preferredWordServiceCalculator;
|
||||
private readonly ICustomFormatCalculationService _formatService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public UpgradeDiskSpecification(UpgradableSpecification qualityUpgradableSpecification,
|
||||
IPreferredWordService preferredWordServiceCalculator,
|
||||
ICacheManager cacheManager,
|
||||
ICustomFormatCalculationService formatService,
|
||||
Logger logger)
|
||||
{
|
||||
_upgradableSpecification = qualityUpgradableSpecification;
|
||||
_preferredWordServiceCalculator = preferredWordServiceCalculator;
|
||||
_formatService = formatService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
@@ -35,13 +35,15 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
var customFormats = _formatService.ParseCustomFormat(file);
|
||||
|
||||
if (!_upgradableSpecification.IsUpgradable(subject.Author.QualityProfile,
|
||||
file.Quality,
|
||||
_preferredWordServiceCalculator.Calculate(subject.Author, file.GetSceneOrFileName(), subject.Release?.IndexerId ?? 0),
|
||||
subject.ParsedBookInfo.Quality,
|
||||
subject.PreferredWordScore))
|
||||
file.Quality,
|
||||
customFormats,
|
||||
subject.ParsedBookInfo.Quality,
|
||||
subject.CustomFormats))
|
||||
{
|
||||
return Decision.Reject("Existing files on disk is of equal or higher preference: {0}", file.Quality);
|
||||
return Decision.Reject("Existing files on disk is of equal or higher preference: {0}", file.Quality.Quality.Name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user