New: Consider all scene SxxE00 releases Specials as well.
* New: Consider all scene SxxE00 releases Specials as well. * Cleanup special episode titles and handle E00 specials with existing scenemappings. * Moved handling of scene mapped E00 to central function.
This commit is contained in:
parent
ad10349878
commit
d0e8aef949
|
@ -104,7 +104,7 @@ namespace NzbDrone.Core.Test.Download.TrackedDownloads
|
|||
.Returns(remoteEpisode);
|
||||
|
||||
Mocker.GetMock<IParsingService>()
|
||||
.Setup(s => s.ParseSpecialEpisodeTitle(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>(), null))
|
||||
.Setup(s => s.ParseSpecialEpisodeTitle(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>(), null))
|
||||
.Returns(remoteEpisode.ParsedEpisodeInfo);
|
||||
|
||||
var client = new DownloadClientDefinition()
|
||||
|
|
|
@ -39,5 +39,12 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
{
|
||||
Parser.Parser.ParseTitle(title).IsPossibleSpecialEpisode.Should().BeTrue();
|
||||
}
|
||||
|
||||
|
||||
[TestCase("Dr.S11E00.A.Christmas.Carol.Special.720p.HDTV-FieldOfView")]
|
||||
public void IsPossibleSpecialEpisode_should_be_true_if_e00_special(string title)
|
||||
{
|
||||
Parser.Parser.ParseTitle(title).IsPossibleSpecialEpisode.Should().BeTrue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,5 +67,31 @@ namespace NzbDrone.Core.Test.TvTests.EpisodeServiceTests
|
|||
.Should()
|
||||
.BeNull();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_handle_e00_specials()
|
||||
{
|
||||
const string expectedTitle = "Inside The Walking Dead: Walker University";
|
||||
GivenEpisodesWithTitles("Inside The Walking Dead", expectedTitle, "Inside The Walking Dead Walker University 2");
|
||||
|
||||
Subject.FindEpisodeByTitle(1, 1, "The.Walking.Dead.S04E00.Inside.The.Walking.Dead.Walker.University.720p.HDTV.x264-W4F")
|
||||
.Title
|
||||
.Should()
|
||||
.Be(expectedTitle);
|
||||
}
|
||||
|
||||
[TestCase("Dead.Man.Walking.S04E00.Inside.The.Walking.Dead.Walker.University.720p.HDTV.x264-W4F", "Inside The Walking Dead: Walker University", new[] { "Inside The Walking Dead", "Inside The Walking Dead Walker University 2" })]
|
||||
[TestCase("Who.1999.S11E00.Twice.Upon.A.Time.1080p.AMZN.WEB-DL.DDP5.1.H.264-NTb", "Twice Upon A Time", new[] { "Last Christmas" })]
|
||||
[TestCase("Who.1999.S11E00.Twice.Upon.A.Time.Christmas.Special.720p.HDTV.x264-FoV", "Twice Upon A Time", new[] { "Last Christmas" })]
|
||||
[TestCase("Who.1999.S10E00.Christmas.Special.The.Return.Of.Doctor.Mysterio.1080p.BluRay.x264-OUIJA", "The Return Of Doctor Mysterio", new[] { "Doctor Mysterio" })]
|
||||
public void should_handle_special(string releaseTitle, string expectedTitle, string[] rejectedTitles)
|
||||
{
|
||||
GivenEpisodesWithTitles(rejectedTitles.Concat(new[] { expectedTitle }).ToArray());
|
||||
|
||||
var episode = Subject.FindEpisodeByTitle(1, 0, releaseTitle);
|
||||
|
||||
episode.Should().NotBeNull();
|
||||
episode.Title.Should().Be(expectedTitle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ namespace NzbDrone.Core.DecisionEngine
|
|||
|
||||
if (parsedEpisodeInfo == null || parsedEpisodeInfo.IsPossibleSpecialEpisode)
|
||||
{
|
||||
var specialEpisodeInfo = _parsingService.ParseSpecialEpisodeTitle(report.Title, report.TvdbId, report.TvRageId, searchCriteria);
|
||||
var specialEpisodeInfo = _parsingService.ParseSpecialEpisodeTitle(parsedEpisodeInfo, report.Title, report.TvdbId, report.TvRageId, searchCriteria);
|
||||
|
||||
if (specialEpisodeInfo != null)
|
||||
{
|
||||
|
|
|
@ -78,7 +78,7 @@ namespace NzbDrone.Core.Download.TrackedDownloads
|
|||
{
|
||||
// Try parsing the original source title and if that fails, try parsing it as a special
|
||||
// TODO: Pass the TVDB ID and TVRage IDs in as well so we have a better chance for finding the item
|
||||
parsedEpisodeInfo = Parser.Parser.ParseTitle(firstHistoryItem.SourceTitle) ?? _parsingService.ParseSpecialEpisodeTitle(firstHistoryItem.SourceTitle, 0, 0);
|
||||
parsedEpisodeInfo = Parser.Parser.ParseTitle(firstHistoryItem.SourceTitle) ?? _parsingService.ParseSpecialEpisodeTitle(parsedEpisodeInfo, firstHistoryItem.SourceTitle, 0, 0);
|
||||
|
||||
if (parsedEpisodeInfo != null)
|
||||
{
|
||||
|
|
|
@ -57,17 +57,29 @@ namespace NzbDrone.Core.Parser.Model
|
|||
{
|
||||
get
|
||||
{
|
||||
// if we don't have eny episode numbers we are likely a special episode and need to do a search by episode title
|
||||
// if we don't have any episode numbers we are likely a special episode and need to do a search by episode title
|
||||
return (AirDate.IsNullOrWhiteSpace() &&
|
||||
SeriesTitle.IsNullOrWhiteSpace() &&
|
||||
(EpisodeNumbers.Length == 0 || SeasonNumber == 0) ||
|
||||
!SeriesTitle.IsNullOrWhiteSpace() && Special);
|
||||
(EpisodeNumbers.Length == 0 || SeasonNumber == 0) || !SeriesTitle.IsNullOrWhiteSpace() && Special) ||
|
||||
EpisodeNumbers.Length == 1 && EpisodeNumbers[0] == 0;
|
||||
}
|
||||
|
||||
//This prevents manually downloading a release from blowing up in mono
|
||||
//TODO: Is there a better way?
|
||||
private set {}
|
||||
}
|
||||
public bool IsPossibleSceneSeasonSpecial
|
||||
{
|
||||
get
|
||||
{
|
||||
// SxxE00 episodes
|
||||
return SeasonNumber != 0 && EpisodeNumbers.Length == 1 && EpisodeNumbers[0] == 0;
|
||||
}
|
||||
|
||||
//This prevents manually downloading a release from blowing up in mono
|
||||
//TODO: Is there a better way?
|
||||
private set { }
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
|
|
|
@ -213,6 +213,16 @@ namespace NzbDrone.Core.Parser
|
|||
RegexOptions.IgnoreCase | RegexOptions.Compiled)
|
||||
};
|
||||
|
||||
|
||||
private static readonly Regex[] SpecialEpisodeTitleRegex = new Regex[]
|
||||
{
|
||||
new Regex(@"\.S\d+E00\.(?<episodetitle>.+?)(?:\.(?:720p|1080p|HDTV|WEB|WEBRip|WEB-DL)\.|$)",
|
||||
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
||||
|
||||
new Regex(@"\.S\d+\.Special\.(?<episodetitle>.+?)(?:\.(?:720p|1080p|HDTV|WEB|WEBRip|WEB-DL)\.|$)",
|
||||
RegexOptions.IgnoreCase | RegexOptions.Compiled)
|
||||
};
|
||||
|
||||
private static readonly Regex[] RejectHashedReleasesRegex = new Regex[]
|
||||
{
|
||||
// Generic match for md5 and mixed-case hashes.
|
||||
|
@ -456,7 +466,19 @@ namespace NzbDrone.Core.Parser
|
|||
|
||||
public static string NormalizeEpisodeTitle(string title)
|
||||
{
|
||||
title = SpecialEpisodeWordRegex.Replace(title, string.Empty);
|
||||
var match = SpecialEpisodeTitleRegex
|
||||
.Select(v => v.Match(title))
|
||||
.Where(v => v.Success)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (match != null)
|
||||
{
|
||||
title = match.Groups["episodetitle"].Value;
|
||||
}
|
||||
|
||||
// Disabled, Until we run into specific testcases for the removal of these words.
|
||||
//title = SpecialEpisodeWordRegex.Replace(title, string.Empty);
|
||||
|
||||
title = PunctuationRegex.Replace(title, " ");
|
||||
title = DuplicateSpacesRegex.Replace(title, " ");
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace NzbDrone.Core.Parser
|
|||
RemoteEpisode Map(ParsedEpisodeInfo parsedEpisodeInfo, int tvdbId, int tvRageId, SearchCriteriaBase searchCriteria = null);
|
||||
RemoteEpisode Map(ParsedEpisodeInfo parsedEpisodeInfo, int seriesId, IEnumerable<int> episodeIds);
|
||||
List<Episode> GetEpisodes(ParsedEpisodeInfo parsedEpisodeInfo, Series series, bool sceneSource, SearchCriteriaBase searchCriteria = null);
|
||||
ParsedEpisodeInfo ParseSpecialEpisodeTitle(string releaseTitle, int tvdbId, int tvRageId, SearchCriteriaBase searchCriteria = null);
|
||||
ParsedEpisodeInfo ParseSpecialEpisodeTitle(ParsedEpisodeInfo parsedEpisodeInfo, string releaseTitle, int tvdbId, int tvRageId, SearchCriteriaBase searchCriteria = null);
|
||||
}
|
||||
|
||||
public class ParsingService : IParsingService
|
||||
|
@ -63,7 +63,7 @@ namespace NzbDrone.Core.Parser
|
|||
if (parsedEpisodeInfo == null || parsedEpisodeInfo.IsPossibleSpecialEpisode)
|
||||
{
|
||||
var title = Path.GetFileNameWithoutExtension(filename);
|
||||
var specialEpisodeInfo = ParseSpecialEpisodeTitle(title, series);
|
||||
var specialEpisodeInfo = ParseSpecialEpisodeTitle(parsedEpisodeInfo, title, series);
|
||||
|
||||
if (specialEpisodeInfo != null)
|
||||
{
|
||||
|
@ -184,18 +184,18 @@ namespace NzbDrone.Core.Parser
|
|||
return GetStandardEpisodes(series, parsedEpisodeInfo, sceneSource, searchCriteria);
|
||||
}
|
||||
|
||||
public ParsedEpisodeInfo ParseSpecialEpisodeTitle(string releaseTitle, int tvdbId, int tvRageId, SearchCriteriaBase searchCriteria = null)
|
||||
public ParsedEpisodeInfo ParseSpecialEpisodeTitle(ParsedEpisodeInfo parsedEpisodeInfo, string releaseTitle, int tvdbId, int tvRageId, SearchCriteriaBase searchCriteria = null)
|
||||
{
|
||||
if (searchCriteria != null)
|
||||
{
|
||||
if (tvdbId != 0 && tvdbId == searchCriteria.Series.TvdbId)
|
||||
{
|
||||
return ParseSpecialEpisodeTitle(releaseTitle, searchCriteria.Series);
|
||||
return ParseSpecialEpisodeTitle(parsedEpisodeInfo, releaseTitle, searchCriteria.Series);
|
||||
}
|
||||
|
||||
if (tvRageId != 0 && tvRageId == searchCriteria.Series.TvRageId)
|
||||
{
|
||||
return ParseSpecialEpisodeTitle(releaseTitle, searchCriteria.Series);
|
||||
return ParseSpecialEpisodeTitle(parsedEpisodeInfo, releaseTitle, searchCriteria.Series);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -222,11 +222,20 @@ namespace NzbDrone.Core.Parser
|
|||
return null;
|
||||
}
|
||||
|
||||
return ParseSpecialEpisodeTitle(releaseTitle, series);
|
||||
return ParseSpecialEpisodeTitle(parsedEpisodeInfo, releaseTitle, series);
|
||||
}
|
||||
|
||||
private ParsedEpisodeInfo ParseSpecialEpisodeTitle(string releaseTitle, Series series)
|
||||
private ParsedEpisodeInfo ParseSpecialEpisodeTitle(ParsedEpisodeInfo parsedEpisodeInfo, string releaseTitle, Series series)
|
||||
{
|
||||
// SxxE00 episodes are sometimes mapped via TheXEM, don't use episode title parsing in that case.
|
||||
if (parsedEpisodeInfo != null && parsedEpisodeInfo.IsPossibleSceneSeasonSpecial && series.UseSceneNumbering)
|
||||
{
|
||||
if (_episodeService.FindEpisodesBySceneNumbering(series.Id, parsedEpisodeInfo.SeasonNumber, 0).Any())
|
||||
{
|
||||
return parsedEpisodeInfo;
|
||||
}
|
||||
}
|
||||
|
||||
// find special episode in series season 0
|
||||
var episode = _episodeService.FindEpisodeByTitle(series.Id, 0, releaseTitle);
|
||||
|
||||
|
|
|
@ -102,11 +102,11 @@ namespace NzbDrone.Core.Tv
|
|||
{
|
||||
return _episodeRepository.GetEpisodes(seriesId, seasonNumber);
|
||||
}
|
||||
|
||||
public Episode FindEpisodeByTitle(int seriesId, int seasonNumber, string releaseTitle)
|
||||
|
||||
public Episode FindEpisodeByTitle(int seriesId, int seasonNumber, string releaseTitle)
|
||||
{
|
||||
// TODO: can replace this search mechanism with something smarter/faster/better
|
||||
var normalizedReleaseTitle = Parser.Parser.NormalizeEpisodeTitle(releaseTitle).Replace(".", " ");
|
||||
var normalizedReleaseTitle = Parser.Parser.NormalizeEpisodeTitle(releaseTitle);
|
||||
var episodes = _episodeRepository.GetEpisodes(seriesId, seasonNumber);
|
||||
|
||||
var matches = episodes.Select(
|
||||
|
@ -222,4 +222,4 @@ namespace NzbDrone.Core.Tv
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue