From d6587dd02663d46249befc8cd122a68df2517c64 Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Sun, 11 Jan 2026 11:08:48 -0800 Subject: [PATCH] New: Improve parsing of non-mini series releases containing "Part #" in the episode name --- .../ParserTests/SingleEpisodeParserFixture.cs | 3 +++ src/NzbDrone.Core/Parser/Parser.cs | 18 ++++++++++-------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/NzbDrone.Core.Test/ParserTests/SingleEpisodeParserFixture.cs b/src/NzbDrone.Core.Test/ParserTests/SingleEpisodeParserFixture.cs index 87255d124..098a1ed5d 100644 --- a/src/NzbDrone.Core.Test/ParserTests/SingleEpisodeParserFixture.cs +++ b/src/NzbDrone.Core.Test/ParserTests/SingleEpisodeParserFixture.cs @@ -181,6 +181,9 @@ public class SingleEpisodeParserFixture : CoreTest [TestCase("Series.2006.S006E18.Some.Title.Name-Part.1.1080p.WEB-DL.AAC2.0.H.264-Release", "Series 2006", 6, 18)] [TestCase("我的人间烟火.Fireworks.Series.S01E01.2023.V2.1080p.WEB-DL.H264.AAC-SeeWEB", "Fireworks Series", 1, 1)] [TestCase("Fireworks.Series.S01E01.2023.V2.1080p.WEB-DL.H264.AAC-SeeWEB", "Fireworks Series", 1, 1)] + [TestCase("S3E3 - Seventeen Seconds [1080p]", "", 3, 3)] + [TestCase("S3E3 - Part 3 Seventeen Seconds [1080p]", "", 3, 3)] + [TestCase("S03E03 - Part 3 Seventeen Seconds [1080p]", "", 3, 3)] // [TestCase("", "", 0, 0)] public void should_parse_single_episode(string postTitle, string title, int seasonNumber, int episodeNumber) diff --git a/src/NzbDrone.Core/Parser/Parser.cs b/src/NzbDrone.Core/Parser/Parser.cs index 4b81038d0..90aa36cff 100644 --- a/src/NzbDrone.Core/Parser/Parser.cs +++ b/src/NzbDrone.Core/Parser/Parser.cs @@ -239,14 +239,6 @@ public static class Parser new Regex(@"^(?.+?)[-_. ]+S(?<season>(?<!\d+)\d{3}(?!\d+))E(?<episode>(?<!\d+)\d{2}(?!\d+))(?:-[ex](?<episode>(?<!\d+)\d{2}(?!\d+)))?([_. ]|$)(?!\\)", RegexOptions.IgnoreCase | RegexOptions.Compiled), - // Mini-Series, treated as season 1, episodes are labelled as Part01, Part 01, Part.1 - new Regex(@"^(?<title>.+?)(?:\W+(?:(?:(?<!\()Part\W?|(?<!\d+\W+)e)(?<episode>\d{1,2}(?!\d+|\))))+)", - RegexOptions.IgnoreCase | RegexOptions.Compiled), - - // Mini-Series, treated as season 1, episodes are labelled as Part One/Two/Three/...Nine, Part.One, Part_One - new Regex(@"^(?<title>.+?)(?:\W+(?:Part[-._ ](?<episode>One|Two|Three|Four|Five|Six|Seven|Eight|Nine)(?>[-._ ])))", - RegexOptions.IgnoreCase | RegexOptions.Compiled), - // Mini-Series, treated as season 1, episodes are labelled as XofY new Regex(@"^(?<title>.+?)(?:\W+(?:(?<episode>(?<!\d+)\d{1,2}(?!\d+))of\d+)+)", RegexOptions.IgnoreCase | RegexOptions.Compiled), @@ -279,6 +271,7 @@ public static class Parser new Regex(@"(?:.*(?:^))(?<title>.*?)[-._ ]+\(S(?<season>(?<!\d+)\d{1}(?!\d+))(?:[E-]{1,2}(?<episode>(?<!\d+)\d{1,2}(?!\d+)))+([._ ]+of[._ ]+[\dx]+)?\)", RegexOptions.IgnoreCase | RegexOptions.Compiled), + // TODO: Here // Single episode season or episode S1E1 or S1-E1 or S1.Ep1 or S01.Ep.01 new Regex(@"(?:.*(?:\""|^))(?<title>.*?)(?:\W?|_)S(?<season>(?<!\d+)\d{1,2}(?!\d+))(?:\W|_)?Ep?[ ._]?(?<episode>(?<!\d+)\d{1,2}(?!\d+))", RegexOptions.IgnoreCase | RegexOptions.Compiled), @@ -398,6 +391,15 @@ public static class Parser new Regex(@"^(?:(?<season>(?<!\d+)(?:\d{1,2})(?!\d+))(?:-(?<episode>\d{2,3}(?!\d+))))", RegexOptions.IgnoreCase | RegexOptions.Compiled), + // TODO: Picked up as mini-series + // Mini-Series, treated as season 1, episodes are labelled as Part01, Part 01, Part.1 + new Regex(@"^(?<title>.+?)(?:\W+(?:(?:(?<!\()Part\W?|(?<!\d+\W+)e)(?<episode>\d{1,2}(?!\d+|\))))+)", + RegexOptions.IgnoreCase | RegexOptions.Compiled), + + // Mini-Series, treated as season 1, episodes are labelled as Part One/Two/Three/...Nine, Part.One, Part_One + new Regex(@"^(?<title>.+?)(?:\W+(?:Part[-._ ](?<episode>One|Two|Three|Four|Five|Six|Seven|Eight|Nine)(?>[-._ ])))", + RegexOptions.IgnoreCase | RegexOptions.Compiled), + // Anime Range - Title Absolute Episode Number (ep01-12) new Regex(@"^(?:\[(?<subgroup>.+?)\][-_. ]?)?(?<title>.+?)(?:_|\s|\.)+(?:e|ep)(?<absoluteepisode>\d{2,3}(\.\d{1,2})?)-(?<absoluteepisode>(?<!\d+)\d{1,2}(\.\d{1,2})?(?!\d+|-)).*?(?<hash>[(\[]\w{8}[)\]])?$", RegexOptions.IgnoreCase | RegexOptions.Compiled),