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);