diff --git a/src/NzbDrone.Core.Test/ParserTests/MultiEpisodeParserFixture.cs b/src/NzbDrone.Core.Test/ParserTests/MultiEpisodeParserFixture.cs index 2afa2bfe4..8ae77273e 100644 --- a/src/NzbDrone.Core.Test/ParserTests/MultiEpisodeParserFixture.cs +++ b/src/NzbDrone.Core.Test/ParserTests/MultiEpisodeParserFixture.cs @@ -72,6 +72,8 @@ namespace NzbDrone.Core.Test.ParserTests [TestCase("The Series Title! - S01E01-02-03", "The Series Title!", 1, new[] { 1, 2, 3 })] [TestCase("Series Title! (2013) - S04E44-E45 - Il 200 spettacolare episodio da narcisisti!", "Series Title! (2013)", 4, new[] { 44, 45 })] [TestCase("Series Title! (2013) - S04E44-E45 - Il 200 spettacolare episodio da narcisisti! [NetflixHD 720p HEVC] [ITA+ENG].mkv", "Series Title! (2013)", 4, new[] { 44, 45 })] + [TestCase("13 Series Se.1 afl.2-3-4 [VTM]", "13 Series", 1, new[] { 2, 3, 4 })] + [TestCase("Series T Se.3 afl.3 en 4", "Series T", 3, new[] { 3, 4 })] // [TestCase("", "", , new [] { })] public void should_parse_multiple_episodes(string postTitle, string title, int season, int[] episodes) diff --git a/src/NzbDrone.Core.Test/ParserTests/SeasonParserFixture.cs b/src/NzbDrone.Core.Test/ParserTests/SeasonParserFixture.cs index 4b4988b9e..271cdf430 100644 --- a/src/NzbDrone.Core.Test/ParserTests/SeasonParserFixture.cs +++ b/src/NzbDrone.Core.Test/ParserTests/SeasonParserFixture.cs @@ -28,6 +28,7 @@ namespace NzbDrone.Core.Test.ParserTests [TestCase("Series Title - Series 1 (1970) DivX", "Series Title", 1)] [TestCase("SeriesTitle.S03.540p.AMZN.WEB-DL.DD+2.0.x264-RTN", "SeriesTitle", 3)] [TestCase("Series.Title.S01.576p.BluRay.DD5.1.x264-HiSD", "Series Title", 1)] + [TestCase("Series.Stagione.3.HDTV.XviD-NOTAG", "Series", 3)] public void should_parse_full_season_release(string postTitle, string title, int season) { var result = Parser.Parser.ParseTitle(postTitle); diff --git a/src/NzbDrone.Core.Test/ParserTests/SingleEpisodeParserFixture.cs b/src/NzbDrone.Core.Test/ParserTests/SingleEpisodeParserFixture.cs index 9136bd196..05fec86cf 100644 --- a/src/NzbDrone.Core.Test/ParserTests/SingleEpisodeParserFixture.cs +++ b/src/NzbDrone.Core.Test/ParserTests/SingleEpisodeParserFixture.cs @@ -155,6 +155,7 @@ namespace NzbDrone.Core.Test.ParserTests [TestCase("Series Title 1x1", "Series Title", 1, 1)] [TestCase("1x1", "", 1, 1)] [TestCase("Series Title [2022] [S25E13] [PL] [720p] [WEB-DL-CZRG] [x264] ", "Series Title [2022]", 25, 13)] + [TestCase("Series T Se.3 afl.3", "Series T", 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 456f2898a..c1eb4d26e 100644 --- a/src/NzbDrone.Core/Parser/Parser.cs +++ b/src/NzbDrone.Core/Parser/Parser.cs @@ -178,7 +178,7 @@ namespace NzbDrone.Core.Parser RegexOptions.IgnoreCase | RegexOptions.Compiled), // Multi-season pack - new Regex(@"^(?.+?)[-_. ]+(?:S|Season[_. ]|Saison[_. ]|Series[_. ])(?<season>(?<!\d+)(?:\d{1,2})(?!\d+))(?:-|[-_. ]{3})(?:S|Season[_. ]|Saison[_. ]|Series[_. ])?(?<season>(?<!\d+)(?:\d{1,2})(?!\d+))", + new Regex(@"^(?<title>.+?)[-_. ]+(?:S|(?:Season|Saison|Series|Stagione)[_. ])(?<season>(?<!\d+)(?:\d{1,2})(?!\d+))(?:-|[-_. ]{3})(?:S|(?:Season|Saison|Series|Stagione)[_. ])?(?<season>(?<!\d+)(?:\d{1,2})(?!\d+))", RegexOptions.IgnoreCase | RegexOptions.Compiled), // Partial season pack @@ -276,11 +276,11 @@ namespace NzbDrone.Core.Parser RegexOptions.IgnoreCase | RegexOptions.Compiled), // Season only releases - new Regex(@"^(?<title>.+?)[-_. ]+?(?:S|Season|Saison|Series)[-_. ]?(?<season>\d{1,2}(?![-_. ]?\d+))(?:[-_. ]|$)+(?<extras>EXTRAS|SUBPACK)?(?!\\)", + new Regex(@"^(?<title>.+?)[-_. ]+?(?:S|Season|Saison|Series|Stagione)[-_. ]?(?<season>\d{1,2}(?![-_. ]?\d+))(?:[-_. ]|$)+(?<extras>EXTRAS|SUBPACK)?(?!\\)", RegexOptions.IgnoreCase | RegexOptions.Compiled), // 4 digit season only releases - new Regex(@"^(?<title>.+?)[-_. ]+?(?:S|Season|Saison|Series)[-_. ]?(?<season>\d{4}(?![-_. ]?\d+))(\W+|_|$)(?<extras>EXTRAS|SUBPACK)?(?!\\)", + new Regex(@"^(?<title>.+?)[-_. ]+?(?:S|Season|Saison|Series|Stagione)[-_. ]?(?<season>\d{4}(?![-_. ]?\d+))(\W+|_|$)(?<extras>EXTRAS|SUBPACK)?(?!\\)", RegexOptions.IgnoreCase | RegexOptions.Compiled), // Episodes with a title and season/episode in square brackets @@ -321,6 +321,10 @@ namespace NzbDrone.Core.Parser new Regex(@"^(?<title>.+?)?(?:(?:[-_. ](?<![()\[!]))*(?<season>(?<!\d+|\(|\[|e|x)\d{2})(?<episode>(?<!e|x)(?:[1-9][0-9]|[0][1-9])(?!p|i|\d+|\)|\]|\W\d+|\W(?:e|ep|x)\d+)))+([-_. ]+|$)(?!\\)", RegexOptions.IgnoreCase | RegexOptions.Compiled), + // Danish/Flemish release titles + new Regex(@"^(?<title>.+?)[-_. ](?:Se\.(?<season>(?<!\d+)(?:\d{1,2}|\d{4})(?!\d+))(?:(?:[-_ ]?afl\.)(?<episode>\d{1,3}(?!\d+))(?:(?:[-]|[-_ ]en[-_ ])(?<episode>\d{1,3}(?!\d+)))*))", + RegexOptions.IgnoreCase | RegexOptions.Compiled), + // Episodes with single digit episode number (S01E1, S01E5E6, etc) new Regex(@"^(?<title>.*?)(?:(?:[-_\W](?<![()\[!]))+S?(?<season>(?<!\d+)\d{1,2}(?!\d+))(?:(?:\-|[ex]){1,2}(?<episode>\d{1}))+)+(\W+|_|$)(?!\\)", RegexOptions.IgnoreCase | RegexOptions.Compiled), @@ -366,7 +370,7 @@ namespace NzbDrone.Core.Parser RegexOptions.IgnoreCase | RegexOptions.Compiled), // Season only releases for poorly named anime - new Regex(@"^(?:\[(?<subgroup>.+?)\][-_. ])?(?<title>.+?)[-_. ]+?[\[(](?:S|Season|Saison|Series)[-_. ]?(?<season>\d{1,2}(?![-_. ]?\d+))(?:[-_. )\]]|$)+(?<extras>EXTRAS|SUBPACK)?(?!\\)", + new Regex(@"^(?:\[(?<subgroup>.+?)\][-_. ])?(?<title>.+?)[-_. ]+?[\[(](?:S|Season|Saison|Series|Stagione)[-_. ]?(?<season>\d{1,2}(?![-_. ]?\d+))(?:[-_. )\]]|$)+(?<extras>EXTRAS|SUBPACK)?(?!\\)", RegexOptions.IgnoreCase | RegexOptions.Compiled), // Episodes without a title, Single episode numbers (S1E1, 1x1)