diff --git a/src/NzbDrone.Core.Test/ParserTests/ParsingServiceTests/GetEpisodesFixture.cs b/src/NzbDrone.Core.Test/ParserTests/ParsingServiceTests/GetEpisodesFixture.cs index 59f6d031f..d6b0b83eb 100644 --- a/src/NzbDrone.Core.Test/ParserTests/ParsingServiceTests/GetEpisodesFixture.cs +++ b/src/NzbDrone.Core.Test/ParserTests/ParsingServiceTests/GetEpisodesFixture.cs @@ -130,7 +130,7 @@ namespace NzbDrone.Core.Test.ParserTests.ParsingServiceTests Subject.Map(_parsedEpisodeInfo, _series.TvRageId); Mocker.GetMock() - .Verify(v => v.FindEpisode(It.IsAny(), It.IsAny(), It.IsAny(), true), Times.Once()); + .Verify(v => v.FindEpisodesBySceneNumbering(It.IsAny(), It.IsAny(), It.IsAny()), Times.Once()); } [Test] @@ -141,7 +141,7 @@ namespace NzbDrone.Core.Test.ParserTests.ParsingServiceTests Subject.Map(_parsedEpisodeInfo, _series.TvRageId, _singleEpisodeSearchCriteria); Mocker.GetMock() - .Verify(v => v.FindEpisode(It.IsAny(), It.IsAny(), It.IsAny(), true), Times.Never()); + .Verify(v => v.FindEpisodesBySceneNumbering(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never()); } [Test] @@ -153,7 +153,7 @@ namespace NzbDrone.Core.Test.ParserTests.ParsingServiceTests Subject.Map(_parsedEpisodeInfo, _series.TvRageId, _singleEpisodeSearchCriteria); Mocker.GetMock() - .Verify(v => v.FindEpisode(It.IsAny(), It.IsAny(), It.IsAny(), true), Times.Once()); + .Verify(v => v.FindEpisodesBySceneNumbering(It.IsAny(), It.IsAny(), It.IsAny()), Times.Once()); } [Test] @@ -162,7 +162,7 @@ namespace NzbDrone.Core.Test.ParserTests.ParsingServiceTests Subject.Map(_parsedEpisodeInfo, _series.TvRageId); Mocker.GetMock() - .Verify(v => v.FindEpisode(It.IsAny(), It.IsAny(), It.IsAny(), false), Times.Once()); + .Verify(v => v.FindEpisode(It.IsAny(), It.IsAny(), It.IsAny()), Times.Once()); } [Test] @@ -171,7 +171,7 @@ namespace NzbDrone.Core.Test.ParserTests.ParsingServiceTests Subject.Map(_parsedEpisodeInfo, _series.TvRageId, _singleEpisodeSearchCriteria); Mocker.GetMock() - .Verify(v => v.FindEpisode(It.IsAny(), It.IsAny(), It.IsAny(), false), Times.Never()); + .Verify(v => v.FindEpisode(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never()); } [Test] @@ -182,7 +182,7 @@ namespace NzbDrone.Core.Test.ParserTests.ParsingServiceTests Subject.Map(_parsedEpisodeInfo, _series.TvRageId, _singleEpisodeSearchCriteria); Mocker.GetMock() - .Verify(v => v.FindEpisode(It.IsAny(), It.IsAny(), It.IsAny(), false), Times.Once()); + .Verify(v => v.FindEpisode(It.IsAny(), It.IsAny(), It.IsAny()), Times.Once()); } } } diff --git a/src/NzbDrone.Core.Test/TvTests/EpisodeRepositoryTests/FindEpisodeFixture.cs b/src/NzbDrone.Core.Test/TvTests/EpisodeRepositoryTests/FindEpisodeFixture.cs index 217e23ab8..685e995e0 100644 --- a/src/NzbDrone.Core.Test/TvTests/EpisodeRepositoryTests/FindEpisodeFixture.cs +++ b/src/NzbDrone.Core.Test/TvTests/EpisodeRepositoryTests/FindEpisodeFixture.cs @@ -1,4 +1,5 @@ -using FizzWare.NBuilder; +using System.Linq; +using FizzWare.NBuilder; using FluentAssertions; using NUnit.Framework; using NzbDrone.Core.Test.Framework; @@ -9,46 +10,55 @@ namespace NzbDrone.Core.Test.TvTests.EpisodeRepositoryTests [TestFixture] public class FindEpisodeFixture : DbTest { - private Episode _episode; + private Episode _episode1; + private Episode _episode2; [SetUp] public void Setup() { - _episode = Builder.CreateNew() - .With(e => e.Id = 0) - .With(e => e.SeriesId = 1) - .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(); + _episode1 = Builder.CreateNew() + .With(e => e.SeriesId = 1) + .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) + .BuildNew(); - _episode = Db.Insert(_episode); + _episode2 = Builder.CreateNew() + .With(e => e.SeriesId = 1) + .With(e => e.SeasonNumber = 1) + .With(e => e.SceneSeasonNumber = 2) + .With(e => e.EpisodeNumber = 4) + .With(e => e.SceneEpisodeNumber = 4) + .BuildNew(); + + _episode1 = Db.Insert(_episode1); } [Test] public void should_find_episode_by_scene_numbering() { - Subject.FindEpisodeBySceneNumbering(_episode.SeriesId, _episode.SceneSeasonNumber, _episode.SceneEpisodeNumber) + Subject.FindEpisodesBySceneNumbering(_episode1.SeriesId, _episode1.SceneSeasonNumber, _episode1.SceneEpisodeNumber) + .First() .Id .Should() - .Be(_episode.Id); + .Be(_episode1.Id); } [Test] public void should_find_episode_by_standard_numbering() { - Subject.Find(_episode.SeriesId, _episode.SeasonNumber, _episode.EpisodeNumber) + Subject.Find(_episode1.SeriesId, _episode1.SeasonNumber, _episode1.EpisodeNumber) .Id .Should() - .Be(_episode.Id); + .Be(_episode1.Id); } [Test] public void should_not_find_episode_that_does_not_exist() { - Subject.Find(_episode.SeriesId, _episode.SeasonNumber + 1, _episode.EpisodeNumber) + Subject.Find(_episode1.SeriesId, _episode1.SeasonNumber + 1, _episode1.EpisodeNumber) .Should() .BeNull(); } @@ -56,10 +66,20 @@ namespace NzbDrone.Core.Test.TvTests.EpisodeRepositoryTests [Test] public void should_find_episode_by_absolute_numbering() { - Subject.Find(_episode.SeriesId, _episode.AbsoluteEpisodeNumber.Value) + Subject.Find(_episode1.SeriesId, _episode1.AbsoluteEpisodeNumber.Value) .Id .Should() - .Be(_episode.Id); + .Be(_episode1.Id); + } + + [Test] + public void should_return_multiple_episode_if_multiple_match_by_scene_numbering() + { + _episode2 = Db.Insert(_episode2); + + Subject.FindEpisodesBySceneNumbering(_episode1.SeriesId, _episode1.SceneSeasonNumber, _episode1.SceneEpisodeNumber) + .Should() + .HaveCount(2); } } } diff --git a/src/NzbDrone.Core/Parser/ParsingService.cs b/src/NzbDrone.Core/Parser/ParsingService.cs index e51a9c855..7028a8f95 100644 --- a/src/NzbDrone.Core/Parser/ParsingService.cs +++ b/src/NzbDrone.Core/Parser/ParsingService.cs @@ -174,33 +174,37 @@ namespace NzbDrone.Core.Parser foreach (var episodeNumber in parsedEpisodeInfo.EpisodeNumbers) { - Episode episodeInfo = null; - if (series.UseSceneNumbering && sceneSource) { + List episodes = new List(); + if (searchCriteria != null) { - episodeInfo = searchCriteria.Episodes.SingleOrDefault(e => e.SceneSeasonNumber == parsedEpisodeInfo.SeasonNumber && - e.SceneEpisodeNumber == episodeNumber); + episodes = searchCriteria.Episodes.Where(e => e.SceneSeasonNumber == parsedEpisodeInfo.SeasonNumber && + e.SceneEpisodeNumber == episodeNumber).ToList(); } - if (episodeInfo == null) + if (!episodes.Any()) { - episodeInfo = _episodeService.FindEpisode(series.Id, parsedEpisodeInfo.SeasonNumber, episodeNumber, true); + episodes = _episodeService.FindEpisodesBySceneNumbering(series.Id, parsedEpisodeInfo.SeasonNumber, episodeNumber); } - if (episodeInfo != null) + if (episodes != null && episodes.Any()) { - _logger.Info("Using Scene to TVDB Mapping for: {0} - Scene: {1}x{2:00} - TVDB: {3}x{4:00}", + _logger.Info("Using Scene to TVDB Mapping for: {0} - Scene: {1}x{2:00} - TVDB: {3}", series.Title, - episodeInfo.SceneSeasonNumber, - episodeInfo.SceneEpisodeNumber, - episodeInfo.SeasonNumber, - episodeInfo.EpisodeNumber); + episodes.First().SceneSeasonNumber, + episodes.First().SceneEpisodeNumber, + String.Join(", ", episodes.Select(e => String.Format("{0}x{1:00}", e.SeasonNumber, e.EpisodeNumber)))); + + result.AddRange(episodes); + continue; } } - if (episodeInfo == null && searchCriteria != null) + Episode episodeInfo = null; + + if (searchCriteria != null) { episodeInfo = searchCriteria.Episodes.SingleOrDefault(e => e.SeasonNumber == parsedEpisodeInfo.SeasonNumber && e.EpisodeNumber == episodeNumber); diff --git a/src/NzbDrone.Core/Queue/QueueService.cs b/src/NzbDrone.Core/Queue/QueueService.cs index 963a2a747..899b41b1a 100644 --- a/src/NzbDrone.Core/Queue/QueueService.cs +++ b/src/NzbDrone.Core/Queue/QueueService.cs @@ -53,7 +53,7 @@ namespace NzbDrone.Core.Queue foreach (var episode in queueItem.RemoteEpisode.Episodes) { var queue = new Queue(); - queue.Id = queueItem.Id.GetHashCode(); + queue.Id = queueItem.Id.GetHashCode() + episode.Id; queue.Series = queueItem.RemoteEpisode.Series; queue.Episode = episode; queue.Quality = queueItem.RemoteEpisode.ParsedEpisodeInfo.Quality; diff --git a/src/NzbDrone.Core/Tv/EpisodeRepository.cs b/src/NzbDrone.Core/Tv/EpisodeRepository.cs index d3ca03965..43cdb26b5 100644 --- a/src/NzbDrone.Core/Tv/EpisodeRepository.cs +++ b/src/NzbDrone.Core/Tv/EpisodeRepository.cs @@ -21,7 +21,7 @@ namespace NzbDrone.Core.Tv List GetEpisodeByFileId(int fileId); PagingSpec EpisodesWithoutFiles(PagingSpec pagingSpec, bool includeSpecials); PagingSpec EpisodesWhereCutoffUnmet(PagingSpec pagingSpec, List qualitiesBelowCutoff, bool includeSpecials); - Episode FindEpisodeBySceneNumbering(int seriesId, int seasonNumber, int episodeNumber); + List FindEpisodesBySceneNumbering(int seriesId, int seasonNumber, int episodeNumber); List EpisodesBetweenDates(DateTime startDate, DateTime endDate); void SetMonitoredFlat(Episode episode, bool monitored); void SetMonitoredBySeason(int seriesId, int seasonNumber, bool monitored); @@ -116,12 +116,11 @@ namespace NzbDrone.Core.Tv return pagingSpec; } - public Episode FindEpisodeBySceneNumbering(int seriesId, int seasonNumber, int episodeNumber) + public List FindEpisodesBySceneNumbering(int seriesId, int seasonNumber, int episodeNumber) { return Query.Where(s => s.SeriesId == seriesId) .AndWhere(s => s.SceneSeasonNumber == seasonNumber) - .AndWhere(s => s.SceneEpisodeNumber == episodeNumber) - .SingleOrDefault(); + .AndWhere(s => s.SceneEpisodeNumber == episodeNumber); } public List EpisodesBetweenDates(DateTime startDate, DateTime endDate) diff --git a/src/NzbDrone.Core/Tv/EpisodeService.cs b/src/NzbDrone.Core/Tv/EpisodeService.cs index 20a575884..b94cb7f00 100644 --- a/src/NzbDrone.Core/Tv/EpisodeService.cs +++ b/src/NzbDrone.Core/Tv/EpisodeService.cs @@ -14,9 +14,10 @@ namespace NzbDrone.Core.Tv public interface IEpisodeService { Episode GetEpisode(int id); - Episode FindEpisode(int seriesId, int seasonNumber, int episodeNumber, bool useScene = false); + Episode FindEpisode(int seriesId, int seasonNumber, int episodeNumber); Episode FindEpisode(int seriesId, int absoluteEpisodeNumber); Episode FindEpisodeByName(int seriesId, int seasonNumber, string episodeTitle); + List FindEpisodesBySceneNumbering(int seriesId, int seasonNumber, int episodeNumber); Episode GetEpisode(int seriesId, String date); Episode FindEpisode(int seriesId, String date); List GetEpisodeBySeries(int seriesId); @@ -39,16 +40,13 @@ namespace NzbDrone.Core.Tv IHandle, IHandleAsync { - private readonly IEpisodeRepository _episodeRepository; - private readonly IQualityProfileRepository _qualityProfileRepository; private readonly IConfigService _configService; private readonly Logger _logger; - public EpisodeService(IEpisodeRepository episodeRepository, IQualityProfileRepository qualityProfileRepository, IConfigService configService, Logger logger) + public EpisodeService(IEpisodeRepository episodeRepository, IConfigService configService, Logger logger) { _episodeRepository = episodeRepository; - _qualityProfileRepository = qualityProfileRepository; _configService = configService; _logger = logger; } @@ -58,12 +56,8 @@ namespace NzbDrone.Core.Tv return _episodeRepository.Get(id); } - public Episode FindEpisode(int seriesId, int seasonNumber, int episodeNumber, bool useSceneNumbering = false) + public Episode FindEpisode(int seriesId, int seasonNumber, int episodeNumber) { - if (useSceneNumbering) - { - return _episodeRepository.FindEpisodeBySceneNumbering(seriesId, seasonNumber, episodeNumber); - } return _episodeRepository.Find(seriesId, seasonNumber, episodeNumber); } @@ -72,6 +66,11 @@ namespace NzbDrone.Core.Tv return _episodeRepository.Find(seriesId, absoluteEpisodeNumber); } + public List FindEpisodesBySceneNumbering(int seriesId, int seasonNumber, int episodeNumber) + { + return _episodeRepository.FindEpisodesBySceneNumbering(seriesId, seasonNumber, episodeNumber); + } + public Episode GetEpisode(int seriesId, String date) { return _episodeRepository.Get(seriesId, date);