New: Parse and reject split episode releases and files
This commit is contained in:
parent
f722d49b3a
commit
895eccebc5
|
@ -211,5 +211,19 @@ namespace NzbDrone.Core.Test.ParserTests
|
||||||
result.FullSeason.Should().BeFalse();
|
result.FullSeason.Should().BeFalse();
|
||||||
result.Special.Should().BeTrue();
|
result.Special.Should().BeTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestCase("Series.Title.S06E01b.Fade.Out.Fade.in.Part.2.1080p.DSNP.WEB-DL.AAC2.0.H.264-FLUX", "Series Title", 6, 1)]
|
||||||
|
public void should_parse_split_episode(string postTitle, string title, int seasonNumber, int episodeNumber)
|
||||||
|
{
|
||||||
|
var result = Parser.Parser.ParseTitle(postTitle);
|
||||||
|
result.Should().NotBeNull();
|
||||||
|
result.EpisodeNumbers.Should().HaveCount(1);
|
||||||
|
result.SeasonNumber.Should().Be(seasonNumber);
|
||||||
|
result.EpisodeNumbers.First().Should().Be(episodeNumber);
|
||||||
|
result.SeriesTitle.Should().Be(title);
|
||||||
|
result.AbsoluteEpisodeNumbers.Should().BeEmpty();
|
||||||
|
result.FullSeason.Should().BeFalse();
|
||||||
|
result.IsSplitEpisode.Should().BeTrue();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
using NLog;
|
||||||
|
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||||
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||||
|
{
|
||||||
|
public class SplitEpisodeSpecification : IDecisionEngineSpecification
|
||||||
|
{
|
||||||
|
private readonly Logger _logger;
|
||||||
|
|
||||||
|
public SplitEpisodeSpecification(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.IsSplitEpisode)
|
||||||
|
{
|
||||||
|
_logger.Debug("Split episode release {0} rejected. Not supported", subject.Release.Title);
|
||||||
|
return Decision.Reject("Split episode releases are not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Decision.Accept();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
using NLog;
|
||||||
|
using NzbDrone.Core.DecisionEngine;
|
||||||
|
using NzbDrone.Core.Download;
|
||||||
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
|
||||||
|
{
|
||||||
|
public class SplitEpisodeSpecification : IImportDecisionEngineSpecification
|
||||||
|
{
|
||||||
|
private readonly Logger _logger;
|
||||||
|
|
||||||
|
public SplitEpisodeSpecification(Logger logger)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Decision IsSatisfiedBy(LocalEpisode localEpisode, DownloadClientItem downloadClientItem)
|
||||||
|
{
|
||||||
|
if (localEpisode.FileEpisodeInfo == null)
|
||||||
|
{
|
||||||
|
return Decision.Accept();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (localEpisode.FileEpisodeInfo.IsSplitEpisode)
|
||||||
|
{
|
||||||
|
_logger.Debug("Single episode split into multiple files");
|
||||||
|
return Decision.Reject("Single episode split into multiple files");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Decision.Accept();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,6 +23,7 @@ namespace NzbDrone.Core.Parser.Model
|
||||||
public bool IsPartialSeason { get; set; }
|
public bool IsPartialSeason { get; set; }
|
||||||
public bool IsMultiSeason { get; set; }
|
public bool IsMultiSeason { get; set; }
|
||||||
public bool IsSeasonExtra { get; set; }
|
public bool IsSeasonExtra { get; set; }
|
||||||
|
public bool IsSplitEpisode { 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; }
|
||||||
|
|
|
@ -74,6 +74,10 @@ namespace NzbDrone.Core.Parser
|
||||||
new Regex(@"^(?:S?(?<season>(?<!\d+)(?:\d{1,2}|\d{4})(?!\d+))(?:(?:[-_]|[ex]){1,2}(?<episode>\d{2,3}(?!\d+))){2,})",
|
new Regex(@"^(?:S?(?<season>(?<!\d+)(?:\d{1,2}|\d{4})(?!\d+))(?:(?:[-_]|[ex]){1,2}(?<episode>\d{2,3}(?!\d+))){2,})",
|
||||||
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
||||||
|
|
||||||
|
// Split episodes (S01E05a, S01E05b, etc)
|
||||||
|
new Regex(@"^(?<title>.+?)(?:S?(?<season>(?<!\d+)(?:\d{1,2}|\d{4})(?!\d+))(?:(?:[-_ ]?[ex])(?<episode>\d{2,3}(?!\d+))(?<splitepisode>[a-d])(?:[ _.])))",
|
||||||
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
||||||
|
|
||||||
// Episodes without a title, Single (S01E05, 1x05)
|
// Episodes without a title, Single (S01E05, 1x05)
|
||||||
new Regex(@"^(?:S?(?<season>(?<!\d+)(?:\d{1,2}|\d{4})(?!\d+))(?:(?:[-_ ]?[ex])(?<episode>\d{2,3}(?!\d+))))",
|
new Regex(@"^(?:S?(?<season>(?<!\d+)(?:\d{1,2}|\d{4})(?!\d+))(?:(?:[-_ ]?[ex])(?<episode>\d{2,3}(?!\d+))))",
|
||||||
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
||||||
|
@ -966,6 +970,11 @@ namespace NzbDrone.Core.Parser
|
||||||
{
|
{
|
||||||
result.Special = true;
|
result.Special = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (matchGroup.Groups["splitepisode"].Success)
|
||||||
|
{
|
||||||
|
result.IsSplitEpisode = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (absoluteEpisodeCaptures.Any())
|
if (absoluteEpisodeCaptures.Any())
|
||||||
|
|
Loading…
Reference in New Issue