Fixed: TheXEM mapping with one scene release to multiple tvdb episodes.

This commit is contained in:
Taloth Saldono 2018-03-09 22:41:10 +01:00
parent 940f59468a
commit e15530cee1
6 changed files with 97 additions and 33 deletions

View File

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using FizzWare.NBuilder; using FizzWare.NBuilder;
using FluentAssertions;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Core.DataAugmentation.Scene; using NzbDrone.Core.DataAugmentation.Scene;
@ -117,6 +118,10 @@ namespace NzbDrone.Core.Test.ParserTests.ParsingServiceTests
{ {
GivenAbsoluteNumberingSeries(); GivenAbsoluteNumberingSeries();
Mocker.GetMock<IEpisodeService>()
.Setup(s => s.FindEpisodesBySceneNumbering(It.IsAny<int>(), It.IsAny<int>()))
.Returns(new List<Episode>());
Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId, _singleEpisodeSearchCriteria); Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId, _singleEpisodeSearchCriteria);
Mocker.GetMock<IEpisodeService>() Mocker.GetMock<IEpisodeService>()
@ -253,7 +258,7 @@ namespace NzbDrone.Core.Test.ParserTests.ParsingServiceTests
[TestCase(0)] [TestCase(0)]
[TestCase(1)] [TestCase(1)]
[TestCase(2)] [TestCase(2)]
public void should_find_episode_by_season_and_absolute_episode_number_when_scene_absolute_episode_number_returns_multiple_results(int seasonNumber) public void should_return_episodes_when_scene_absolute_episode_number_returns_multiple_results(int seasonNumber)
{ {
GivenAbsoluteNumberingSeries(); GivenAbsoluteNumberingSeries();
@ -265,6 +270,32 @@ namespace NzbDrone.Core.Test.ParserTests.ParsingServiceTests
.Setup(s => s.FindEpisodesBySceneNumbering(It.IsAny<int>(), seasonNumber, It.IsAny<int>())) .Setup(s => s.FindEpisodesBySceneNumbering(It.IsAny<int>(), seasonNumber, It.IsAny<int>()))
.Returns(Builder<Episode>.CreateListOfSize(5).Build().ToList()); .Returns(Builder<Episode>.CreateListOfSize(5).Build().ToList());
var result = Subject.GetEpisodes(_parsedEpisodeInfo, _series, true, null);
result.Should().HaveCount(5);
Mocker.GetMock<IEpisodeService>()
.Verify(v => v.FindEpisodesBySceneNumbering(It.IsAny<int>(), seasonNumber, It.IsAny<int>()), Times.Once());
Mocker.GetMock<IEpisodeService>()
.Verify(v => v.FindEpisode(It.IsAny<int>(), seasonNumber, It.IsAny<int>()), Times.Never());
}
[TestCase(0)]
[TestCase(1)]
[TestCase(2)]
public void should_find_episode_by_season_and_absolute_episode_number_when_scene_absolute_episode_number_returns_no_results(int seasonNumber)
{
GivenAbsoluteNumberingSeries();
Mocker.GetMock<ISceneMappingService>()
.Setup(s => s.GetSceneSeasonNumber(_parsedEpisodeInfo.SeriesTitle, It.IsAny<string>()))
.Returns(seasonNumber);
Mocker.GetMock<IEpisodeService>()
.Setup(s => s.FindEpisodesBySceneNumbering(It.IsAny<int>(), seasonNumber, It.IsAny<int>()))
.Returns(Builder<Episode>.CreateListOfSize(0).Build().ToList());
Subject.GetEpisodes(_parsedEpisodeInfo, _series, true, null); Subject.GetEpisodes(_parsedEpisodeInfo, _series, true, null);
Mocker.GetMock<IEpisodeService>() Mocker.GetMock<IEpisodeService>()

View File

@ -31,7 +31,25 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.Search
if (!criteriaEpisodes.Intersect(remoteEpisodes).Any()) if (!criteriaEpisodes.Intersect(remoteEpisodes).Any())
{ {
_logger.Debug("Release rejected since the episode wasn't requested: {0}", remoteEpisode.ParsedEpisodeInfo); _logger.Debug("Release rejected since the episode wasn't requested: {0}", remoteEpisode.ParsedEpisodeInfo);
return Decision.Reject("Episode wasn't requested");
if (remoteEpisodes.Any())
{
var episodes = remoteEpisode.Episodes.OrderBy(v => v.SeasonNumber).ThenBy(v => v.EpisodeNumber).ToList();
if (episodes.Count > 1)
{
return Decision.Reject($"Episode wasn't requested: {episodes.First().SeasonNumber}x{episodes.First().EpisodeNumber}-{episodes.Last().EpisodeNumber}");
}
else
{
return Decision.Reject($"Episode wasn't requested: {episodes.First().SeasonNumber}x{episodes.First().EpisodeNumber}");
}
}
else
{
return Decision.Reject("Episode wasn't requested");
}
} }
return Decision.Accept(); return Decision.Accept();

View File

@ -25,8 +25,16 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.Search
} }
var singleEpisodeSpec = searchCriteria as SingleEpisodeSearchCriteria; var singleEpisodeSpec = searchCriteria as SingleEpisodeSearchCriteria;
if (singleEpisodeSpec == null) return Decision.Accept(); if (singleEpisodeSpec != null) return IsSatisfiedBy(remoteEpisode, singleEpisodeSpec);
var animeEpisodeSpec = searchCriteria as AnimeEpisodeSearchCriteria;
if (animeEpisodeSpec != null) return IsSatisfiedBy(remoteEpisode, animeEpisodeSpec);
return Decision.Accept();
}
private Decision IsSatisfiedBy(RemoteEpisode remoteEpisode, SingleEpisodeSearchCriteria singleEpisodeSpec)
{
if (singleEpisodeSpec.SeasonNumber != remoteEpisode.ParsedEpisodeInfo.SeasonNumber) if (singleEpisodeSpec.SeasonNumber != remoteEpisode.ParsedEpisodeInfo.SeasonNumber)
{ {
_logger.Debug("Season number does not match searched season number, skipping."); _logger.Debug("Season number does not match searched season number, skipping.");
@ -47,5 +55,16 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.Search
return Decision.Accept(); return Decision.Accept();
} }
private Decision IsSatisfiedBy(RemoteEpisode remoteEpisode, AnimeEpisodeSearchCriteria singleEpisodeSpec)
{
if (remoteEpisode.ParsedEpisodeInfo.FullSeason)
{
_logger.Debug("Full season result during single episode search, skipping.");
return Decision.Reject("Full season pack");
}
return Decision.Accept();
}
} }
} }

View File

@ -363,13 +363,13 @@ namespace NzbDrone.Core.Parser
foreach (var absoluteEpisodeNumber in parsedEpisodeInfo.AbsoluteEpisodeNumbers) foreach (var absoluteEpisodeNumber in parsedEpisodeInfo.AbsoluteEpisodeNumbers)
{ {
Episode episode = null; var episodes = new List<Episode>();
if (parsedEpisodeInfo.Special) if (parsedEpisodeInfo.Special)
{ {
episode = _episodeService.FindEpisode(series.Id, 0, absoluteEpisodeNumber); var episode = _episodeService.FindEpisode(series.Id, 0, absoluteEpisodeNumber);
episodes.AddIfNotNull(episode);
} }
else if (sceneSource) else if (sceneSource)
{ {
// Is there a reason why we excluded season 1 from this handling before? // Is there a reason why we excluded season 1 from this handling before?
@ -377,31 +377,33 @@ namespace NzbDrone.Core.Parser
// If this needs to be reverted tests will need to be added // If this needs to be reverted tests will need to be added
if (sceneSeasonNumber.HasValue) if (sceneSeasonNumber.HasValue)
{ {
var episodes = _episodeService.FindEpisodesBySceneNumbering(series.Id, sceneSeasonNumber.Value, absoluteEpisodeNumber); episodes = _episodeService.FindEpisodesBySceneNumbering(series.Id, sceneSeasonNumber.Value, absoluteEpisodeNumber);
if (episodes.Count == 1) if (episodes.Empty())
{ {
episode = episodes.First(); var episode = _episodeService.FindEpisode(series.Id, sceneSeasonNumber.Value, absoluteEpisodeNumber);
} episodes.AddIfNotNull(episode);
if (episode == null)
{
episode = _episodeService.FindEpisode(series.Id, sceneSeasonNumber.Value, absoluteEpisodeNumber);
} }
} }
else else
{ {
episode = _episodeService.FindEpisodeBySceneNumbering(series.Id, absoluteEpisodeNumber); episodes = _episodeService.FindEpisodesBySceneNumbering(series.Id, absoluteEpisodeNumber);
// Don't allow multiple results without a scene name mapping.
if (episodes.Count > 1)
{
episodes.Clear();
}
} }
} }
if (episode == null) if (episodes.Empty())
{ {
episode = _episodeService.FindEpisode(series.Id, absoluteEpisodeNumber); var episode = _episodeService.FindEpisode(series.Id, absoluteEpisodeNumber);
episodes.AddIfNotNull(episode);
} }
if (episode != null) foreach (var episode in episodes)
{ {
_logger.Debug("Using absolute episode number {0} for: {1} - TVDB: {2}x{3:00}", _logger.Debug("Using absolute episode number {0} for: {1} - TVDB: {2}x{3:00}",
absoluteEpisodeNumber, absoluteEpisodeNumber,

View File

@ -25,7 +25,7 @@ namespace NzbDrone.Core.Tv
PagingSpec<Episode> EpisodesWithoutFiles(PagingSpec<Episode> pagingSpec, bool includeSpecials); PagingSpec<Episode> EpisodesWithoutFiles(PagingSpec<Episode> pagingSpec, bool includeSpecials);
PagingSpec<Episode> EpisodesWhereCutoffUnmet(PagingSpec<Episode> pagingSpec, List<QualitiesBelowCutoff> qualitiesBelowCutoff, bool includeSpecials); PagingSpec<Episode> EpisodesWhereCutoffUnmet(PagingSpec<Episode> pagingSpec, List<QualitiesBelowCutoff> qualitiesBelowCutoff, bool includeSpecials);
List<Episode> FindEpisodesBySceneNumbering(int seriesId, int seasonNumber, int episodeNumber); List<Episode> FindEpisodesBySceneNumbering(int seriesId, int seasonNumber, int episodeNumber);
Episode FindEpisodeBySceneNumbering(int seriesId, int sceneAbsoluteEpisodeNumber); List<Episode> FindEpisodesBySceneNumbering(int seriesId, int sceneAbsoluteEpisodeNumber);
List<Episode> EpisodesBetweenDates(DateTime startDate, DateTime endDate, bool includeUnmonitored); List<Episode> EpisodesBetweenDates(DateTime startDate, DateTime endDate, bool includeUnmonitored);
void SetMonitoredFlat(Episode episode, bool monitored); void SetMonitoredFlat(Episode episode, bool monitored);
void SetMonitoredBySeason(int seriesId, int seasonNumber, bool monitored); void SetMonitoredBySeason(int seriesId, int seasonNumber, bool monitored);
@ -134,21 +134,15 @@ namespace NzbDrone.Core.Tv
{ {
return Query.Where(s => s.SeriesId == seriesId) return Query.Where(s => s.SeriesId == seriesId)
.AndWhere(s => s.SceneSeasonNumber == seasonNumber) .AndWhere(s => s.SceneSeasonNumber == seasonNumber)
.AndWhere(s => s.SceneEpisodeNumber == episodeNumber); .AndWhere(s => s.SceneEpisodeNumber == episodeNumber)
.ToList();
} }
public Episode FindEpisodeBySceneNumbering(int seriesId, int sceneAbsoluteEpisodeNumber) public List<Episode> FindEpisodesBySceneNumbering(int seriesId, int sceneAbsoluteEpisodeNumber)
{ {
var episodes = Query.Where(s => s.SeriesId == seriesId) return Query.Where(s => s.SeriesId == seriesId)
.AndWhere(s => s.SceneAbsoluteEpisodeNumber == sceneAbsoluteEpisodeNumber) .AndWhere(s => s.SceneAbsoluteEpisodeNumber == sceneAbsoluteEpisodeNumber)
.ToList(); .ToList();
if (episodes.Empty() || episodes.Count > 1)
{
return null;
}
return episodes.Single();
} }
public List<Episode> EpisodesBetweenDates(DateTime startDate, DateTime endDate, bool includeUnmonitored) public List<Episode> EpisodesBetweenDates(DateTime startDate, DateTime endDate, bool includeUnmonitored)

View File

@ -19,7 +19,7 @@ namespace NzbDrone.Core.Tv
Episode FindEpisode(int seriesId, int absoluteEpisodeNumber); Episode FindEpisode(int seriesId, int absoluteEpisodeNumber);
Episode FindEpisodeByTitle(int seriesId, int seasonNumber, string releaseTitle); Episode FindEpisodeByTitle(int seriesId, int seasonNumber, string releaseTitle);
List<Episode> FindEpisodesBySceneNumbering(int seriesId, int seasonNumber, int episodeNumber); List<Episode> FindEpisodesBySceneNumbering(int seriesId, int seasonNumber, int episodeNumber);
Episode FindEpisodeBySceneNumbering(int seriesId, int sceneAbsoluteEpisodeNumber); List<Episode> FindEpisodesBySceneNumbering(int seriesId, int sceneAbsoluteEpisodeNumber);
Episode GetEpisode(int seriesId, string date); Episode GetEpisode(int seriesId, string date);
Episode FindEpisode(int seriesId, string date); Episode FindEpisode(int seriesId, string date);
List<Episode> GetEpisodeBySeries(int seriesId); List<Episode> GetEpisodeBySeries(int seriesId);
@ -78,9 +78,9 @@ namespace NzbDrone.Core.Tv
return _episodeRepository.FindEpisodesBySceneNumbering(seriesId, seasonNumber, episodeNumber); return _episodeRepository.FindEpisodesBySceneNumbering(seriesId, seasonNumber, episodeNumber);
} }
public Episode FindEpisodeBySceneNumbering(int seriesId, int sceneAbsoluteEpisodeNumber) public List<Episode> FindEpisodesBySceneNumbering(int seriesId, int sceneAbsoluteEpisodeNumber)
{ {
return _episodeRepository.FindEpisodeBySceneNumbering(seriesId, sceneAbsoluteEpisodeNumber); return _episodeRepository.FindEpisodesBySceneNumbering(seriesId, sceneAbsoluteEpisodeNumber);
} }
public Episode GetEpisode(int seriesId, string date) public Episode GetEpisode(int seriesId, string date)