mirror of
https://github.com/Sonarr/Sonarr.git
synced 2025-04-24 06:17:08 -04:00
Refactor history checks and add tests for decision logic
Streamlined history checks by replacing `MostRecentForEpisodeInEventCollection` with more granular methods to improve clarity and maintainability. Added comprehensive unit tests to validate the updated decision-making logic for episode downloads. Removed unused methods and imports to enhance code consistency.
This commit is contained in:
parent
02e455b2da
commit
d894035922
5 changed files with 417 additions and 88 deletions
|
@ -0,0 +1,306 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.CustomFormats;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications.RssSync;
|
||||
using NzbDrone.Core.History;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Profiles;
|
||||
using NzbDrone.Core.Profiles.Qualities;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Test.Qualities;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.Test.HistoryTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class HistorySpecificationFixture : CoreTest<HistorySpecification>
|
||||
{
|
||||
private RemoteEpisode _remoteEpisode;
|
||||
private Series _series;
|
||||
private Episode _episode;
|
||||
private QualityModel _quality;
|
||||
private QualityProfile _profile;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_series = Builder<Series>.CreateNew()
|
||||
.With(s => s.Id = 1)
|
||||
.Build();
|
||||
|
||||
_episode = Builder<Episode>.CreateNew()
|
||||
.With(e => e.Id = 1)
|
||||
.With(e => e.SeriesId = _series.Id)
|
||||
.Build();
|
||||
|
||||
_quality = new QualityModel(Quality.HDTV720p);
|
||||
_series.QualityProfile = _profile;
|
||||
|
||||
_remoteEpisode = Builder<RemoteEpisode>.CreateNew()
|
||||
.With(r => r.Series = _series)
|
||||
.With(r => r.Episodes = new List<Episode> { _episode })
|
||||
.With(r => r.ParsedEpisodeInfo = new ParsedEpisodeInfo { Quality = _quality })
|
||||
.With(r => r.CustomFormats = new List<CustomFormat>())
|
||||
.With(r => r.CustomFormatScore = 0)
|
||||
.Build();
|
||||
|
||||
_profile = new QualityProfile
|
||||
{
|
||||
Cutoff = Quality.HDTV720p.Id,
|
||||
Items = QualityFixture.GetDefaultQualities(),
|
||||
Name = "Test"
|
||||
};
|
||||
}
|
||||
|
||||
private void SetupHistoryServiceMock(List<EpisodeHistory> history)
|
||||
{
|
||||
// Setup mock for IHistoryService
|
||||
Mocker.GetMock<IHistoryService>()
|
||||
.Setup(s => s.FindByEpisodeId(It.IsAny<int>()))
|
||||
.Returns(history);
|
||||
}
|
||||
|
||||
private void SetupCdh(bool cdhEnabled)
|
||||
{
|
||||
// Setup mock for IHistoryService
|
||||
Mocker.GetMock<IConfigService>()
|
||||
.Setup(s => s.EnableCompletedDownloadHandling)
|
||||
.Returns(cdhEnabled);
|
||||
}
|
||||
|
||||
private List<EpisodeHistory> GivenFileHistory(DateTime date, QualityModel quality, EpisodeHistoryEventType eventType = EpisodeHistoryEventType.SeriesFolderImported)
|
||||
{
|
||||
return new List<EpisodeHistory>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Date = date,
|
||||
Quality = quality,
|
||||
EventType = eventType
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private RemoteEpisode MockUpOrDownGrade(int customFormatScoreHistory, int customFormatScoreNew, QualityModel newQuality, int cutoff, bool hasFile = false)
|
||||
{
|
||||
_profile.FormatItems = new List<ProfileFormatItem>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Format = new CustomFormat(),
|
||||
Score = customFormatScoreHistory
|
||||
}
|
||||
};
|
||||
_profile.Cutoff = cutoff;
|
||||
|
||||
var episode = Builder<Episode>.CreateNew()
|
||||
.With(e => e.Id = 1)
|
||||
.With(e => e.EpisodeFileId = hasFile ? 1 : 0)
|
||||
.Build();
|
||||
|
||||
var remoteEpisode = new RemoteEpisode
|
||||
{
|
||||
Episodes = new List<Episode> { episode },
|
||||
Series = new Series
|
||||
{
|
||||
QualityProfile = _profile
|
||||
},
|
||||
CustomFormatScore = customFormatScoreNew,
|
||||
ParsedEpisodeInfo = new ParsedEpisodeInfo { Quality = newQuality },
|
||||
};
|
||||
|
||||
Mocker.GetMock<ICustomFormatCalculationService>()
|
||||
.Setup(s => s.ParseCustomFormat(It.IsAny<EpisodeHistory>(), It.IsAny<Series>()))
|
||||
.Returns(new List<CustomFormat>()
|
||||
{
|
||||
_profile.FormatItems.First().Format
|
||||
});
|
||||
return remoteEpisode;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_accept_if_no_history()
|
||||
{
|
||||
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_reject_when_grabbed_history_is_old_and_cdh_enabled_when_no_quality_update()
|
||||
{
|
||||
// Arrange
|
||||
var newQuality = new QualityModel(Quality.HDTV720p);
|
||||
var remoteEpisode = MockUpOrDownGrade(3000, 3000, newQuality, Quality.HDTV720p.Id, true);
|
||||
var history = GivenFileHistory(DateTime.UtcNow.AddHours(-13), _quality, EpisodeHistoryEventType.Grabbed);
|
||||
history.AddRange(GivenFileHistory(DateTime.UtcNow.AddHours(-13), _quality));
|
||||
SetupHistoryServiceMock(history);
|
||||
SetupCdh(true);
|
||||
|
||||
// Act
|
||||
var decision = Subject.IsSatisfiedBy(remoteEpisode, null);
|
||||
|
||||
// Assert
|
||||
decision.Accepted.Should().BeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_accept_when_grabbed_history_is_old_and_cdh_enabled_when_quality_update()
|
||||
{
|
||||
// Arrange
|
||||
var newQuality = new QualityModel(Quality.Bluray1080p);
|
||||
var remoteEpisode = MockUpOrDownGrade(3000, 3000, newQuality, Quality.WEBRip2160p.Id);
|
||||
var history = GivenFileHistory(DateTime.UtcNow.AddHours(-13), _quality, EpisodeHistoryEventType.Grabbed);
|
||||
SetupHistoryServiceMock(history);
|
||||
SetupCdh(true);
|
||||
|
||||
// Act
|
||||
var decision = Subject.IsSatisfiedBy(remoteEpisode, null);
|
||||
|
||||
// Assert
|
||||
decision.Accepted.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_accept_when_grabbed_history_is_old_and_cdh_enabled_when_custom_format_score_update()
|
||||
{
|
||||
// Arrange
|
||||
var newQuality = new QualityModel(Quality.Bluray1080p);
|
||||
var remoteEpisode = MockUpOrDownGrade(3000, 8000, newQuality, Quality.WEBRip1080p.Id);
|
||||
var history = GivenFileHistory(DateTime.UtcNow.AddHours(-13), _quality, EpisodeHistoryEventType.Grabbed);
|
||||
history.AddRange(GivenFileHistory(DateTime.UtcNow.AddHours(-13), _quality));
|
||||
SetupHistoryServiceMock(history);
|
||||
SetupCdh(true);
|
||||
|
||||
// Act
|
||||
var decision = Subject.IsSatisfiedBy(remoteEpisode, null);
|
||||
|
||||
// Assert
|
||||
decision.Accepted.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_reject_when_grabbed_history_meets_cutoff_and_is_recent()
|
||||
{
|
||||
// Arrange
|
||||
var betterQuality = new QualityModel(Quality.Bluray1080p);
|
||||
var history = GivenFileHistory(DateTime.UtcNow.AddHours(-1), betterQuality, EpisodeHistoryEventType.Grabbed);
|
||||
|
||||
var newQuality = new QualityModel(Quality.Bluray1080p);
|
||||
var remoteEpisode = MockUpOrDownGrade(3000, 8000, newQuality, Quality.Bluray1080p.Id);
|
||||
SetupHistoryServiceMock(history);
|
||||
|
||||
// Act
|
||||
var decision = Subject.IsSatisfiedBy(remoteEpisode, null);
|
||||
|
||||
// Assert
|
||||
decision.Accepted.Should().BeFalse();
|
||||
decision.Reason.Should().Be(DownloadRejectionReason.HistoryRecentCutoffMet);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_reject_when_grabbed_history_meets_cutoff_and_cdh_disabled()
|
||||
{
|
||||
// Arrange
|
||||
var newQuality = new QualityModel(Quality.WEBDL720p);
|
||||
var remoteEpisode = MockUpOrDownGrade(3000, 8000, newQuality, Quality.Bluray1080p.Id);
|
||||
var betterQuality = new QualityModel(Quality.Bluray1080p);
|
||||
var history = GivenFileHistory(DateTime.UtcNow.AddHours(-13), betterQuality, EpisodeHistoryEventType.Grabbed);
|
||||
SetupHistoryServiceMock(history);
|
||||
|
||||
// Act
|
||||
var decision = Subject.IsSatisfiedBy(remoteEpisode, null);
|
||||
|
||||
// Assert
|
||||
decision.Accepted.Should().BeFalse();
|
||||
decision.Reason.Should().Be(DownloadRejectionReason.HistoryCdhDisabledCutoffMet);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_accept_when_file_history_has_lower_quality_in_custom_format_score()
|
||||
{
|
||||
// Arrange
|
||||
var newQuality = new QualityModel(Quality.SDTV);
|
||||
var remoteEpisode = MockUpOrDownGrade(3000, 8000, newQuality, Quality.WEBDL720p.Id, true);
|
||||
var history = GivenFileHistory(DateTime.UtcNow.AddDays(-5), new QualityModel(Quality.SDTV));
|
||||
SetupHistoryServiceMock(history);
|
||||
|
||||
// Act
|
||||
var decision = Subject.IsSatisfiedBy(remoteEpisode, null);
|
||||
|
||||
// Assert
|
||||
decision.Accepted.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_reject_when_file_history_has_higher_quality_in_custom_format_score()
|
||||
{
|
||||
// Arrange
|
||||
var newQuality = new QualityModel(Quality.SDTV);
|
||||
var remoteEpisode = MockUpOrDownGrade(8000, 3000, newQuality, Quality.WEBDL720p.Id, true);
|
||||
var history = GivenFileHistory(DateTime.UtcNow.AddDays(-5), new QualityModel(Quality.SDTV));
|
||||
SetupHistoryServiceMock(history);
|
||||
|
||||
// Act
|
||||
var decision = Subject.IsSatisfiedBy(remoteEpisode, null);
|
||||
|
||||
// Assert
|
||||
decision.Accepted.Should().BeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_accept_when_file_history_has_lower_quality_in_quality_profile()
|
||||
{
|
||||
// Arrange
|
||||
var newQuality = new QualityModel(Quality.WEBDL720p);
|
||||
var remoteEpisode = MockUpOrDownGrade(3000, 3000, newQuality, Quality.WEBDL720p.Id, true);
|
||||
var history = GivenFileHistory(DateTime.UtcNow.AddDays(-5), new QualityModel(Quality.SDTV));
|
||||
SetupHistoryServiceMock(history);
|
||||
|
||||
// Act
|
||||
var decision = Subject.IsSatisfiedBy(remoteEpisode, null);
|
||||
|
||||
// Assert
|
||||
decision.Accepted.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_reject_when_file_history_has_higher_quality_in_quality_profile()
|
||||
{
|
||||
// Arrange
|
||||
var newQuality = new QualityModel(Quality.SDTV);
|
||||
var remoteEpisode = MockUpOrDownGrade(3000, 3000, newQuality, Quality.WEBDL720p.Id, true);
|
||||
var history = GivenFileHistory(DateTime.UtcNow.AddDays(-5), new QualityModel(Quality.WEBDL720p));
|
||||
SetupHistoryServiceMock(history);
|
||||
|
||||
// Act
|
||||
var decision = Subject.IsSatisfiedBy(remoteEpisode, null);
|
||||
|
||||
// Assert
|
||||
decision.Accepted.Should().BeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_reject_when_grabbed_history_has_better_custom_format()
|
||||
{
|
||||
// Arrange
|
||||
var date = DateTime.UtcNow.AddMinutes(-10);
|
||||
var grabHistory = GivenFileHistory(date, new QualityModel(Quality.HDTV720p), EpisodeHistoryEventType.Grabbed);
|
||||
var remoteEpisode = MockUpOrDownGrade(5, 2, new QualityModel(Quality.HDTV720p), 0);
|
||||
SetupHistoryServiceMock(grabHistory);
|
||||
|
||||
// Act
|
||||
var decision = Subject.IsSatisfiedBy(remoteEpisode, null);
|
||||
|
||||
// Assert
|
||||
decision.Accepted.Should().BeFalse();
|
||||
decision.Reason.Should().Be(DownloadRejectionReason.HistoryRecentCutoffMet);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -73,5 +73,6 @@ public enum DownloadRejectionReason
|
|||
DiskCustomFormatCutoffMet,
|
||||
DiskCustomFormatScore,
|
||||
DiskCustomFormatScoreIncrement,
|
||||
DiskUpgradesNotAllowed
|
||||
DiskUpgradesNotAllowed,
|
||||
BetterQuality
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
|
@ -9,6 +8,8 @@ using NzbDrone.Core.CustomFormats;
|
|||
using NzbDrone.Core.History;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Profiles.Qualities;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
||||
namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
|
||||
{
|
||||
|
@ -52,61 +53,83 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
|
|||
foreach (var episode in subject.Episodes)
|
||||
{
|
||||
_logger.Debug("Checking current status of episode [{0}] in history", episode.Id);
|
||||
var mostRecent = _historyService.MostRecentForEpisode(episode.Id);
|
||||
var episodeHistories = _historyService.FindByEpisodeId(episode.Id);
|
||||
|
||||
if (mostRecent == null)
|
||||
if (episodeHistories == null || !episodeHistories.Any())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mostRecent.EventType == EpisodeHistoryEventType.Grabbed)
|
||||
// Check for grabbed events first
|
||||
var rejectionDecision = CheckGrabbedEvents(episodeHistories, subject, qualityProfile, cdhEnabled);
|
||||
if (!rejectionDecision.Accepted)
|
||||
{
|
||||
var recent = mostRecent.Date.After(DateTime.UtcNow.AddHours(-12));
|
||||
return rejectionDecision;
|
||||
}
|
||||
|
||||
if (!recent && cdhEnabled)
|
||||
// Then check for file events if episode has a file
|
||||
if (episode.HasFile)
|
||||
{
|
||||
rejectionDecision = CheckLastImportedFile(episodeHistories, subject, qualityProfile);
|
||||
if (!rejectionDecision.Accepted)
|
||||
{
|
||||
continue;
|
||||
return rejectionDecision;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return DownloadSpecDecision.Accept();
|
||||
}
|
||||
|
||||
private DownloadSpecDecision CheckGrabbedEvents(List<EpisodeHistory> histories, RemoteEpisode subject, QualityProfile qualityProfile, bool cdhEnabled)
|
||||
{
|
||||
foreach (var history in histories.Where(h => h.EventType == EpisodeHistoryEventType.Grabbed))
|
||||
{
|
||||
var customFormats = _formatService.ParseCustomFormat(history, subject.Series);
|
||||
var recent = history.Date.After(DateTime.UtcNow.AddHours(-12));
|
||||
|
||||
if (!recent && cdhEnabled)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var cutoffUnmet = _upgradableSpecification.CutoffNotMet(
|
||||
qualityProfile,
|
||||
history.Quality,
|
||||
customFormats,
|
||||
subject.ParsedEpisodeInfo.Quality);
|
||||
|
||||
var upgradeableRejectReason = _upgradableSpecification.IsUpgradable(
|
||||
qualityProfile,
|
||||
history.Quality,
|
||||
customFormats,
|
||||
subject.ParsedEpisodeInfo.Quality,
|
||||
subject.CustomFormats);
|
||||
|
||||
if (!cutoffUnmet)
|
||||
{
|
||||
if (recent)
|
||||
{
|
||||
return DownloadSpecDecision.Reject(DownloadRejectionReason.HistoryRecentCutoffMet,
|
||||
"Recent grab event in history already meets cutoff: {0}",
|
||||
history.Quality);
|
||||
}
|
||||
|
||||
var customFormats = _formatService.ParseCustomFormat(mostRecent, subject.Series);
|
||||
return DownloadSpecDecision.Reject(DownloadRejectionReason.HistoryCdhDisabledCutoffMet, "CDH is disabled and grab event in history already meets cutoff: {0}", history.Quality);
|
||||
}
|
||||
|
||||
// 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.Series.QualityProfile,
|
||||
mostRecent.Quality,
|
||||
customFormats,
|
||||
subject.ParsedEpisodeInfo.Quality);
|
||||
var rejectionSubject = recent ? "Recent" : "CDH is disabled and";
|
||||
|
||||
var upgradeableRejectReason = _upgradableSpecification.IsUpgradable(
|
||||
subject.Series.QualityProfile,
|
||||
mostRecent.Quality,
|
||||
customFormats,
|
||||
subject.ParsedEpisodeInfo.Quality,
|
||||
subject.CustomFormats);
|
||||
|
||||
if (!cutoffUnmet)
|
||||
{
|
||||
if (recent)
|
||||
{
|
||||
return DownloadSpecDecision.Reject(DownloadRejectionReason.HistoryRecentCutoffMet, "Recent grab event in history already meets cutoff: {0}", mostRecent.Quality);
|
||||
}
|
||||
|
||||
return DownloadSpecDecision.Reject(DownloadRejectionReason.HistoryCdhDisabledCutoffMet, "CDH is disabled and grab event in history already meets cutoff: {0}", mostRecent.Quality);
|
||||
}
|
||||
|
||||
var rejectionSubject = recent ? "Recent" : "CDH is disabled and";
|
||||
|
||||
switch (upgradeableRejectReason)
|
||||
switch (upgradeableRejectReason)
|
||||
{
|
||||
case UpgradeableRejectReason.None:
|
||||
continue;
|
||||
|
||||
case UpgradeableRejectReason.BetterQuality:
|
||||
return DownloadSpecDecision.Reject(DownloadRejectionReason.HistoryHigherPreference, "{0} grab event in history is of equal or higher preference: {1}", rejectionSubject, mostRecent.Quality);
|
||||
return DownloadSpecDecision.Reject(DownloadRejectionReason.HistoryHigherPreference, "{0} grab event in history is of equal or higher preference: {1}", rejectionSubject, history.Quality);
|
||||
|
||||
case UpgradeableRejectReason.BetterRevision:
|
||||
return DownloadSpecDecision.Reject(DownloadRejectionReason.HistoryHigherRevision, "{0} grab event in history is of equal or higher revision: {1}", rejectionSubject, mostRecent.Quality.Revision);
|
||||
return DownloadSpecDecision.Reject(DownloadRejectionReason.HistoryHigherRevision, "{0} grab event in history is of equal or higher revision: {1}", rejectionSubject, history.Quality.Revision);
|
||||
|
||||
case UpgradeableRejectReason.QualityCutoff:
|
||||
return DownloadSpecDecision.Reject(DownloadRejectionReason.HistoryCutoffMet, "{0} grab event in history meets quality cutoff: {1}", rejectionSubject, qualityProfile.Items[qualityProfile.GetIndex(qualityProfile.Cutoff).Index]);
|
||||
|
@ -123,45 +146,58 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
|
|||
case UpgradeableRejectReason.UpgradesNotAllowed:
|
||||
return DownloadSpecDecision.Reject(DownloadRejectionReason.HistoryUpgradesNotAllowed, "{0} grab event in history and Quality Profile '{1}' does not allow upgrades", rejectionSubject, qualityProfile.Name);
|
||||
}
|
||||
}
|
||||
|
||||
if (episode is { HasFile: true })
|
||||
{
|
||||
EpisodeHistory availableUsableEpisodeHistoryForCustomFormatScore;
|
||||
|
||||
var episodeHistoryEventTypeForHistoryComparison = new List<EpisodeHistoryEventType>
|
||||
{
|
||||
EpisodeHistoryEventType.Grabbed,
|
||||
EpisodeHistoryEventType.SeriesFolderImported,
|
||||
};
|
||||
|
||||
if (episodeHistoryEventTypeForHistoryComparison.Contains(mostRecent.EventType))
|
||||
{
|
||||
availableUsableEpisodeHistoryForCustomFormatScore = mostRecent;
|
||||
}
|
||||
else
|
||||
{
|
||||
availableUsableEpisodeHistoryForCustomFormatScore = _historyService.MostRecentForEpisodeInEventCollection(
|
||||
episode.Id,
|
||||
new ReadOnlyCollection<EpisodeHistoryEventType>(episodeHistoryEventTypeForHistoryComparison));
|
||||
}
|
||||
|
||||
if (availableUsableEpisodeHistoryForCustomFormatScore == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var mostRecentCustomFormat = _formatService.ParseCustomFormat(availableUsableEpisodeHistoryForCustomFormatScore, subject.Series);
|
||||
var mostRecentCustomFormatScore = qualityProfile.CalculateCustomFormatScore(mostRecentCustomFormat);
|
||||
|
||||
if (mostRecentCustomFormatScore > subject.CustomFormatScore)
|
||||
{
|
||||
return DownloadSpecDecision.Reject(DownloadRejectionReason.HistoryCustomFormatScore, "Quality Profile '{0}' has a higher Custom Format score than the report: {1}", qualityProfile.Name, subject.CustomFormatScore);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return DownloadSpecDecision.Accept();
|
||||
}
|
||||
|
||||
private DownloadSpecDecision CheckLastImportedFile(List<EpisodeHistory> histories, RemoteEpisode subject, QualityProfile qualityProfile)
|
||||
{
|
||||
var newQuality = subject.ParsedEpisodeInfo.Quality;
|
||||
var relevantHistorie = histories.FirstOrDefault(h => h.EventType == EpisodeHistoryEventType.SeriesFolderImported);
|
||||
if (relevantHistorie == null)
|
||||
{
|
||||
return DownloadSpecDecision.Accept();
|
||||
}
|
||||
|
||||
var qualityComparer = new QualityModelComparer(qualityProfile);
|
||||
var qualityCompare = qualityComparer.Compare(newQuality, relevantHistorie.Quality);
|
||||
var historyCustomFormats = _formatService.ParseCustomFormat(relevantHistorie, subject.Series);
|
||||
var historyCustomFormatScore = qualityProfile.CalculateCustomFormatScore(historyCustomFormats);
|
||||
|
||||
// New release has better quality - always accept
|
||||
if (qualityCompare > 0)
|
||||
{
|
||||
return DownloadSpecDecision.Accept();
|
||||
}
|
||||
|
||||
// New release has worse quality - reject
|
||||
if (qualityCompare < 0)
|
||||
{
|
||||
var reject = DownloadSpecDecision.Reject(DownloadRejectionReason.BetterQuality, "Existing item has better quality, skipping. Existing: {0}. New: {1}", relevantHistorie.Quality, newQuality);
|
||||
_logger.Debug(reject.Message);
|
||||
return reject;
|
||||
}
|
||||
|
||||
// Quality is the same, check custom format score
|
||||
if (subject.CustomFormatScore > historyCustomFormatScore)
|
||||
{
|
||||
// New release has better custom format score
|
||||
return DownloadSpecDecision.Accept();
|
||||
}
|
||||
else
|
||||
{
|
||||
// New release has same or worse custom format score
|
||||
var reject = DownloadSpecDecision.Reject(DownloadRejectionReason.HistoryCustomFormatScore,
|
||||
"New item's custom formats [{0}] ({1}) do not improve on [{2}] ({3}), skipping",
|
||||
subject.CustomFormats.ConcatToString(),
|
||||
subject.CustomFormatScore,
|
||||
historyCustomFormats?.ConcatToString(),
|
||||
historyCustomFormatScore);
|
||||
|
||||
_logger.Debug(reject.Message);
|
||||
return reject;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
|
@ -21,7 +20,6 @@ namespace NzbDrone.Core.History
|
|||
void DeleteForSeries(List<int> seriesIds);
|
||||
List<EpisodeHistory> Since(DateTime date, EpisodeHistoryEventType? eventType);
|
||||
PagingSpec<EpisodeHistory> GetPaged(PagingSpec<EpisodeHistory> pagingSpec, int[] languages, int[] qualities);
|
||||
EpisodeHistory MostRecentForEpisodeInEventCollection(int id, ReadOnlyCollection<EpisodeHistoryEventType> episodeHistoryEventTypes);
|
||||
}
|
||||
|
||||
public class HistoryRepository : BasicRepository<EpisodeHistory>, IHistoryRepository
|
||||
|
@ -134,11 +132,6 @@ namespace NzbDrone.Core.History
|
|||
return pagingSpec;
|
||||
}
|
||||
|
||||
public EpisodeHistory MostRecentForEpisodeInEventCollection(int id, ReadOnlyCollection<EpisodeHistoryEventType> episodeHistoryEventTypes)
|
||||
{
|
||||
return Query(x => x.EpisodeId == id).Where(x => episodeHistoryEventTypes.Contains(x.EventType)).MaxBy(h => h.Date);
|
||||
}
|
||||
|
||||
private SqlBuilder PagedBuilder(int[] languages, int[] qualities)
|
||||
{
|
||||
var builder = Builder()
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
|
@ -28,7 +27,6 @@ namespace NzbDrone.Core.History
|
|||
List<EpisodeHistory> FindByDownloadId(string downloadId);
|
||||
string FindDownloadId(EpisodeImportedEvent trackedDownload);
|
||||
List<EpisodeHistory> Since(DateTime date, EpisodeHistoryEventType? eventType);
|
||||
EpisodeHistory MostRecentForEpisodeInEventCollection(int id, ReadOnlyCollection<EpisodeHistoryEventType> episodeHistoryEventTypes);
|
||||
}
|
||||
|
||||
public class HistoryService : IHistoryService,
|
||||
|
@ -367,10 +365,5 @@ namespace NzbDrone.Core.History
|
|||
{
|
||||
return _historyRepository.Since(date, eventType);
|
||||
}
|
||||
|
||||
public EpisodeHistory MostRecentForEpisodeInEventCollection(int id, ReadOnlyCollection<EpisodeHistoryEventType> episodeHistoryEventTypes)
|
||||
{
|
||||
return _historyRepository.MostRecentForEpisodeInEventCollection(id, episodeHistoryEventTypes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue