mirror of
https://github.com/Sonarr/Sonarr.git
synced 2026-04-24 22:36:19 -04:00
New: Custom Formats
Co-Authored-By: ta264 <ta264@users.noreply.github.com>
This commit is contained in:
+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(RemoteEpisode subject, SearchCriteriaBase searchCriteria)
|
||||
{
|
||||
var minScore = subject.Series.QualityProfile.Value.MinFormatScore;
|
||||
var score = subject.CustomFormatScore;
|
||||
|
||||
if (score < minScore)
|
||||
{
|
||||
return Decision.Reject("Custom Formats {0} have score {1} below Series profile minimum {2}", subject.CustomFormats.ConcatToString(), score, minScore);
|
||||
}
|
||||
|
||||
return Decision.Accept();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Core.CustomFormats;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
@@ -10,13 +11,13 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
public class CutoffSpecification : IDecisionEngineSpecification
|
||||
{
|
||||
private readonly UpgradableSpecification _upgradableSpecification;
|
||||
private readonly IEpisodeFilePreferredWordCalculator _episodeFilePreferredWordCalculator;
|
||||
private readonly ICustomFormatCalculationService _formatService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public CutoffSpecification(UpgradableSpecification upgradableSpecification, IEpisodeFilePreferredWordCalculator episodeFilePreferredWordCalculator, Logger logger)
|
||||
public CutoffSpecification(UpgradableSpecification upgradableSpecification, ICustomFormatCalculationService formatService, Logger logger)
|
||||
{
|
||||
_upgradableSpecification = upgradableSpecification;
|
||||
_episodeFilePreferredWordCalculator = episodeFilePreferredWordCalculator;
|
||||
_formatService = formatService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
@@ -38,13 +39,14 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
|
||||
_logger.Debug("Comparing file quality and language with report. Existing file is {0} - {1}", file.Quality, file.Language);
|
||||
|
||||
var customFormats = _formatService.ParseCustomFormat(file);
|
||||
|
||||
if (!_upgradableSpecification.CutoffNotMet(qualityProfile,
|
||||
languageProfile,
|
||||
file.Quality,
|
||||
file.Language,
|
||||
_episodeFilePreferredWordCalculator.Calculate(subject.Series, file),
|
||||
subject.ParsedEpisodeInfo.Quality,
|
||||
subject.PreferredWordScore))
|
||||
_formatService.ParseCustomFormat(file),
|
||||
subject.ParsedEpisodeInfo.Quality))
|
||||
{
|
||||
_logger.Debug("Cutoff already met, rejecting.");
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Core.CustomFormats;
|
||||
using NzbDrone.Core.Download.TrackedDownloads;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
@@ -12,17 +13,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,
|
||||
ICustomFormatCalculationService formatService,
|
||||
Logger logger)
|
||||
{
|
||||
_queueService = queueService;
|
||||
_upgradableSpecification = upgradableSpecification;
|
||||
_preferredWordServiceCalculator = preferredWordServiceCalculator;
|
||||
_formatService = formatService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
@@ -52,16 +53,16 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
continue;
|
||||
}
|
||||
|
||||
var queuedItemCustomFormats = _formatService.ParseCustomFormat(remoteEpisode.ParsedEpisodeInfo);
|
||||
|
||||
_logger.Debug("Checking if existing release in queue meets cutoff. Queued: {0} - {1}", remoteEpisode.ParsedEpisodeInfo.Quality, remoteEpisode.ParsedEpisodeInfo.Language);
|
||||
var queuedItemPreferredWordScore = _preferredWordServiceCalculator.Calculate(subject.Series, queueItem.Title, subject.Release?.IndexerId ?? 0);
|
||||
|
||||
if (!_upgradableSpecification.CutoffNotMet(qualityProfile,
|
||||
languageProfile,
|
||||
remoteEpisode.ParsedEpisodeInfo.Quality,
|
||||
remoteEpisode.ParsedEpisodeInfo.Language,
|
||||
queuedItemPreferredWordScore,
|
||||
subject.ParsedEpisodeInfo.Quality,
|
||||
subject.PreferredWordScore))
|
||||
queuedItemCustomFormats,
|
||||
subject.ParsedEpisodeInfo.Quality))
|
||||
{
|
||||
return Decision.Reject("Release in queue already meets cutoff: {0} - {1}", remoteEpisode.ParsedEpisodeInfo.Quality, remoteEpisode.ParsedEpisodeInfo.Language);
|
||||
}
|
||||
@@ -72,10 +73,10 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
languageProfile,
|
||||
remoteEpisode.ParsedEpisodeInfo.Quality,
|
||||
remoteEpisode.ParsedEpisodeInfo.Language,
|
||||
queuedItemPreferredWordScore,
|
||||
remoteEpisode.CustomFormats,
|
||||
subject.ParsedEpisodeInfo.Quality,
|
||||
subject.ParsedEpisodeInfo.Language,
|
||||
subject.PreferredWordScore))
|
||||
subject.CustomFormats))
|
||||
{
|
||||
return Decision.Reject("Release in queue is of equal or higher preference: {0} - {1}", remoteEpisode.ParsedEpisodeInfo.Quality, remoteEpisode.ParsedEpisodeInfo.Language);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
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;
|
||||
@@ -13,20 +14,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 upgradableSpecification,
|
||||
IConfigService configService,
|
||||
IPreferredWordService preferredWordServiceCalculator,
|
||||
Logger logger)
|
||||
UpgradableSpecification upgradableSpecification,
|
||||
ICustomFormatCalculationService formatService,
|
||||
IConfigService configService,
|
||||
Logger logger)
|
||||
{
|
||||
_historyService = historyService;
|
||||
_upgradableSpecification = upgradableSpecification;
|
||||
_formatService = formatService;
|
||||
_configService = configService;
|
||||
_preferredWordServiceCalculator = preferredWordServiceCalculator;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
@@ -58,28 +59,27 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
|
||||
continue;
|
||||
}
|
||||
|
||||
var customFormats = _formatService.ParseCustomFormat(mostRecent);
|
||||
|
||||
// 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 preferredWordScore = _preferredWordServiceCalculator.Calculate(subject.Series, mostRecent.SourceTitle, subject.Release?.IndexerId ?? 0);
|
||||
|
||||
var cutoffUnmet = _upgradableSpecification.CutoffNotMet(
|
||||
subject.Series.QualityProfile,
|
||||
subject.Series.LanguageProfile,
|
||||
mostRecent.Quality,
|
||||
mostRecent.Language,
|
||||
preferredWordScore,
|
||||
subject.ParsedEpisodeInfo.Quality,
|
||||
subject.PreferredWordScore);
|
||||
customFormats,
|
||||
subject.ParsedEpisodeInfo.Quality);
|
||||
|
||||
var upgradeable = _upgradableSpecification.IsUpgradable(
|
||||
subject.Series.QualityProfile,
|
||||
subject.Series.LanguageProfile,
|
||||
mostRecent.Quality,
|
||||
mostRecent.Language,
|
||||
preferredWordScore,
|
||||
customFormats,
|
||||
subject.ParsedEpisodeInfo.Quality,
|
||||
subject.ParsedEpisodeInfo.Language,
|
||||
subject.PreferredWordScore);
|
||||
subject.CustomFormats);
|
||||
|
||||
if (!cutoffUnmet)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
using System.Collections.Generic;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.CustomFormats;
|
||||
using NzbDrone.Core.Languages;
|
||||
using NzbDrone.Core.Profiles.Languages;
|
||||
using NzbDrone.Core.Profiles.Qualities;
|
||||
@@ -9,10 +12,10 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
{
|
||||
public interface IUpgradableSpecification
|
||||
{
|
||||
bool IsUpgradable(QualityProfile profile, LanguageProfile languageProfile, QualityModel currentQuality, Language currentLanguage, int currentScore, QualityModel newQuality, Language newLanguage, int newScore);
|
||||
bool IsUpgradable(QualityProfile profile, LanguageProfile languageProfile, QualityModel currentQuality, Language currentLanguage, List<CustomFormat> currentCustomFormats, QualityModel newQuality, Language newLanguage, List<CustomFormat> newCustomFormats);
|
||||
bool QualityCutoffNotMet(QualityProfile profile, QualityModel currentQuality, QualityModel newQuality = null);
|
||||
bool LanguageCutoffNotMet(LanguageProfile languageProfile, Language currentLanguage);
|
||||
bool CutoffNotMet(QualityProfile profile, LanguageProfile languageProfile, QualityModel currentQuality, Language currentLanguage, int currentScore, QualityModel newQuality = null, int newScore = 0);
|
||||
bool CutoffNotMet(QualityProfile profile, LanguageProfile languageProfile, QualityModel currentQuality, Language currentLanguage, List<CustomFormat> currentCustomFormats, QualityModel newQuality = null);
|
||||
bool IsRevisionUpgrade(QualityModel currentQuality, QualityModel newQuality);
|
||||
bool IsUpgradeAllowed(QualityProfile qualityProfile, LanguageProfile languageProfile, QualityModel currentQuality, Language currentLanguage, QualityModel newQuality, Language newLanguage);
|
||||
}
|
||||
@@ -35,7 +38,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
return newScore > currentScore;
|
||||
}
|
||||
|
||||
public bool IsUpgradable(QualityProfile qualityProfile, LanguageProfile languageProfile, QualityModel currentQuality, Language currentLanguage, int currentScore, QualityModel newQuality, Language newLanguage, int newScore)
|
||||
public bool IsUpgradable(QualityProfile qualityProfile, LanguageProfile languageProfile, QualityModel currentQuality, Language currentLanguage, List<CustomFormat> currentCustomFormats, QualityModel newQuality, Language newLanguage, List<CustomFormat> newCustomFormats)
|
||||
{
|
||||
var qualityComparer = new QualityModelComparer(qualityProfile);
|
||||
var qualityCompare = qualityComparer.Compare(newQuality?.Quality, currentQuality.Quality);
|
||||
@@ -64,6 +67,9 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
return true;
|
||||
}
|
||||
|
||||
var currentFormatScore = qualityProfile.CalculateCustomFormatScore(currentCustomFormats);
|
||||
var newFormatScore = qualityProfile.CalculateCustomFormatScore(newCustomFormats);
|
||||
|
||||
// Reject unless the user does not prefer propers/repacks and it's a revision downgrade.
|
||||
if (downloadPropersAndRepacks != ProperDownloadTypes.DoNotPrefer &&
|
||||
qualityRevisionComapre < 0)
|
||||
@@ -86,13 +92,15 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsPreferredWordUpgradable(currentScore, newScore))
|
||||
if (newFormatScore <= currentFormatScore)
|
||||
{
|
||||
_logger.Debug("Existing item has an equal or 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;
|
||||
}
|
||||
|
||||
@@ -125,7 +133,13 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
return languageCompare < 0;
|
||||
}
|
||||
|
||||
public bool CutoffNotMet(QualityProfile profile, LanguageProfile languageProfile, QualityModel currentQuality, Language currentLanguage, 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, LanguageProfile languageProfile, QualityModel currentQuality, Language currentLanguage, List<CustomFormat> currentFormats, QualityModel newQuality = null)
|
||||
{
|
||||
// If we can upgrade the language (it is not the cutoff) then the quality doesn't
|
||||
// matter as we can always get same quality with prefered language.
|
||||
@@ -139,7 +153,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IsPreferredWordUpgradable(currentScore, newScore))
|
||||
if (CustomFormatCutoffNotMet(profile, currentFormats))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Core.CustomFormats;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
@@ -10,13 +11,15 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
public class UpgradeDiskSpecification : IDecisionEngineSpecification
|
||||
{
|
||||
private readonly UpgradableSpecification _upgradableSpecification;
|
||||
private readonly IEpisodeFilePreferredWordCalculator _episodeFilePreferredWordCalculator;
|
||||
private readonly ICustomFormatCalculationService _formatService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public UpgradeDiskSpecification(UpgradableSpecification upgradableSpecification, IEpisodeFilePreferredWordCalculator episodeFilePreferredWordCalculator, Logger logger)
|
||||
public UpgradeDiskSpecification(UpgradableSpecification upgradableSpecification,
|
||||
ICustomFormatCalculationService formatService,
|
||||
Logger logger)
|
||||
{
|
||||
_upgradableSpecification = upgradableSpecification;
|
||||
_episodeFilePreferredWordCalculator = episodeFilePreferredWordCalculator;
|
||||
_formatService = formatService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
@@ -33,16 +36,18 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
continue;
|
||||
}
|
||||
|
||||
var customFormats = _formatService.ParseCustomFormat(file);
|
||||
|
||||
_logger.Debug("Comparing file quality and language with report. Existing file is {0} - {1}", file.Quality, file.Language);
|
||||
|
||||
if (!_upgradableSpecification.IsUpgradable(subject.Series.QualityProfile,
|
||||
subject.Series.LanguageProfile,
|
||||
file.Quality,
|
||||
file.Language,
|
||||
_episodeFilePreferredWordCalculator.Calculate(subject.Series, file),
|
||||
customFormats,
|
||||
subject.ParsedEpisodeInfo.Quality,
|
||||
subject.ParsedEpisodeInfo.Language,
|
||||
subject.PreferredWordScore))
|
||||
subject.CustomFormats))
|
||||
{
|
||||
return Decision.Reject("Existing file on disk is of equal or higher preference: {0} - {1}", file.Quality, file.Language);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user