diff --git a/src/NzbDrone.Common/Extensions/RegexExtensions.cs b/src/NzbDrone.Common/Extensions/RegexExtensions.cs new file mode 100644 index 000000000..5e99c8400 --- /dev/null +++ b/src/NzbDrone.Common/Extensions/RegexExtensions.cs @@ -0,0 +1,13 @@ +using System; +using System.Text.RegularExpressions; + +namespace NzbDrone.Common.Extensions +{ + public static class RegexExtensions + { + public static int EndIndex(this Capture regexMatch) + { + return regexMatch.Index + regexMatch.Length; + } + } +} diff --git a/src/NzbDrone.Common/NzbDrone.Common.csproj b/src/NzbDrone.Common/NzbDrone.Common.csproj index fad4a7e93..7378e855d 100644 --- a/src/NzbDrone.Common/NzbDrone.Common.csproj +++ b/src/NzbDrone.Common/NzbDrone.Common.csproj @@ -102,6 +102,7 @@ + diff --git a/src/NzbDrone.Core.Test/ParserTests/IsPossibleSpecialEpisodeFixture.cs b/src/NzbDrone.Core.Test/ParserTests/IsPossibleSpecialEpisodeFixture.cs index 0db07c03f..747884b07 100644 --- a/src/NzbDrone.Core.Test/ParserTests/IsPossibleSpecialEpisodeFixture.cs +++ b/src/NzbDrone.Core.Test/ParserTests/IsPossibleSpecialEpisodeFixture.cs @@ -46,5 +46,11 @@ public void IsPossibleSpecialEpisode_should_be_true_if_e00_special(string title) { Parser.Parser.ParseTitle(title).IsPossibleSpecialEpisode.Should().BeTrue(); } + + [TestCase("Big.Special.Show.S05.HDTV.x264-2HD")] + public void IsPossibleSpecialEpisode_should_be_false_for_Special_in_title(string title) + { + Parser.Parser.ParseTitle(title).IsPossibleSpecialEpisode.Should().BeFalse(); + } } } diff --git a/src/NzbDrone.Core/Parser/Model/ParsedEpisodeInfo.cs b/src/NzbDrone.Core/Parser/Model/ParsedEpisodeInfo.cs index 7e5977afa..5b2128160 100644 --- a/src/NzbDrone.Core/Parser/Model/ParsedEpisodeInfo.cs +++ b/src/NzbDrone.Core/Parser/Model/ParsedEpisodeInfo.cs @@ -24,6 +24,7 @@ public class ParsedEpisodeInfo public string ReleaseGroup { get; set; } public string ReleaseHash { get; set; } public int SeasonPart { get; set; } + public string ReleaseTokens { get; set; } public ParsedEpisodeInfo() { @@ -104,6 +105,13 @@ public override string ToString() { episodeString = string.Format("{0}", string.Join("-", AbsoluteEpisodeNumbers.Select(c => c.ToString("000")))); } + else if (Special) + { + if (SeasonNumber != 0) + episodeString = string.Format("[Unknown Season {0:00} Special]", SeasonNumber); + else + episodeString = "[Unknown Special]"; + } return string.Format("{0} - {1} {2}", SeriesTitle, episodeString, Quality); } diff --git a/src/NzbDrone.Core/Parser/Parser.cs b/src/NzbDrone.Core/Parser/Parser.cs index 7fac3c646..faba1172e 100644 --- a/src/NzbDrone.Core/Parser/Parser.cs +++ b/src/NzbDrone.Core/Parser/Parser.cs @@ -450,7 +450,7 @@ public static ParsedEpisodeInfo ParseTitle(string title) if (result != null) { - if (result.FullSeason && title.ContainsIgnoreCase("Special")) + if (result.FullSeason && result.ReleaseTokens.ContainsIgnoreCase("Special")) { result.FullSeason = false; result.Special = true; @@ -643,6 +643,8 @@ private static ParsedEpisodeInfo ParseMatchCollection(MatchCollection matchColle int airYear; int.TryParse(matchCollection[0].Groups["airyear"].Value, out airYear); + int lastSeasonEpisodeStringIndex = matchCollection[0].Groups["title"].EndIndex(); + ParsedEpisodeInfo result; if (airYear < 1900) @@ -653,7 +655,11 @@ private static ParsedEpisodeInfo ParseMatchCollection(MatchCollection matchColle { int parsedSeason; if (int.TryParse(seasonCapture.Value, out parsedSeason)) + { seasons.Add(parsedSeason); + + lastSeasonEpisodeStringIndex = Math.Max(lastSeasonEpisodeStringIndex, seasonCapture.EndIndex()); + } } //If no season was found it should be treated as a mini series and season 1 @@ -688,6 +694,8 @@ private static ParsedEpisodeInfo ParseMatchCollection(MatchCollection matchColle var count = last - first + 1; result.EpisodeNumbers = Enumerable.Range(first, count).ToArray(); + + lastSeasonEpisodeStringIndex = Math.Max(lastSeasonEpisodeStringIndex, episodeCaptures.Last().EndIndex()); } if (absoluteEpisodeCaptures.Any()) @@ -707,6 +715,8 @@ private static ParsedEpisodeInfo ParseMatchCollection(MatchCollection matchColle result.SpecialAbsoluteEpisodeNumbers = new decimal[] { first }; result.Special = true; + + lastSeasonEpisodeStringIndex = Math.Max(lastSeasonEpisodeStringIndex, absoluteEpisodeCaptures.First().EndIndex()); } else { @@ -717,6 +727,8 @@ private static ParsedEpisodeInfo ParseMatchCollection(MatchCollection matchColle { result.Special = true; } + + lastSeasonEpisodeStringIndex = Math.Max(lastSeasonEpisodeStringIndex, absoluteEpisodeCaptures.Last().EndIndex()); } } @@ -782,6 +794,10 @@ private static ParsedEpisodeInfo ParseMatchCollection(MatchCollection matchColle throw new InvalidDateException("Invalid date found: {0}", airDate); } + lastSeasonEpisodeStringIndex = Math.Max(lastSeasonEpisodeStringIndex, matchCollection[0].Groups["airyear"].EndIndex()); + lastSeasonEpisodeStringIndex = Math.Max(lastSeasonEpisodeStringIndex, matchCollection[0].Groups["airmonth"].EndIndex()); + lastSeasonEpisodeStringIndex = Math.Max(lastSeasonEpisodeStringIndex, matchCollection[0].Groups["airday"].EndIndex()); + result = new ParsedEpisodeInfo { ReleaseTitle = releaseTitle, @@ -789,6 +805,11 @@ private static ParsedEpisodeInfo ParseMatchCollection(MatchCollection matchColle }; } + if (lastSeasonEpisodeStringIndex != releaseTitle.Length) + result.ReleaseTokens = releaseTitle.Substring(lastSeasonEpisodeStringIndex); + else + result.ReleaseTokens = releaseTitle; + result.SeriesTitle = seriesName; result.SeriesTitleInfo = GetSeriesTitleInfo(result.SeriesTitle);