Don't reject for having the same file size

Fixed: Remove same file size rejection during import
Fixed: Reject imports for non-season pack files if quality of file doesn't match grabbed quality
Closes #3691
This commit is contained in:
Mark McDowall 2020-04-20 17:58:59 -07:00
parent f2a56b29d9
commit be3b3df903
5 changed files with 168 additions and 165 deletions

View File

@ -0,0 +1,106 @@
using System.Collections.Generic;
using FizzWare.NBuilder;
using FluentAssertions;
using Marr.Data;
using Moq;
using NUnit.Framework;
using NzbDrone.Core.Download;
using NzbDrone.Core.History;
using NzbDrone.Core.MediaFiles.EpisodeImport.Specifications;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Profiles.Qualities;
using NzbDrone.Core.Qualities;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications
{
[TestFixture]
public class DifferentQualitySpecificationFixture : CoreTest<DifferentQualitySpecification>
{
private LocalEpisode _localEpisode;
private DownloadClientItem _downloadClientItem;
[SetUp]
public void Setup()
{
var qualityProfile = new QualityProfile
{
Cutoff = Quality.Bluray1080p.Id,
Items = Qualities.QualityFixture.GetDefaultQualities(Quality.DVD, Quality.HDTV720p, Quality.Bluray1080p)
};
var fakeSeries = Builder<Series>.CreateNew()
.With(c => c.QualityProfile = qualityProfile)
.Build();
_localEpisode = Builder<LocalEpisode>.CreateNew()
.With(l => l.Quality = new QualityModel(Quality.Bluray1080p))
.With(l => l.DownloadClientEpisodeInfo = new ParsedEpisodeInfo())
.With(l => l.Series = fakeSeries)
.Build();
_downloadClientItem = Builder<DownloadClientItem>.CreateNew()
.Build();
}
private void GivenGrabbedEpisodeHistory(QualityModel quality)
{
var history = Builder<EpisodeHistory>.CreateListOfSize(1)
.TheFirst(1)
.With(h => h.Quality = quality)
.With(h => h.EventType = EpisodeHistoryEventType.Grabbed)
.BuildList();
Mocker.GetMock<IHistoryService>()
.Setup(s => s.FindByDownloadId(It.IsAny<string>()))
.Returns(history);
}
[Test]
public void should_be_accepted_if_no_download_client_item()
{
Subject.IsSatisfiedBy(_localEpisode, null).Accepted.Should().BeTrue();
}
[Test]
public void should_be_accepted_if_quality_does_not_match_for_full_season_pack()
{
GivenGrabbedEpisodeHistory(new QualityModel(Quality.SDTV));
_localEpisode.DownloadClientEpisodeInfo.FullSeason = true;
Subject.IsSatisfiedBy(_localEpisode, _downloadClientItem).Accepted.Should().BeTrue();
}
[Test]
public void should_be_accepted_if_no_grabbed_episode_history()
{
Mocker.GetMock<IHistoryService>()
.Setup(s => s.FindByDownloadId(It.IsAny<string>()))
.Returns(new List<EpisodeHistory>());
_localEpisode.Episodes = Builder<Episode>.CreateListOfSize(1)
.TheFirst(1)
.With(e => e.EpisodeFileId = 0)
.BuildList();
Subject.IsSatisfiedBy(_localEpisode, _downloadClientItem).Accepted.Should().BeTrue();
}
[Test]
public void should_be_accepted_if_quality_matches()
{
GivenGrabbedEpisodeHistory(_localEpisode.Quality);
Subject.IsSatisfiedBy(_localEpisode, _downloadClientItem).Accepted.Should().BeTrue();
}
[Test]
public void should_be_rejected_if_quality_does_not_match()
{
GivenGrabbedEpisodeHistory(new QualityModel(Quality.SDTV));
Subject.IsSatisfiedBy(_localEpisode, _downloadClientItem).Accepted.Should().BeFalse();
}
}
}

View File

@ -1,110 +0,0 @@
using System.Linq;
using FizzWare.NBuilder;
using FluentAssertions;
using Marr.Data;
using NUnit.Framework;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.MediaFiles.EpisodeImport.Specifications;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications
{
[TestFixture]
public class SameFileSpecificationFixture : CoreTest<SameFileSpecification>
{
private LocalEpisode _localEpisode;
[SetUp]
public void Setup()
{
_localEpisode = Builder<LocalEpisode>.CreateNew()
.With(l => l.Size = 150.Megabytes())
.Build();
}
[Test]
public void should_be_accepted_if_no_existing_file()
{
_localEpisode.Episodes = Builder<Episode>.CreateListOfSize(1)
.TheFirst(1)
.With(e => e.EpisodeFileId = 0)
.BuildList();
Subject.IsSatisfiedBy(_localEpisode, null).Accepted.Should().BeTrue();
}
[Test]
public void should_be_accepted_if_multiple_existing_files()
{
_localEpisode.Episodes = Builder<Episode>.CreateListOfSize(2)
.TheFirst(1)
.With(e => e.EpisodeFileId = 1)
.With(e => e.EpisodeFile = new LazyLoaded<EpisodeFile>(
new EpisodeFile
{
Size = _localEpisode.Size
}))
.TheNext(1)
.With(e => e.EpisodeFileId = 2)
.With(e => e.EpisodeFile = new LazyLoaded<EpisodeFile>(
new EpisodeFile
{
Size = _localEpisode.Size
}))
.Build()
.ToList();
Subject.IsSatisfiedBy(_localEpisode, null).Accepted.Should().BeTrue();
}
[Test]
public void should_be_accepted_if_file_size_is_different()
{
_localEpisode.Episodes = Builder<Episode>.CreateListOfSize(1)
.TheFirst(1)
.With(e => e.EpisodeFileId = 1)
.With(e => e.EpisodeFile = new LazyLoaded<EpisodeFile>(
new EpisodeFile
{
Size = _localEpisode.Size + 100.Megabytes()
}))
.Build()
.ToList();
Subject.IsSatisfiedBy(_localEpisode, null).Accepted.Should().BeTrue();
}
[Test]
public void should_be_reject_if_file_size_is_the_same()
{
_localEpisode.Episodes = Builder<Episode>.CreateListOfSize(1)
.TheFirst(1)
.With(e => e.EpisodeFileId = 1)
.With(e => e.EpisodeFile = new LazyLoaded<EpisodeFile>(
new EpisodeFile
{
Size = _localEpisode.Size
}))
.Build()
.ToList();
Subject.IsSatisfiedBy(_localEpisode, null).Accepted.Should().BeFalse();
}
[Test]
public void should_be_accepted_if_file_cannot_be_fetched()
{
_localEpisode.Episodes = Builder<Episode>.CreateListOfSize(1)
.TheFirst(1)
.With(e => e.EpisodeFileId = 1)
.With(e => e.EpisodeFile = new LazyLoaded<EpisodeFile>((EpisodeFile)null))
.Build()
.ToList();
Subject.IsSatisfiedBy(_localEpisode, null).Accepted.Should().BeTrue();
}
}
}

View File

@ -26,14 +26,15 @@ namespace NzbDrone.Core.Download
public bool IgnoreDownload(TrackedDownload trackedDownload)
{
var series = trackedDownload.RemoteEpisode.Series;
var episodes = trackedDownload.RemoteEpisode.Episodes;
if (series == null || episodes.Empty())
if (series == null)
{
_logger.Warn("Unable to ignore download for unknown series/episode");
_logger.Warn("Unable to ignore download for unknown series");
return false;
}
var episodes = trackedDownload.RemoteEpisode.Episodes;
var downloadIgnoredEvent = new DownloadIgnoredEvent
{
SeriesId = series.Id,

View File

@ -0,0 +1,58 @@
using System.Linq;
using NLog;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Download;
using NzbDrone.Core.History;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Qualities;
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
{
public class DifferentQualitySpecification : IImportDecisionEngineSpecification
{
private readonly IHistoryService _historyService;
private readonly Logger _logger;
public DifferentQualitySpecification(IHistoryService historyService, Logger logger)
{
_historyService = historyService;
_logger = logger;
}
public Decision IsSatisfiedBy(LocalEpisode localEpisode, DownloadClientItem downloadClientItem)
{
if (downloadClientItem == null)
{
_logger.Debug("No download client item, skipping");
return Decision.Accept();
}
if (localEpisode.DownloadClientEpisodeInfo?.FullSeason == true)
{
_logger.Debug("Full season download, skipping");
return Decision.Accept();
}
var test = _historyService.FindByDownloadId(downloadClientItem.DownloadId);
var grabbedEpisodeHistory = _historyService.FindByDownloadId(downloadClientItem.DownloadId)
.OrderByDescending(h => h.Date)
.FirstOrDefault(h => h.EventType == EpisodeHistoryEventType.Grabbed);
if (grabbedEpisodeHistory == null)
{
_logger.Debug("No grabbed history for this download item, skipping");
return Decision.Accept();
}
var qualityComparer = new QualityModelComparer(localEpisode.Series.QualityProfile);
var qualityCompare = qualityComparer.Compare(localEpisode.Quality, grabbedEpisodeHistory.Quality);
if (qualityCompare != 0)
{
_logger.Debug("Quality of file ({0}) does not match quality of grabbed history ({1})", localEpisode.Quality, grabbedEpisodeHistory.Quality);
return Decision.Reject("Not an upgrade for existing episode file(s)");
}
return Decision.Accept();
}
}
}

View File

@ -1,52 +0,0 @@
using System.Linq;
using NLog;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Download;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
{
public class SameFileSpecification : IImportDecisionEngineSpecification
{
private readonly Logger _logger;
public SameFileSpecification(Logger logger)
{
_logger = logger;
}
public Decision IsSatisfiedBy(LocalEpisode localEpisode, DownloadClientItem downloadClientItem)
{
var episodeFiles = localEpisode.Episodes.Where(e => e.EpisodeFileId != 0).Select(e => e.EpisodeFile).ToList();
if (episodeFiles.Count == 0)
{
_logger.Debug("No existing episode file, skipping");
return Decision.Accept();
}
if (episodeFiles.Count > 1)
{
_logger.Debug("More than one existing episode file, skipping.");
return Decision.Accept();
}
var episodeFile = episodeFiles.First().Value;
if (episodeFile == null)
{
var episode = localEpisode.Episodes.First();
_logger.Trace("Unable to get episode file details from the DB. EpisodeId: {0} EpisodeFileId: {1}", episode.Id, episode.EpisodeFileId);
return Decision.Accept();
}
if (episodeFiles.First().Value.Size == localEpisode.Size)
{
_logger.Debug("'{0}' Has the same filesize as existing file", localEpisode.Path);
return Decision.Reject("Has the same filesize as existing file");
}
return Decision.Accept();
}
}
}