mirror of
https://github.com/Sonarr/Sonarr.git
synced 2024-12-16 11:37:58 +02:00
Fixed: Do not replace a file unless it contains the same episodes
This commit is contained in:
parent
c08d8252ff
commit
0c6ca6971d
@ -37,5 +37,10 @@ public static bool NotAll<TSource>(this IEnumerable<TSource> source, Func<TSourc
|
|||||||
{
|
{
|
||||||
return !source.All(predicate);
|
return !source.All(predicate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<TResult> SelectList<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> predicate)
|
||||||
|
{
|
||||||
|
return source.Select(predicate).ToList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,76 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using FizzWare.NBuilder;
|
||||||
|
using FluentAssertions;
|
||||||
|
using Moq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Core.DecisionEngine;
|
||||||
|
using NzbDrone.Core.Tv;
|
||||||
|
|
||||||
|
using NzbDrone.Core.Test.Framework;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class SameEpisodesSpecificationFixture : CoreTest<SameEpisodesSpecification>
|
||||||
|
{
|
||||||
|
private List<Episode> _episodes;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
_episodes = Builder<Episode>.CreateListOfSize(2)
|
||||||
|
.All()
|
||||||
|
.With(e => e.EpisodeFileId = 1)
|
||||||
|
.BuildList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GivenEpisodesInFile(List<Episode> episodes)
|
||||||
|
{
|
||||||
|
Mocker.GetMock<IEpisodeService>()
|
||||||
|
.Setup(s => s.GetEpisodesByFileId(It.IsAny<int>()))
|
||||||
|
.Returns(episodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_not_upgrade_when_new_release_contains_less_episodes()
|
||||||
|
{
|
||||||
|
GivenEpisodesInFile(_episodes);
|
||||||
|
|
||||||
|
Subject.IsSatisfiedBy(new List<Episode> { _episodes.First() }).Should().BeFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_upgrade_when_new_release_contains_more_episodes()
|
||||||
|
{
|
||||||
|
GivenEpisodesInFile(new List<Episode> { _episodes.First() });
|
||||||
|
|
||||||
|
Subject.IsSatisfiedBy(_episodes).Should().BeTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_upgrade_when_new_release_contains_the_same_episodes()
|
||||||
|
{
|
||||||
|
GivenEpisodesInFile(_episodes);
|
||||||
|
|
||||||
|
Subject.IsSatisfiedBy(_episodes).Should().BeTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_upgrade_when_release_contains_the_same_episodes_as_multiple_files()
|
||||||
|
{
|
||||||
|
var episodes = Builder<Episode>.CreateListOfSize(2)
|
||||||
|
.BuildList();
|
||||||
|
|
||||||
|
Mocker.GetMock<IEpisodeService>()
|
||||||
|
.Setup(s => s.GetEpisodesByFileId(episodes.First().EpisodeFileId))
|
||||||
|
.Returns(new List<Episode> { episodes.First() });
|
||||||
|
|
||||||
|
Mocker.GetMock<IEpisodeService>()
|
||||||
|
.Setup(s => s.GetEpisodesByFileId(episodes.Last().EpisodeFileId))
|
||||||
|
.Returns(new List<Episode> { episodes.Last() });
|
||||||
|
|
||||||
|
Subject.IsSatisfiedBy(episodes).Should().BeTrue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -147,6 +147,7 @@
|
|||||||
<Compile Include="DecisionEngineTests\RssSync\DelaySpecificationFixture.cs" />
|
<Compile Include="DecisionEngineTests\RssSync\DelaySpecificationFixture.cs" />
|
||||||
<Compile Include="DecisionEngineTests\RssSync\ProperSpecificationFixture.cs" />
|
<Compile Include="DecisionEngineTests\RssSync\ProperSpecificationFixture.cs" />
|
||||||
<Compile Include="DecisionEngineTests\Search\SeriesSpecificationFixture.cs" />
|
<Compile Include="DecisionEngineTests\Search\SeriesSpecificationFixture.cs" />
|
||||||
|
<Compile Include="DecisionEngineTests\SameEpisodesSpecificationFixture.cs" />
|
||||||
<Compile Include="DecisionEngineTests\UpgradeDiskSpecificationFixture.cs" />
|
<Compile Include="DecisionEngineTests\UpgradeDiskSpecificationFixture.cs" />
|
||||||
<Compile Include="Download\CompletedDownloadServiceFixture.cs" />
|
<Compile Include="Download\CompletedDownloadServiceFixture.cs" />
|
||||||
<Compile Include="Download\DownloadApprovedReportsTests\DownloadApprovedFixture.cs" />
|
<Compile Include="Download\DownloadApprovedReportsTests\DownloadApprovedFixture.cs" />
|
||||||
|
@ -30,6 +30,7 @@ public class PathParserFixture : CoreTest
|
|||||||
[TestCase(@"C:\Test\Series\Season 01\1 Pilot (1080p HD).mkv", 1, 1)]
|
[TestCase(@"C:\Test\Series\Season 01\1 Pilot (1080p HD).mkv", 1, 1)]
|
||||||
[TestCase(@"C:\Test\Series\Season 1\02 Honor Thy Father (1080p HD).m4v", 1, 2)]
|
[TestCase(@"C:\Test\Series\Season 1\02 Honor Thy Father (1080p HD).m4v", 1, 2)]
|
||||||
[TestCase(@"C:\Test\Series\Season 1\2 Honor Thy Father (1080p HD).m4v", 1, 2)]
|
[TestCase(@"C:\Test\Series\Season 1\2 Honor Thy Father (1080p HD).m4v", 1, 2)]
|
||||||
|
// [TestCase(@"C:\CSI.NY.S02E04.720p.WEB-DL.DD5.1.H.264\73696S02-04.mkv", 2, 4)] //Gets treated as S01E04 (because it gets parsed as anime)
|
||||||
public void should_parse_from_path(string path, int season, int episode)
|
public void should_parse_from_path(string path, int season, int episode)
|
||||||
{
|
{
|
||||||
var result = Parser.Parser.ParsePath(path.AsOsAgnostic());
|
var result = Parser.Parser.ParsePath(path.AsOsAgnostic());
|
||||||
|
@ -0,0 +1,35 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using NzbDrone.Common.Extensions;
|
||||||
|
using NzbDrone.Core.Tv;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.DecisionEngine
|
||||||
|
{
|
||||||
|
public class SameEpisodesSpecification
|
||||||
|
{
|
||||||
|
private readonly IEpisodeService _episodeService;
|
||||||
|
|
||||||
|
public SameEpisodesSpecification(IEpisodeService episodeService)
|
||||||
|
{
|
||||||
|
_episodeService = episodeService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsSatisfiedBy(List<Episode> episodes)
|
||||||
|
{
|
||||||
|
var episodeIds = episodes.SelectList(e => e.Id);
|
||||||
|
var episodeFileIds = episodes.Where(c => c.EpisodeFileId != 0).Select(c => c.EpisodeFileId).Distinct();
|
||||||
|
|
||||||
|
foreach (var episodeFileId in episodeFileIds)
|
||||||
|
{
|
||||||
|
var episodesInFile = _episodeService.GetEpisodesByFileId(episodeFileId);
|
||||||
|
|
||||||
|
if (episodesInFile.Select(e => e.Id).Except(episodeIds).Any())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
using NLog;
|
||||||
|
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||||
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||||
|
{
|
||||||
|
public class SameEpisodesGrabSpecification : IDecisionEngineSpecification
|
||||||
|
{
|
||||||
|
private readonly SameEpisodesSpecification _sameEpisodesSpecification;
|
||||||
|
private readonly Logger _logger;
|
||||||
|
|
||||||
|
public SameEpisodesGrabSpecification(SameEpisodesSpecification sameEpisodesSpecification, Logger logger)
|
||||||
|
{
|
||||||
|
_sameEpisodesSpecification = sameEpisodesSpecification;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RejectionType Type { get { return RejectionType.Permanent; } }
|
||||||
|
|
||||||
|
public virtual Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria)
|
||||||
|
{
|
||||||
|
if (_sameEpisodesSpecification.IsSatisfiedBy(subject.Episodes))
|
||||||
|
{
|
||||||
|
return Decision.Accept();
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.Debug("Episode file on disk contains more episodes than this release contains");
|
||||||
|
return Decision.Reject("Episode file on disk contains more episodes than this release contains");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
using NLog;
|
||||||
|
using NzbDrone.Core.DecisionEngine;
|
||||||
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
|
||||||
|
{
|
||||||
|
public class SameEpisodesImportSpecification : IImportDecisionEngineSpecification
|
||||||
|
{
|
||||||
|
private readonly SameEpisodesSpecification _sameEpisodesSpecification;
|
||||||
|
private readonly Logger _logger;
|
||||||
|
|
||||||
|
public SameEpisodesImportSpecification(SameEpisodesSpecification sameEpisodesSpecification, Logger logger)
|
||||||
|
{
|
||||||
|
_sameEpisodesSpecification = sameEpisodesSpecification;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RejectionType Type { get { return RejectionType.Permanent; } }
|
||||||
|
|
||||||
|
public Decision IsSatisfiedBy(LocalEpisode localEpisode)
|
||||||
|
{
|
||||||
|
if (_sameEpisodesSpecification.IsSatisfiedBy(localEpisode.Episodes))
|
||||||
|
{
|
||||||
|
return Decision.Accept();
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.Debug("Episode file on disk contains more episodes than this file contains");
|
||||||
|
return Decision.Reject("Episode file on disk contains more episodes than this file contains");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -281,6 +281,7 @@
|
|||||||
<Compile Include="DecisionEngine\QualityUpgradableSpecification.cs" />
|
<Compile Include="DecisionEngine\QualityUpgradableSpecification.cs" />
|
||||||
<Compile Include="DecisionEngine\Rejection.cs" />
|
<Compile Include="DecisionEngine\Rejection.cs" />
|
||||||
<Compile Include="DecisionEngine\RejectionType.cs" />
|
<Compile Include="DecisionEngine\RejectionType.cs" />
|
||||||
|
<Compile Include="DecisionEngine\SameEpisodesSpecification.cs" />
|
||||||
<Compile Include="DecisionEngine\Specifications\AcceptableSizeSpecification.cs" />
|
<Compile Include="DecisionEngine\Specifications\AcceptableSizeSpecification.cs" />
|
||||||
<Compile Include="DecisionEngine\Specifications\BlacklistSpecification.cs" />
|
<Compile Include="DecisionEngine\Specifications\BlacklistSpecification.cs" />
|
||||||
<Compile Include="DecisionEngine\Specifications\AnimeVersionUpgradeSpecification.cs" />
|
<Compile Include="DecisionEngine\Specifications\AnimeVersionUpgradeSpecification.cs" />
|
||||||
@ -303,6 +304,7 @@
|
|||||||
<Compile Include="DecisionEngine\Specifications\Search\SeriesSpecification.cs" />
|
<Compile Include="DecisionEngine\Specifications\Search\SeriesSpecification.cs" />
|
||||||
<Compile Include="DecisionEngine\Specifications\Search\SingleEpisodeSearchMatchSpecification.cs" />
|
<Compile Include="DecisionEngine\Specifications\Search\SingleEpisodeSearchMatchSpecification.cs" />
|
||||||
<Compile Include="DecisionEngine\Specifications\Search\TorrentSeedingSpecification.cs" />
|
<Compile Include="DecisionEngine\Specifications\Search\TorrentSeedingSpecification.cs" />
|
||||||
|
<Compile Include="DecisionEngine\Specifications\SameEpisodesGrabSpecification.cs" />
|
||||||
<Compile Include="DecisionEngine\Specifications\UpgradeDiskSpecification.cs" />
|
<Compile Include="DecisionEngine\Specifications\UpgradeDiskSpecification.cs" />
|
||||||
<Compile Include="DiskSpace\DiskSpace.cs" />
|
<Compile Include="DiskSpace\DiskSpace.cs" />
|
||||||
<Compile Include="DiskSpace\DiskSpaceService.cs" />
|
<Compile Include="DiskSpace\DiskSpaceService.cs" />
|
||||||
@ -582,6 +584,7 @@
|
|||||||
<Compile Include="MediaFiles\EpisodeImport\Specifications\FullSeasonSpecification.cs" />
|
<Compile Include="MediaFiles\EpisodeImport\Specifications\FullSeasonSpecification.cs" />
|
||||||
<Compile Include="MediaFiles\EpisodeImport\Specifications\NotSampleSpecification.cs" />
|
<Compile Include="MediaFiles\EpisodeImport\Specifications\NotSampleSpecification.cs" />
|
||||||
<Compile Include="MediaFiles\EpisodeImport\Specifications\NotUnpackingSpecification.cs" />
|
<Compile Include="MediaFiles\EpisodeImport\Specifications\NotUnpackingSpecification.cs" />
|
||||||
|
<Compile Include="MediaFiles\EpisodeImport\Specifications\SameEpisodesImportSpecification.cs" />
|
||||||
<Compile Include="MediaFiles\EpisodeImport\Specifications\UpgradeSpecification.cs" />
|
<Compile Include="MediaFiles\EpisodeImport\Specifications\UpgradeSpecification.cs" />
|
||||||
<Compile Include="MediaFiles\Events\EpisodeDownloadedEvent.cs" />
|
<Compile Include="MediaFiles\Events\EpisodeDownloadedEvent.cs" />
|
||||||
<Compile Include="MediaFiles\Events\EpisodeFileAddedEvent.cs" />
|
<Compile Include="MediaFiles\Events\EpisodeFileAddedEvent.cs" />
|
||||||
|
Loading…
Reference in New Issue
Block a user