diff --git a/src/NzbDrone.Core.Test/ParserTests/ParsingServiceTests/GetEpisodesFixture.cs b/src/NzbDrone.Core.Test/ParserTests/ParsingServiceTests/GetEpisodesFixture.cs index b1d235dee..59f6d031f 100644 --- a/src/NzbDrone.Core.Test/ParserTests/ParsingServiceTests/GetEpisodesFixture.cs +++ b/src/NzbDrone.Core.Test/ParserTests/ParsingServiceTests/GetEpisodesFixture.cs @@ -38,7 +38,8 @@ public void Setup() { SeriesTitle = _series.Title, SeasonNumber = 1, - EpisodeNumbers = new[] { 1 } + EpisodeNumbers = new[] { 1 }, + AbsoluteEpisodeNumbers = new int[0] }; _singleEpisodeSearchCriteria = new SingleEpisodeSearchCriteria @@ -69,6 +70,11 @@ private void GivenSceneNumberingSeries() _series.UseSceneNumbering = true; } + private void GivenAbsoluteNumberingSeries() + { + _parsedEpisodeInfo.AbsoluteEpisodeNumbers = new[] { 1 }; + } + [Test] public void should_get_daily_episode_episode_when_search_criteria_is_null() { @@ -105,6 +111,17 @@ public void should_fallback_to_daily_episode_lookup_when_search_criteria_episode .Verify(v => v.FindEpisode(It.IsAny(), It.IsAny()), Times.Once()); } + [Test] + public void should_use_search_criteria_episode_when_it_matches_absolute() + { + GivenAbsoluteNumberingSeries(); + + Subject.Map(_parsedEpisodeInfo, _series.TvRageId, _singleEpisodeSearchCriteria); + + Mocker.GetMock() + .Verify(v => v.FindEpisode(It.IsAny(), It.IsAny()), Times.Never()); + } + [Test] public void should_use_scene_numbering_when_series_uses_scene_numbering() { diff --git a/src/NzbDrone.Core.Test/TvTests/EpisodeRepositoryTests/FindEpisodeFixture.cs b/src/NzbDrone.Core.Test/TvTests/EpisodeRepositoryTests/FindEpisodeFixture.cs index 21fa4c91a..217e23ab8 100644 --- a/src/NzbDrone.Core.Test/TvTests/EpisodeRepositoryTests/FindEpisodeFixture.cs +++ b/src/NzbDrone.Core.Test/TvTests/EpisodeRepositoryTests/FindEpisodeFixture.cs @@ -20,6 +20,7 @@ public void Setup() .With(e => e.SeasonNumber = 1) .With(e => e.SceneSeasonNumber = 2) .With(e => e.EpisodeNumber = 3) + .With(e => e.AbsoluteEpisodeNumber = 3) .With(e => e.SceneEpisodeNumber = 4) .Build(); @@ -51,5 +52,14 @@ public void should_not_find_episode_that_does_not_exist() .Should() .BeNull(); } + + [Test] + public void should_find_episode_by_absolute_numbering() + { + Subject.Find(_episode.SeriesId, _episode.AbsoluteEpisodeNumber.Value) + .Id + .Should() + .Be(_episode.Id); + } } } diff --git a/src/NzbDrone.Core/Parser/Model/ParsedEpisodeInfo.cs b/src/NzbDrone.Core/Parser/Model/ParsedEpisodeInfo.cs index 48e9ec577..ee9e8f94b 100644 --- a/src/NzbDrone.Core/Parser/Model/ParsedEpisodeInfo.cs +++ b/src/NzbDrone.Core/Parser/Model/ParsedEpisodeInfo.cs @@ -41,5 +41,10 @@ public bool IsDaily() { return !String.IsNullOrWhiteSpace(AirDate); } + + public bool IsAbsoluteNumbering() + { + return AbsoluteEpisodeNumbers.Length > 0; + } } } \ No newline at end of file diff --git a/src/NzbDrone.Core/Parser/ParsingService.cs b/src/NzbDrone.Core/Parser/ParsingService.cs index 3cd3aa407..aa474954b 100644 --- a/src/NzbDrone.Core/Parser/ParsingService.cs +++ b/src/NzbDrone.Core/Parser/ParsingService.cs @@ -129,6 +129,28 @@ public List GetEpisodes(ParsedEpisodeInfo parsedEpisodeInfo, Series ser return result; } + if (parsedEpisodeInfo.IsAbsoluteNumbering()) + { + foreach (var absoluteEpisodeNumber in parsedEpisodeInfo.AbsoluteEpisodeNumbers) + { + var episodeInfo = _episodeService.FindEpisode(series.Id, absoluteEpisodeNumber); + + if (episodeInfo != null) + { + _logger.Info("Using absolute episode number {0} for: {1} - Scene: {2}x{3:00} - TVDB: {4}x{5:00}", + absoluteEpisodeNumber, + series.Title, + episodeInfo.SceneSeasonNumber, + episodeInfo.SceneEpisodeNumber, + episodeInfo.SeasonNumber, + episodeInfo.EpisodeNumber); + result.Add(episodeInfo); + } + } + + return result; + } + if (parsedEpisodeInfo.EpisodeNumbers == null) return result; diff --git a/src/NzbDrone.Core/Tv/EpisodeRepository.cs b/src/NzbDrone.Core/Tv/EpisodeRepository.cs index daba4d5e0..58099d8c3 100644 --- a/src/NzbDrone.Core/Tv/EpisodeRepository.cs +++ b/src/NzbDrone.Core/Tv/EpisodeRepository.cs @@ -11,6 +11,7 @@ namespace NzbDrone.Core.Tv public interface IEpisodeRepository : IBasicRepository { Episode Find(int seriesId, int season, int episodeNumber); + Episode Find(int seriesId, int absoluteEpisodeNumber); Episode Get(int seriesId, String date); Episode Find(int seriesId, String date); List GetEpisodes(int seriesId); @@ -39,6 +40,11 @@ public Episode Find(int seriesId, int season, int episodeNumber) return Query.SingleOrDefault(s => s.SeriesId == seriesId && s.SeasonNumber == season && s.EpisodeNumber == episodeNumber); } + public Episode Find(int seriesId, int absoluteEpisodeNumber) + { + return Query.SingleOrDefault(s => s.SeriesId == seriesId && s.AbsoluteEpisodeNumber == absoluteEpisodeNumber); + } + public Episode Get(int seriesId, String date) { return Query.Single(s => s.SeriesId == seriesId && s.AirDate == date); diff --git a/src/NzbDrone.Core/Tv/EpisodeService.cs b/src/NzbDrone.Core/Tv/EpisodeService.cs index 9ef46761f..96bfb1e52 100644 --- a/src/NzbDrone.Core/Tv/EpisodeService.cs +++ b/src/NzbDrone.Core/Tv/EpisodeService.cs @@ -14,6 +14,7 @@ public interface IEpisodeService { Episode GetEpisode(int id); Episode FindEpisode(int seriesId, int seasonNumber, int episodeNumber, bool useScene = false); + Episode FindEpisode(int seriesId, int absoluteEpisodeNumber); Episode GetEpisode(int seriesId, String date); Episode FindEpisode(int seriesId, String date); List GetEpisodeBySeries(int seriesId); @@ -62,6 +63,11 @@ public Episode FindEpisode(int seriesId, int seasonNumber, int episodeNumber, bo return _episodeRepository.Find(seriesId, seasonNumber, episodeNumber); } + public Episode FindEpisode(int seriesId, int absoluteEpisodeNumber) + { + return _episodeRepository.Find(seriesId, absoluteEpisodeNumber); + } + public Episode GetEpisode(int seriesId, String date) { return _episodeRepository.Get(seriesId, date);