mirror of
https://github.com/Sonarr/Sonarr.git
synced 2025-01-17 10:45:49 +02:00
Fixed: Season Search now correctly uses scene numbering.
This commit is contained in:
parent
da5713688d
commit
198ff059c4
@ -10,6 +10,7 @@
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Test.Common;
|
||||
using FizzWare.NBuilder;
|
||||
|
||||
namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||
{
|
||||
@ -141,7 +142,8 @@ public void should_not_attempt_to_map_episode_if_not_parsable()
|
||||
results.Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Test] public void should_not_attempt_to_map_episode_series_title_is_blank()
|
||||
[Test]
|
||||
public void should_not_attempt_to_map_episode_series_title_is_blank()
|
||||
{
|
||||
GivenSpecifications(_pass1, _pass2, _pass3);
|
||||
_reports[0].Title = "1937 - Snow White and the Seven Dwarves";
|
||||
@ -204,5 +206,44 @@ public void should_return_unknown_series_rejection_if_series_is_unknown()
|
||||
|
||||
result.Should().HaveCount(1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_only_include_reports_for_requested_episodes()
|
||||
{
|
||||
var series = Builder<Series>.CreateNew().Build();
|
||||
|
||||
var episodes = Builder<Episode>.CreateListOfSize(2)
|
||||
.All()
|
||||
.With(v => v.SeriesId, series.Id)
|
||||
.With(v => v.Series, series)
|
||||
.With(v => v.SeasonNumber, 1)
|
||||
.With(v => v.SceneSeasonNumber, 2)
|
||||
.BuildList();
|
||||
|
||||
var criteria = new SeasonSearchCriteria { Episodes = episodes.Take(1).ToList(), SeasonNumber = 1 };
|
||||
|
||||
var reports = episodes.Select(v =>
|
||||
new ReleaseInfo()
|
||||
{
|
||||
Title = string.Format("{0}.S{1:00}E{2:00}.720p.WEB-DL-DRONE", series.Title, v.SceneSeasonNumber, v.SceneEpisodeNumber)
|
||||
}).ToList();
|
||||
|
||||
Mocker.GetMock<IParsingService>()
|
||||
.Setup(v => v.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<int>(), It.IsAny<SearchCriteriaBase>()))
|
||||
.Returns<ParsedEpisodeInfo, int, SearchCriteriaBase>((p,id,c) =>
|
||||
new RemoteEpisode
|
||||
{
|
||||
DownloadAllowed = true,
|
||||
ParsedEpisodeInfo = p,
|
||||
Series = series,
|
||||
Episodes = episodes.Where(v => v.SceneEpisodeNumber == p.EpisodeNumbers.First()).ToList()
|
||||
});
|
||||
|
||||
Mocker.SetConstant<IEnumerable<IDecisionEngineSpecification>>(new List<IDecisionEngineSpecification>());
|
||||
|
||||
var decisions = Subject.GetSearchDecision(reports, criteria);
|
||||
|
||||
Assert.AreEqual(1, decisions.Count);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,170 @@
|
||||
using NzbDrone.Core.IndexerSearch;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using FizzWare.NBuilder;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Indexers;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
|
||||
namespace NzbDrone.Core.Test.IndexerSearchTests
|
||||
{
|
||||
public class NzbSearchServiceFixture : CoreTest<NzbSearchService>
|
||||
{
|
||||
private Series _xemSeries;
|
||||
private List<Episode> _xemEpisodes;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
var indexer = Mocker.GetMock<IIndexer>();
|
||||
indexer.SetupGet(s => s.SupportsSearching).Returns(true);
|
||||
|
||||
Mocker.GetMock<IIndexerFactory>()
|
||||
.Setup(s => s.GetAvailableProviders())
|
||||
.Returns(new List<IIndexer>{indexer.Object});
|
||||
|
||||
Mocker.GetMock<NzbDrone.Core.DecisionEngine.IMakeDownloadDecision>()
|
||||
.Setup(s => s.GetSearchDecision(It.IsAny<List<Parser.Model.ReleaseInfo>>(), It.IsAny<SearchCriteriaBase>()))
|
||||
.Returns(new List<NzbDrone.Core.DecisionEngine.Specifications.DownloadDecision>());
|
||||
|
||||
_xemSeries = Builder<Series>.CreateNew()
|
||||
.With(v => v.UseSceneNumbering = true)
|
||||
.Build();
|
||||
|
||||
_xemEpisodes = new List<Episode>();
|
||||
|
||||
Mocker.GetMock<ISeriesService>()
|
||||
.Setup(v => v.GetSeries(_xemSeries.Id))
|
||||
.Returns(_xemSeries);
|
||||
|
||||
Mocker.GetMock<IEpisodeService>()
|
||||
.Setup(v => v.GetEpisodesBySeason(_xemSeries.Id, It.IsAny<int>()))
|
||||
.Returns<int, int>((i, j) => _xemEpisodes.Where(d => d.SeasonNumber == j).ToList());
|
||||
}
|
||||
|
||||
private void WithEpisode(int seasonNumber, int episodeNumber, int sceneSeasonNumber, int sceneEpisodeNumber)
|
||||
{
|
||||
var episode = Builder<Episode>.CreateNew()
|
||||
.With(v => v.SeriesId == _xemSeries.Id)
|
||||
.With(v => v.Series == _xemSeries)
|
||||
.With(v => v.SeasonNumber, seasonNumber)
|
||||
.With(v => v.EpisodeNumber, episodeNumber)
|
||||
.With(v => v.SceneSeasonNumber, sceneSeasonNumber)
|
||||
.With(v => v.SceneEpisodeNumber, sceneEpisodeNumber)
|
||||
.Build();
|
||||
|
||||
_xemEpisodes.Add(episode);
|
||||
}
|
||||
|
||||
private void WithEpisodes()
|
||||
{
|
||||
// Season 1 maps to Scene Season 2 (one-to-one)
|
||||
WithEpisode(1, 12, 2, 3);
|
||||
WithEpisode(1, 13, 2, 4);
|
||||
|
||||
// Season 2 maps to Scene Season 3 & 4 (one-to-one)
|
||||
WithEpisode(2, 1, 3, 11);
|
||||
WithEpisode(2, 2, 3, 12);
|
||||
WithEpisode(2, 3, 4, 11);
|
||||
WithEpisode(2, 4, 4, 12);
|
||||
|
||||
// Season 3 maps to Scene Season 5 (partial)
|
||||
// Season 4 maps to Scene Season 5 & 6 (partial)
|
||||
WithEpisode(3, 1, 5, 11);
|
||||
WithEpisode(3, 2, 5, 12);
|
||||
WithEpisode(4, 1, 5, 13);
|
||||
WithEpisode(4, 2, 5, 14);
|
||||
WithEpisode(4, 3, 6, 11);
|
||||
WithEpisode(5, 1, 6, 12);
|
||||
}
|
||||
|
||||
private List<SearchCriteriaBase> WatchForSearchCriteria()
|
||||
{
|
||||
List<SearchCriteriaBase> result = new List<SearchCriteriaBase>();
|
||||
|
||||
Mocker.GetMock<IFetchFeedFromIndexers>()
|
||||
.Setup(v => v.Fetch(It.IsAny<IIndexer>(), It.IsAny<SingleEpisodeSearchCriteria>()))
|
||||
.Callback<IIndexer, SingleEpisodeSearchCriteria>((i, s) => result.Add(s))
|
||||
.Returns(new List<Parser.Model.ReleaseInfo>());
|
||||
|
||||
Mocker.GetMock<IFetchFeedFromIndexers>()
|
||||
.Setup(v => v.Fetch(It.IsAny<IIndexer>(), It.IsAny<SeasonSearchCriteria>()))
|
||||
.Callback<IIndexer,SeasonSearchCriteria>((i,s) => result.Add(s))
|
||||
.Returns(new List<Parser.Model.ReleaseInfo>());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void scene_episodesearch()
|
||||
{
|
||||
WithEpisodes();
|
||||
|
||||
var allCriteria = WatchForSearchCriteria();
|
||||
|
||||
Subject.EpisodeSearch(_xemEpisodes.First());
|
||||
|
||||
var criteria = allCriteria.OfType<SingleEpisodeSearchCriteria>().ToList();
|
||||
|
||||
Assert.AreEqual(1, criteria.Count);
|
||||
Assert.AreEqual(2, criteria[0].SeasonNumber);
|
||||
Assert.AreEqual(3, criteria[0].EpisodeNumber);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void scene_seasonsearch()
|
||||
{
|
||||
WithEpisodes();
|
||||
|
||||
var allCriteria = WatchForSearchCriteria();
|
||||
|
||||
Subject.SeasonSearch(_xemSeries.Id, 1);
|
||||
|
||||
var criteria = allCriteria.OfType<SeasonSearchCriteria>().ToList();
|
||||
|
||||
Assert.AreEqual(1, criteria.Count);
|
||||
Assert.AreEqual(2, criteria[0].SeasonNumber);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void scene_seasonsearch_should_search_multiple_seasons()
|
||||
{
|
||||
WithEpisodes();
|
||||
|
||||
var allCriteria = WatchForSearchCriteria();
|
||||
|
||||
Subject.SeasonSearch(_xemSeries.Id, 2);
|
||||
|
||||
var criteria = allCriteria.OfType<SeasonSearchCriteria>().ToList();
|
||||
|
||||
Assert.AreEqual(2, criteria.Count);
|
||||
Assert.AreEqual(3, criteria[0].SeasonNumber);
|
||||
Assert.AreEqual(4, criteria[1].SeasonNumber);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void scene_seasonsearch_should_search_single_episode_if_possible()
|
||||
{
|
||||
WithEpisodes();
|
||||
|
||||
var allCriteria = WatchForSearchCriteria();
|
||||
|
||||
Subject.SeasonSearch(_xemSeries.Id, 4);
|
||||
|
||||
var criteria1 = allCriteria.OfType<SeasonSearchCriteria>().ToList();
|
||||
var criteria2 = allCriteria.OfType<SingleEpisodeSearchCriteria>().ToList();
|
||||
|
||||
Assert.AreEqual(1, criteria1.Count);
|
||||
Assert.AreEqual(5, criteria1[0].SeasonNumber);
|
||||
|
||||
Assert.AreEqual(1, criteria2.Count);
|
||||
Assert.AreEqual(6, criteria2[0].SeasonNumber);
|
||||
Assert.AreEqual(11, criteria2[0].EpisodeNumber);
|
||||
}
|
||||
}
|
||||
}
|
@ -138,6 +138,7 @@
|
||||
<Compile Include="Housekeeping\Housekeepers\CleanupOrphanedMetadataFilesFixture.cs" />
|
||||
<Compile Include="Housekeeping\Housekeepers\CleanupDuplicateMetadataFilesFixture.cs" />
|
||||
<Compile Include="Housekeeping\Housekeepers\FixFutureRunScheduledTasksFixture.cs" />
|
||||
<Compile Include="IndexerSearchTests\NzbSearchServiceFixture.cs" />
|
||||
<Compile Include="IndexerSearchTests\SearchDefinitionFixture.cs" />
|
||||
<Compile Include="IndexerTests\BasicRssParserFixture.cs" />
|
||||
<Compile Include="IndexerTests\IndexerServiceFixture.cs" />
|
||||
|
@ -97,6 +97,17 @@ private IEnumerable<DownloadDecision> GetDecisions(List<ReleaseInfo> reports, Se
|
||||
|
||||
if (decision != null)
|
||||
{
|
||||
if (searchCriteria != null)
|
||||
{
|
||||
var criteriaEpisodes = searchCriteria.Episodes.Select(v => v.Id).ToList();
|
||||
var remoteEpisodes = decision.RemoteEpisode.Episodes.Select(v => v.Id).ToList();
|
||||
if (!criteriaEpisodes.Intersect(remoteEpisodes).Any())
|
||||
{
|
||||
_logger.Debug("Release rejected since the episode wasn't requested: {0}", decision.RemoteEpisode.ParsedEpisodeInfo);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (decision.Rejections.Any())
|
||||
{
|
||||
_logger.Debug("Release rejected for the following reasons: {0}", String.Join(", ", decision.Rejections));
|
||||
|
@ -138,10 +138,43 @@ public List<DownloadDecision> SeasonSearch(int seriesId, int seasonNumber)
|
||||
return SearchSpecial(series, episodes);
|
||||
}
|
||||
|
||||
var searchSpec = Get<SeasonSearchCriteria>(series, episodes);
|
||||
searchSpec.SeasonNumber = seasonNumber;
|
||||
List<DownloadDecision> downloadDecisions = new List<DownloadDecision>();
|
||||
|
||||
return Dispatch(indexer => _feedFetcher.Fetch(indexer, searchSpec), searchSpec);
|
||||
if (series.UseSceneNumbering)
|
||||
{
|
||||
var sceneSeasonGroups = episodes.GroupBy(v => v.SceneSeasonNumber).Distinct();
|
||||
|
||||
foreach (var sceneSeasonEpisodes in sceneSeasonGroups)
|
||||
{
|
||||
if (sceneSeasonEpisodes.Count() == 1)
|
||||
{
|
||||
var searchSpec = Get<SingleEpisodeSearchCriteria>(series, sceneSeasonEpisodes.ToList());
|
||||
searchSpec.SeasonNumber = sceneSeasonEpisodes.Key;
|
||||
searchSpec.EpisodeNumber = sceneSeasonEpisodes.First().SceneEpisodeNumber;
|
||||
|
||||
var decisions = Dispatch(indexer => _feedFetcher.Fetch(indexer, searchSpec), searchSpec);
|
||||
downloadDecisions.AddRange(decisions);
|
||||
}
|
||||
else
|
||||
{
|
||||
var searchSpec = Get<SeasonSearchCriteria>(series, sceneSeasonEpisodes.ToList());
|
||||
searchSpec.SeasonNumber = sceneSeasonEpisodes.Key;
|
||||
|
||||
var decisions = Dispatch(indexer => _feedFetcher.Fetch(indexer, searchSpec), searchSpec);
|
||||
downloadDecisions.AddRange(decisions);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var searchSpec = Get<SeasonSearchCriteria>(series, episodes);
|
||||
searchSpec.SeasonNumber = seasonNumber;
|
||||
|
||||
var decisions = Dispatch(indexer => _feedFetcher.Fetch(indexer, searchSpec), searchSpec);
|
||||
downloadDecisions.AddRange(decisions);
|
||||
}
|
||||
|
||||
return downloadDecisions;
|
||||
}
|
||||
|
||||
private TSpec Get<TSpec>(Series series, List<Episode> episodes) where TSpec : SearchCriteriaBase, new()
|
||||
|
Loading…
Reference in New Issue
Block a user