Fixed: Reject partial season packs

Fixes #2135
This commit is contained in:
Mark McDowall 2017-08-26 22:55:06 -07:00
parent 58d158a5dc
commit 52ce2c0007
No known key found for this signature in database
GPG Key ID: D4CEFA9A718052E0
5 changed files with 46 additions and 8 deletions

View File

@ -49,27 +49,27 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
{ {
_remoteEpisode.ParsedEpisodeInfo.FullSeason = false; _remoteEpisode.ParsedEpisodeInfo.FullSeason = false;
_remoteEpisode.Episodes.Last().AirDateUtc = DateTime.UtcNow.AddDays(+2); _remoteEpisode.Episodes.Last().AirDateUtc = DateTime.UtcNow.AddDays(+2);
Mocker.Resolve<FullSeasonSpecification>().IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue(); Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue();
} }
[Test] [Test]
public void should_return_true_if_all_episodes_have_aired() public void should_return_true_if_all_episodes_have_aired()
{ {
Mocker.Resolve<FullSeasonSpecification>().IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue(); Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue();
} }
[Test] [Test]
public void should_return_false_if_one_episode_has_not_aired() public void should_return_false_if_one_episode_has_not_aired()
{ {
_remoteEpisode.Episodes.Last().AirDateUtc = DateTime.UtcNow.AddDays(+2); _remoteEpisode.Episodes.Last().AirDateUtc = DateTime.UtcNow.AddDays(+2);
Mocker.Resolve<FullSeasonSpecification>().IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse(); Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse();
} }
[Test] [Test]
public void should_return_false_if_an_episode_does_not_have_an_air_date() public void should_return_false_if_an_episode_does_not_have_an_air_date()
{ {
_remoteEpisode.Episodes.Last().AirDateUtc = null; _remoteEpisode.Episodes.Last().AirDateUtc = null;
Mocker.Resolve<FullSeasonSpecification>().IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse(); Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse();
} }
} }
} }

View File

@ -1,4 +1,4 @@
using FluentAssertions; using FluentAssertions;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
@ -53,5 +53,18 @@ namespace NzbDrone.Core.Test.ParserTests
result.Should().BeNull(); result.Should().BeNull();
} }
[TestCase("The.Ranch.2016.S02.Part.1.1080p.NF.WEBRip.DD5.1.x264-NTb", "The Ranch 2016", 2, 1)]
public void should_parse_partial_season_release(string postTitle, string title, int season, int seasonPart)
{
var result = Parser.Parser.ParseTitle(postTitle);
result.SeasonNumber.Should().Be(season);
result.SeriesTitle.Should().Be(title);
result.EpisodeNumbers.Should().BeEmpty();
result.AbsoluteEpisodeNumbers.Should().BeEmpty();
result.FullSeason.Should().BeFalse();
result.IsPartialSeason.Should().BeTrue();
result.SeasonPart.Should().Be(seasonPart);
}
} }
} }

View File

@ -94,7 +94,14 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
if (localEpisode.Episodes.Empty()) if (localEpisode.Episodes.Empty())
{ {
decision = new ImportDecision(localEpisode, new Rejection("Invalid season or episode")); if (localEpisode.ParsedEpisodeInfo.IsPartialSeason)
{
decision = new ImportDecision(localEpisode, new Rejection("Partial season packs are not supported"));
}
else
{
decision = new ImportDecision(localEpisode, new Rejection("Invalid season or episode"));
}
} }
else else
{ {

View File

@ -1,4 +1,4 @@
using System.Linq; using System.Linq;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Core.Qualities; using NzbDrone.Core.Qualities;
@ -16,9 +16,11 @@ namespace NzbDrone.Core.Parser.Model
public string AirDate { get; set; } public string AirDate { get; set; }
public Language Language { get; set; } public Language Language { get; set; }
public bool FullSeason { get; set; } public bool FullSeason { get; set; }
public bool IsPartialSeason { get; set; }
public bool Special { get; set; } public bool Special { get; set; }
public string ReleaseGroup { get; set; } public string ReleaseGroup { get; set; }
public string ReleaseHash { get; set; } public string ReleaseHash { get; set; }
public int SeasonPart { get; set; }
public ParsedEpisodeInfo() public ParsedEpisodeInfo()
{ {

View File

@ -94,6 +94,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?(?!\\)", 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), 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),
//Mini-Series with year in title, treated as season 1, episodes are labelled as Part01, Part 01, Part.1 //Mini-Series with year in title, treated as season 1, episodes are labelled as Part01, Part 01, Part.1
new Regex(@"^(?<title>.+?\d{4})(?:\W+(?:(?:Part\W?|e)(?<episode>\d{1,2}(?!\d+)))+)", new Regex(@"^(?<title>.+?\d{4})(?:\W+(?:(?:Part\W?|e)(?<episode>\d{1,2}(?!\d+)))+)",
RegexOptions.IgnoreCase | RegexOptions.Compiled), RegexOptions.IgnoreCase | RegexOptions.Compiled),
@ -602,7 +606,19 @@ namespace NzbDrone.Core.Parser
//Todo: Set a "Extras" flag in EpisodeParseResult if we want to download them ever //Todo: Set a "Extras" flag in EpisodeParseResult if we want to download them ever
if (!matchCollection[0].Groups["extras"].Value.IsNullOrWhiteSpace()) return null; if (!matchCollection[0].Groups["extras"].Value.IsNullOrWhiteSpace()) return null;
result.FullSeason = true; // Partial season packs will have a seasonpart group so they can be differentiated
// from a full season/single episode release
var seasonPart = matchCollection[0].Groups["seasonpart"].Value;
if (seasonPart.IsNotNullOrWhiteSpace())
{
result.SeasonPart = Convert.ToInt32(seasonPart);
result.IsPartialSeason = true;
}
else
{
result.FullSeason = true;
}
} }
} }