New: Reject multi-season releases

Closes #683
This commit is contained in:
Mark McDowall 2019-04-27 18:27:05 -07:00
parent a9a3e50179
commit 7991ed0154
8 changed files with 118 additions and 4 deletions

View File

@ -0,0 +1,61 @@

using System;
using NUnit.Framework;
using NzbDrone.Core.DecisionEngine.Specifications;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Test.Framework;
using FizzWare.NBuilder;
using System.Linq;
using FluentAssertions;
using NzbDrone.Core.Tv;
using Moq;
using System.Collections.Generic;
namespace NzbDrone.Core.Test.DecisionEngineTests
{
[TestFixture]
public class MultiSeasonSpecificationFixture : CoreTest<MultiSeasonSpecification>
{
private RemoteEpisode _remoteEpisode;
[SetUp]
public void Setup()
{
var series = Builder<Series>.CreateNew().With(s => s.Id = 1234).Build();
_remoteEpisode = new RemoteEpisode
{
ParsedEpisodeInfo = new ParsedEpisodeInfo
{
FullSeason = true,
IsMultiSeason = true
},
Episodes = Builder<Episode>.CreateListOfSize(3)
.All()
.With(s => s.SeriesId = series.Id)
.BuildList(),
Series = series,
Release = new ReleaseInfo
{
Title = "Series.Title.S01-05.720p.BluRay.X264-RlsGrp"
}
};
Mocker.GetMock<IEpisodeService>().Setup(s => s.EpisodesBetweenDates(It.IsAny<DateTime>(), It.IsAny<DateTime>(), false))
.Returns(new List<Episode>());
}
[Test]
public void should_return_true_if_is_not_a_multi_season_release()
{
_remoteEpisode.ParsedEpisodeInfo.IsMultiSeason = false;
_remoteEpisode.Episodes.Last().AirDateUtc = DateTime.UtcNow.AddDays(+2);
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue();
}
[Test]
public void should_return_false_if_is_a_multi_season_release()
{
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse();
}
}
}

View File

@ -159,6 +159,7 @@
<Compile Include="Datastore\SqliteSchemaDumperTests\SqliteSchemaDumperFixture.cs" />
<Compile Include="DecisionEngineTests\AcceptableSizeSpecificationFixture.cs" />
<Compile Include="DecisionEngineTests\AnimeVersionUpgradeSpecificationFixture.cs" />
<Compile Include="DecisionEngineTests\MultiSeasonSpecificationFixture.cs" />
<Compile Include="DecisionEngineTests\UpgradeAllowedSpecificationFixture .cs" />
<Compile Include="DecisionEngineTests\FullSeasonSpecificationFixture.cs" />
<Compile Include="DecisionEngineTests\MaximumSizeSpecificationFixture.cs" />

View File

@ -76,5 +76,18 @@ namespace NzbDrone.Core.Test.ParserTests
result.IsPartialSeason.Should().BeTrue();
result.SeasonPart.Should().Be(seasonPart);
}
[TestCase("The Wire S01-05 WS BDRip X264-REWARD-No Rars", "The Wire", 1)]
public void should_parse_multi_season_release(string postTitle, string title, int firstSeason)
{
var result = Parser.Parser.ParseTitle(postTitle);
result.SeasonNumber.Should().Be(firstSeason);
result.SeriesTitle.Should().Be(title);
result.EpisodeNumbers.Should().BeEmpty();
result.AbsoluteEpisodeNumbers.Should().BeEmpty();
result.FullSeason.Should().BeTrue();
result.IsPartialSeason.Should().BeFalse();
result.IsMultiSeason.Should().BeTrue();
}
}
}

View File

@ -4,7 +4,6 @@ using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Common.Extensions;
using System.Linq;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.DecisionEngine.Specifications
{

View File

@ -0,0 +1,30 @@
using NLog;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.DecisionEngine.Specifications
{
public class MultiSeasonSpecification : IDecisionEngineSpecification
{
private readonly Logger _logger;
public MultiSeasonSpecification(Logger logger)
{
_logger = logger;
}
public SpecificationPriority Priority => SpecificationPriority.Default;
public RejectionType Type => RejectionType.Permanent;
public virtual Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria)
{
if (subject.ParsedEpisodeInfo.IsMultiSeason)
{
_logger.Debug("Multi-season release {0} rejected. Not supported", subject.Release.Title);
return Decision.Reject("Multi-season releases are not supported");
}
return Decision.Accept();
}
}
}

View File

@ -145,6 +145,7 @@
<Compile Include="CustomFilters\CustomFilterService.cs" />
<Compile Include="Datastore\Migration\127_rename_release_profiles.cs" />
<Compile Include="Datastore\Migration\126_add_custom_filters.cs" />
<Compile Include="DecisionEngine\Specifications\MultiSeasonSpecification.cs" />
<Compile Include="DecisionEngine\Specifications\UpgradeAllowedSpecification.cs" />
<Compile Include="Exceptions\SearchFailedException.cs" />
<Compile Include="Extras\Metadata\MetadataSectionType.cs" />

View File

@ -19,6 +19,7 @@ namespace NzbDrone.Core.Parser.Model
public Language Language { get; set; }
public bool FullSeason { get; set; }
public bool IsPartialSeason { get; set; }
public bool IsMultiSeason { get; set; }
public bool IsSeasonExtra { get; set; }
public bool Special { get; set; }
public string ReleaseGroup { get; set; }

View File

@ -128,6 +128,10 @@ namespace NzbDrone.Core.Parser
new Regex(@"^(?<title>.+?)(?:(?:[-_\W](?<![()\[!]))+(?<season>(?<!\d+)(?:\d{4})(?!\d+))(?:x|\Wx){1,2}(?<episode>\d{2,3}(?!\d+))(?:(?:\-|x|\Wx|_){1,2}(?<episode>\d{2,3}(?!\d+)))*)\W?(?!\\)",
RegexOptions.IgnoreCase | RegexOptions.Compiled),
// Multi-season pack
new Regex(@"^(?<title>.+?)[-_. ]+S(?<season>(?<!\d+)(?:\d{1,2})(?!\d+))-(?<season>(?<!\d+)(?:\d{1,2})(?!\d+))",
RegexOptions.IgnoreCase | RegexOptions.Compiled),
// Partial season pack
new Regex(@"^(?<title>.+?)(?:\W+S(?<season>(?<!\d+)(?:\d{1,2})(?!\d+))\W+(?:(?:Part\W?|(?<!\d+\W+)e)(?<seasonpart>\d{1,2}(?!\d+)))+)",
RegexOptions.IgnoreCase | RegexOptions.Compiled),
@ -684,9 +688,6 @@ namespace NzbDrone.Core.Parser
//If no season was found it should be treated as a mini series and season 1
if (seasons.Count == 0) seasons.Add(1);
//If more than 1 season was parsed go to the next REGEX (A multi-season release is unlikely)
if (seasons.Distinct().Count() > 1) return null;
result = new ParsedEpisodeInfo
{
ReleaseTitle = releaseTitle,
@ -695,6 +696,13 @@ namespace NzbDrone.Core.Parser
AbsoluteEpisodeNumbers = new int[0]
};
//If more than 1 season was parsed set IsMultiSeason to true so it can be rejected later
if (seasons.Distinct().Count() > 1)
{
result.IsMultiSeason = true;
}
foreach (Match matchGroup in matchCollection)
{
var episodeCaptures = matchGroup.Groups["episode"].Captures.Cast<Capture>().ToList();