|
|
@ -1,5 +1,6 @@
|
|
|
|
using System;
|
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
using System.IO;
|
|
|
|
using System.IO;
|
|
|
|
using System.Linq;
|
|
|
|
using System.Linq;
|
|
|
|
using System.Text.RegularExpressions;
|
|
|
|
using System.Text.RegularExpressions;
|
|
|
@ -20,6 +21,22 @@ namespace NzbDrone.Core.Parser
|
|
|
|
new Regex(@"^(?<title>.+?)?\W*(?<airyear>\d{4})\W+(?<airmonth>[0-1][0-9])\W+(?<airday>[0-3][0-9])(\W+|_|$)(?!\\)",
|
|
|
|
new Regex(@"^(?<title>.+?)?\W*(?<airyear>\d{4})\W+(?<airmonth>[0-1][0-9])\W+(?<airday>[0-3][0-9])(\W+|_|$)(?!\\)",
|
|
|
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
|
|
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//Anime - Absolute Episode Number + Title + Season+Episode
|
|
|
|
|
|
|
|
new Regex(@"^(?:(?<absoluteepisode>\d{2,3})(?:_|-|\s|\.)+)+(?<title>.+?)(?:\W|_)+(?:S?(?<season>(?<!\d+)\d{1,2}(?!\d+))(?:(?:\-|[ex]|\W[ex]){1,2}(?<episode>\d{2}(?!\d+)))+)",
|
|
|
|
|
|
|
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//Anime - [SubGroup] Title Absolute Episode Number + Season+Episode
|
|
|
|
|
|
|
|
new Regex(@"^(?:\[(?<subgroup>.+?)\](?:_|-|\s|\.))?(?<title>.+?)(?:(?:\W|_)+(?<absoluteepisode>\d{2,3}))+(?:_|-|\s|\.)+(?:S?(?<season>(?<!\d+)\d{1,2}(?!\d+))(?:(?:\-|[ex]|\W[ex]){1,2}(?<episode>\d{2}(?!\d+)))+)",
|
|
|
|
|
|
|
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//Anime - [SubGroup] Title Season+Episode + Absolute Episode Number
|
|
|
|
|
|
|
|
new Regex(@"^(?:\[(?<subgroup>.+?)\](?:_|-|\s|\.))?(?<title>.+?)(?:\W|_)+(?:S?(?<season>(?<!\d+)\d{1,2}(?!\d+))(?:(?:\-|[ex]|\W[ex]){1,2}(?<episode>\d{2}(?!\d+)))+)(?:\s|\.)(?:(?<absoluteepisode>\d{2,3})(?:_|-|\s|\.|$)+)+",
|
|
|
|
|
|
|
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//Anime - [SubGroup] Title Absolute Episode Number
|
|
|
|
|
|
|
|
new Regex(@"^\[(?<subgroup>.+?)\](?:_|-|\s|\.)?(?<title>.+?)(?:(?:\W|_)+(?<absoluteepisode>\d{2,}))+",
|
|
|
|
|
|
|
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
|
|
|
|
|
|
|
|
|
|
|
//Multi-Part episodes without a title (S01E05.S01E06)
|
|
|
|
//Multi-Part episodes without a title (S01E05.S01E06)
|
|
|
|
new Regex(@"^(?:\W*S?(?<season>(?<!\d+)\d{1,2}(?!\d+))(?:(?:[ex]){1,2}(?<episode>\d{1,3}(?!\d+)))+){2,}(\W+|_|$)(?!\\)",
|
|
|
|
new Regex(@"^(?:\W*S?(?<season>(?<!\d+)\d{1,2}(?!\d+))(?:(?:[ex]){1,2}(?<episode>\d{1,3}(?!\d+)))+){2,}(\W+|_|$)(?!\\)",
|
|
|
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
|
|
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
|
|
@ -44,6 +61,10 @@ namespace NzbDrone.Core.Parser
|
|
|
|
new Regex(@"^(?<title>.*?)(?:\W?S?(?<season>(?<!\d+)\d{1,2}(?!\d+))(?:(?:\-|[ex]){1,2}(?<episode>\d{1}))+)+(\W+|_|$)(?!\\)",
|
|
|
|
new Regex(@"^(?<title>.*?)(?:\W?S?(?<season>(?<!\d+)\d{1,2}(?!\d+))(?:(?:\-|[ex]){1,2}(?<episode>\d{1}))+)+(\W+|_|$)(?!\\)",
|
|
|
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
|
|
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//Anime - Title Absolute Episode Number [SubGroup]
|
|
|
|
|
|
|
|
new Regex(@"^(?<title>.+?)(?:(?:_|-|\s|\.)+(?<absoluteepisode>\d{2,3}))+(?:.+?)\[(?<subgroup>.+?)\](?:\.|$)",
|
|
|
|
|
|
|
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
|
|
|
|
|
|
|
|
|
|
|
//Supports 103/113 naming
|
|
|
|
//Supports 103/113 naming
|
|
|
|
new Regex(@"^(?<title>.+?)?(?:\W?(?<season>(?<!\d+)\d{1})(?<episode>\d{2}(?!p|i|\d+)))+(\W+|_|$)(?!\\)",
|
|
|
|
new Regex(@"^(?<title>.+?)?(?:\W?(?<season>(?<!\d+)\d{1})(?<episode>\d{2}(?!p|i|\d+)))+(\W+|_|$)(?!\\)",
|
|
|
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
|
|
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
|
|
@ -53,7 +74,7 @@ namespace NzbDrone.Core.Parser
|
|
|
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
|
|
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
|
|
|
|
|
|
|
|
|
|
|
//Supports 1103/1113 naming
|
|
|
|
//Supports 1103/1113 naming
|
|
|
|
new Regex(@"^(?<title>.+?)?(?:\W?(?<season>(?<!\d+|\(|\[)\d{2})(?<episode>\d{2}(?!p|i|\d+|\)|\]|\W\d+)))+(\W+|_|$)(?!\\)",
|
|
|
|
new Regex(@"^(?<title>.+?)?(?:\W?(?<season>(?<!\d+|\(|\[|e|x)\d{2})(?<episode>(?<!e|x)\d{2}(?!p|i|\d+|\)|\]|\W\d+)))+(\W+|_|$)(?!\\)",
|
|
|
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
|
|
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
|
|
|
|
|
|
|
|
|
|
|
//Supports Season 01 Episode 03
|
|
|
|
//Supports Season 01 Episode 03
|
|
|
@ -62,7 +83,20 @@ namespace NzbDrone.Core.Parser
|
|
|
|
|
|
|
|
|
|
|
|
//Supports Season only releases
|
|
|
|
//Supports Season only releases
|
|
|
|
new Regex(@"^(?<title>.+?)\W(?:S|Season)\W?(?<season>\d{1,2}(?!\d+))(\W+|_|$)(?<extras>EXTRAS|SUBPACK)?(?!\\)",
|
|
|
|
new Regex(@"^(?<title>.+?)\W(?:S|Season)\W?(?<season>\d{1,2}(?!\d+))(\W+|_|$)(?<extras>EXTRAS|SUBPACK)?(?!\\)",
|
|
|
|
RegexOptions.IgnoreCase | RegexOptions.Compiled)
|
|
|
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//4-digit episode number
|
|
|
|
|
|
|
|
//Episodes without a title, Single (S01E05, 1x05) AND Multi (S01E04E05, 1x04x05, etc)
|
|
|
|
|
|
|
|
new Regex(@"^(?:S?(?<season>(?<!\d+)\d{1,2}(?!\d+))(?:(?:\-|[ex]|\W[ex]|_){1,2}(?<episode>\d{4}(?!\d+|i|p)))+)(\W+|_|$)(?!\\)",
|
|
|
|
|
|
|
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//Episodes with a title, Single episodes (S01E05, 1x05, etc) & Multi-episode (S01E05E06, S01E05-06, S01E05 E06, etc)
|
|
|
|
|
|
|
|
new Regex(@"^(?<title>.+?)(?:(\W|_)+S?(?<season>(?<!\d+)\d{1,2}(?!\d+))(?:(?:\-|[ex]|\W[ex]|_){1,2}(?<episode>\d{4}(?!\d+|i|p)))+)\W?(?!\\)",
|
|
|
|
|
|
|
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//Anime - Title Absolute Episode Number
|
|
|
|
|
|
|
|
new Regex(@"^(?<title>.+?)(?:(?:_|-|\s|\.)+e(?<absoluteepisode>\d{2,3}))+",
|
|
|
|
|
|
|
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
private static readonly Regex NormalizeRegex = new Regex(@"((^|\W|_)(a|an|the|and|or|of)($|\W|_))|\W|_|(?:(?<=[^0-9]+)|\b)(?!(?:19\d{2}|20\d{2}))\d+(?=[^0-9ip]+|\b)",
|
|
|
|
private static readonly Regex NormalizeRegex = new Regex(@"((^|\W|_)(a|an|the|and|or|of)($|\W|_))|\W|_|(?:(?<=[^0-9]+)|\b)(?!(?:19\d{2}|20\d{2}))\d+(?=[^0-9ip]+|\b)",
|
|
|
@ -114,6 +148,7 @@ namespace NzbDrone.Core.Parser
|
|
|
|
|
|
|
|
|
|
|
|
if (match.Count != 0)
|
|
|
|
if (match.Count != 0)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
Debug.WriteLine(regex);
|
|
|
|
try
|
|
|
|
try
|
|
|
|
{
|
|
|
|
{
|
|
|
|
var result = ParseMatchCollection(match);
|
|
|
|
var result = ParseMatchCollection(match);
|
|
|
@ -226,11 +261,13 @@ namespace NzbDrone.Core.Parser
|
|
|
|
{
|
|
|
|
{
|
|
|
|
SeasonNumber = seasons.First(),
|
|
|
|
SeasonNumber = seasons.First(),
|
|
|
|
EpisodeNumbers = new int[0],
|
|
|
|
EpisodeNumbers = new int[0],
|
|
|
|
|
|
|
|
AbsoluteEpisodeNumbers = new int[0]
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
foreach (Match matchGroup in matchCollection)
|
|
|
|
foreach (Match matchGroup in matchCollection)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
var episodeCaptures = matchGroup.Groups["episode"].Captures.Cast<Capture>().ToList();
|
|
|
|
var episodeCaptures = matchGroup.Groups["episode"].Captures.Cast<Capture>().ToList();
|
|
|
|
|
|
|
|
var absoluteEpisodeCaptures = matchGroup.Groups["absoluteepisode"].Captures.Cast<Capture>().ToList();
|
|
|
|
|
|
|
|
|
|
|
|
//Allows use to return a list of 0 episodes (We can handle that as a full season release)
|
|
|
|
//Allows use to return a list of 0 episodes (We can handle that as a full season release)
|
|
|
|
if (episodeCaptures.Any())
|
|
|
|
if (episodeCaptures.Any())
|
|
|
@ -246,6 +283,20 @@ namespace NzbDrone.Core.Parser
|
|
|
|
var count = last - first + 1;
|
|
|
|
var count = last - first + 1;
|
|
|
|
result.EpisodeNumbers = Enumerable.Range(first, count).ToArray();
|
|
|
|
result.EpisodeNumbers = Enumerable.Range(first, count).ToArray();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (absoluteEpisodeCaptures.Any())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
var first = Convert.ToInt32(absoluteEpisodeCaptures.First().Value);
|
|
|
|
|
|
|
|
var last = Convert.ToInt32(absoluteEpisodeCaptures.Last().Value);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (first > last)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var count = last - first + 1;
|
|
|
|
|
|
|
|
result.AbsoluteEpisodeNumbers = Enumerable.Range(first, count).ToArray();
|
|
|
|
|
|
|
|
}
|
|
|
|
else
|
|
|
|
else
|
|
|
|
{
|
|
|
|
{
|
|
|
|
//Check to see if this is an "Extras" or "SUBPACK" release, if it is, return NULL
|
|
|
|
//Check to see if this is an "Extras" or "SUBPACK" release, if it is, return NULL
|
|
|
@ -256,6 +307,10 @@ namespace NzbDrone.Core.Parser
|
|
|
|
result.FullSeason = true;
|
|
|
|
result.FullSeason = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (result.AbsoluteEpisodeNumbers.Any() && !result.EpisodeNumbers.Any())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
result.SeasonNumber = 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
else
|
|
|
|
else
|
|
|
|