|
|
@ -43,7 +43,7 @@ namespace NzbDrone.Core.Parser
|
|
|
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
|
|
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
|
|
|
|
|
|
|
|
|
|
|
//Episodes without a title, Single (S01E05, 1x05) AND Multi (S01E04E05, 1x04x05, etc)
|
|
|
|
//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{2,3}(?!\d+)))+(?![\da-z]))",
|
|
|
|
new Regex(@"^(?:S?(?<season>(?<!\d+)\d{1,2}(?!\d+))(?:(?:\-|[ex]|\W[ex]|_){1,2}(?<episode>\d{2,3}(?!\d+)))+)",
|
|
|
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
|
|
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
|
|
|
|
|
|
|
|
|
|
|
//Episodes with a title, Single episodes (S01E05, 1x05, etc) & Multi-episode (S01E05E06, S01E05-06, S01E05 E06, etc)
|
|
|
|
//Episodes with a title, Single episodes (S01E05, 1x05, etc) & Multi-episode (S01E05E06, S01E05-06, S01E05 E06, etc)
|
|
|
@ -92,7 +92,7 @@ namespace NzbDrone.Core.Parser
|
|
|
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
|
|
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
|
|
|
|
|
|
|
|
|
|
|
//Episodes with a title, Single episodes (S01E05, 1x05, etc) & Multi-episode (S01E05E06, S01E05-06, S01E05 E06, etc)
|
|
|
|
//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)))+(?![\da-z]))\W?(?!\\)",
|
|
|
|
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),
|
|
|
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
|
|
|
|
|
|
|
|
|
|
|
//Anime - Title Absolute Episode Number
|
|
|
|
//Anime - Title Absolute Episode Number
|
|
|
@ -100,6 +100,18 @@ namespace NzbDrone.Core.Parser
|
|
|
|
RegexOptions.IgnoreCase | RegexOptions.Compiled)
|
|
|
|
RegexOptions.IgnoreCase | RegexOptions.Compiled)
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static readonly Regex[] RejectHashedReleasesRegex = new Regex[]
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
// Generic match for md5 and mixed-case hashes.
|
|
|
|
|
|
|
|
new Regex(@"^[0-9a-zA-Z]{32}", RegexOptions.Compiled),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Format seen on some NZBGeek releases
|
|
|
|
|
|
|
|
new Regex(@"^[A-Z]{11}\d{3}$", RegexOptions.Compiled)
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//Regex to detect whether the title was reversed.
|
|
|
|
|
|
|
|
private static readonly Regex ReversedTitleRegex = new Regex(@"\.p027\.|\.p0801\.|\.\d{2}E\d{2}S\.", RegexOptions.Compiled);
|
|
|
|
|
|
|
|
|
|
|
|
private static readonly Regex NormalizeRegex = new Regex(@"((?:\b|_)(?<!^)(a|an|the|and|or|of)(?:\b|_))|\W|_",
|
|
|
|
private static readonly Regex NormalizeRegex = new Regex(@"((?:\b|_)(?<!^)(a|an|the|and|or|of)(?:\b|_))|\W|_",
|
|
|
|
RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
|
|
|
RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
|
|
|
|
|
|
|
|
|
|
@ -155,6 +167,17 @@ namespace NzbDrone.Core.Parser
|
|
|
|
if (!ValidateBeforeParsing(title)) return null;
|
|
|
|
if (!ValidateBeforeParsing(title)) return null;
|
|
|
|
|
|
|
|
|
|
|
|
Logger.Debug("Parsing string '{0}'", title);
|
|
|
|
Logger.Debug("Parsing string '{0}'", title);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (ReversedTitleRegex.IsMatch(title))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
var titleWithoutExtension = RemoveFileExtension(title).ToCharArray();
|
|
|
|
|
|
|
|
Array.Reverse(titleWithoutExtension);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
title = new string(titleWithoutExtension) + title.Substring(titleWithoutExtension.Length);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Logger.Debug("Reversed name detected. Converted to '{0}'", title);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var simpleTitle = SimpleTitleRegex.Replace(title, String.Empty);
|
|
|
|
var simpleTitle = SimpleTitleRegex.Replace(title, String.Empty);
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var regex in ReportTitleRegex)
|
|
|
|
foreach (var regex in ReportTitleRegex)
|
|
|
@ -245,10 +268,9 @@ namespace NzbDrone.Core.Parser
|
|
|
|
|
|
|
|
|
|
|
|
title = title.Trim();
|
|
|
|
title = title.Trim();
|
|
|
|
|
|
|
|
|
|
|
|
if (!title.ContainsInvalidPathChars() && MediaFiles.MediaFileExtensions.Extensions.Contains(Path.GetExtension(title).ToLower()))
|
|
|
|
title = RemoveFileExtension(title);
|
|
|
|
{
|
|
|
|
|
|
|
|
title = Path.GetFileNameWithoutExtension(title).Trim();
|
|
|
|
title = title.TrimEnd("-RP");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var index = title.LastIndexOf('-');
|
|
|
|
var index = title.LastIndexOf('-');
|
|
|
|
|
|
|
|
|
|
|
@ -275,6 +297,19 @@ namespace NzbDrone.Core.Parser
|
|
|
|
return group;
|
|
|
|
return group;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static string RemoveFileExtension(string title)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (!title.ContainsInvalidPathChars())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (MediaFiles.MediaFileExtensions.Extensions.Contains(Path.GetExtension(title).ToLower()))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
title = Path.Combine(Path.GetDirectoryName(title), Path.GetFileNameWithoutExtension(title));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return title;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static SeriesTitleInfo GetSeriesTitleInfo(string title)
|
|
|
|
private static SeriesTitleInfo GetSeriesTitleInfo(string title)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
var seriesTitleInfo = new SeriesTitleInfo();
|
|
|
|
var seriesTitleInfo = new SeriesTitleInfo();
|
|
|
@ -511,6 +546,14 @@ namespace NzbDrone.Core.Parser
|
|
|
|
return false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var titleWithoutExtension = RemoveFileExtension(title);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (RejectHashedReleasesRegex.Any(v => v.IsMatch(titleWithoutExtension)))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
Logger.Debug("Rejected Hashed Release Title: " + title);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|