New: Season Search for Daily series type.

closes #755
pull/2268/merge
Taloth Saldono 6 years ago committed by Taloth
parent 81e385bebf
commit 740af2751a

@ -1,16 +1,17 @@
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.DataAugmentation.Scene;
using NzbDrone.Core.IndexerSearch;
using NzbDrone.Core.Test.Framework;
using FizzWare.NBuilder;
using System;
using System.Collections.Generic;
using System.Linq;
using FizzWare.NBuilder;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Core.Tv;
using NzbDrone.Core.DataAugmentation.Scene;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.IndexerSearch;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Test.IndexerSearchTests
{
@ -55,7 +56,7 @@ namespace NzbDrone.Core.Test.IndexerSearchTests
.Returns(new List<string>());
}
private void WithEpisode(int seasonNumber, int episodeNumber, int? sceneSeasonNumber, int? sceneEpisodeNumber)
private void WithEpisode(int seasonNumber, int episodeNumber, int? sceneSeasonNumber, int? sceneEpisodeNumber, string airDate = null)
{
var episode = Builder<Episode>.CreateNew()
.With(v => v.SeriesId == _xemSeries.Id)
@ -64,6 +65,7 @@ namespace NzbDrone.Core.Test.IndexerSearchTests
.With(v => v.EpisodeNumber, episodeNumber)
.With(v => v.SceneSeasonNumber, sceneSeasonNumber)
.With(v => v.SceneEpisodeNumber, sceneEpisodeNumber)
.With(v => v.AirDate = (airDate ?? $"{2000 + seasonNumber}-{episodeNumber:00}-05"))
.With(v => v.Monitored = true)
.Build();
@ -108,10 +110,22 @@ namespace NzbDrone.Core.Test.IndexerSearchTests
.Callback<SeasonSearchCriteria>(s => result.Add(s))
.Returns(new List<Parser.Model.ReleaseInfo>());
_mockIndexer.Setup(v => v.Fetch(It.IsAny<DailyEpisodeSearchCriteria>()))
.Callback<DailyEpisodeSearchCriteria>(s => result.Add(s))
.Returns(new List<Parser.Model.ReleaseInfo>());
_mockIndexer.Setup(v => v.Fetch(It.IsAny<DailySeasonSearchCriteria>()))
.Callback<DailySeasonSearchCriteria>(s => result.Add(s))
.Returns(new List<Parser.Model.ReleaseInfo>());
_mockIndexer.Setup(v => v.Fetch(It.IsAny<AnimeEpisodeSearchCriteria>()))
.Callback<AnimeEpisodeSearchCriteria>(s => result.Add(s))
.Returns(new List<Parser.Model.ReleaseInfo>());
_mockIndexer.Setup(v => v.Fetch(It.IsAny<SpecialEpisodeSearchCriteria>()))
.Callback<SpecialEpisodeSearchCriteria>(s => result.Add(s))
.Returns(new List<Parser.Model.ReleaseInfo>());
return result;
}
@ -249,6 +263,68 @@ namespace NzbDrone.Core.Test.IndexerSearchTests
criteria.Count.Should().Be(0);
}
[Test]
public void season_search_for_daily_should_search_multiple_years()
{
WithEpisode(1, 1, null, null, "2005-12-30");
WithEpisode(1, 2, null, null, "2005-12-31");
WithEpisode(1, 3, null, null, "2006-01-01");
WithEpisode(1, 4, null, null, "2006-01-02");
_xemSeries.SeriesType = SeriesTypes.Daily;
var allCriteria = WatchForSearchCriteria();
Subject.SeasonSearch(_xemSeries.Id, 1, false, true);
var criteria = allCriteria.OfType<DailySeasonSearchCriteria>().ToList();
criteria.Count.Should().Be(2);
criteria[0].Year.Should().Be(2005);
criteria[1].Year.Should().Be(2006);
}
[Test]
public void season_search_for_daily_should_search_single_episode_if_possible()
{
WithEpisode(1, 1, null, null, "2005-12-30");
WithEpisode(1, 2, null, null, "2005-12-31");
WithEpisode(1, 3, null, null, "2006-01-01");
_xemSeries.SeriesType = SeriesTypes.Daily;
var allCriteria = WatchForSearchCriteria();
Subject.SeasonSearch(_xemSeries.Id, 1, false, true);
var criteria1 = allCriteria.OfType<DailySeasonSearchCriteria>().ToList();
var criteria2 = allCriteria.OfType<DailyEpisodeSearchCriteria>().ToList();
criteria1.Count.Should().Be(1);
criteria1[0].Year.Should().Be(2005);
criteria2.Count.Should().Be(1);
criteria2[0].AirDate.Should().Be(new DateTime(2006, 1, 1));
}
[Test]
public void season_search_for_daily_should_not_search_for_unmonitored_episodes()
{
WithEpisode(1, 1, null, null, "2005-12-30");
WithEpisode(1, 2, null, null, "2005-12-31");
WithEpisode(1, 3, null, null, "2006-01-01");
_xemSeries.SeriesType = SeriesTypes.Daily;
_xemEpisodes[0].Monitored = false;
var allCriteria = WatchForSearchCriteria();
Subject.SeasonSearch(_xemSeries.Id, 1, false, true);
var criteria1 = allCriteria.OfType<DailySeasonSearchCriteria>().ToList();
var criteria2 = allCriteria.OfType<DailyEpisodeSearchCriteria>().ToList();
criteria1.Should().HaveCount(0);
criteria2.Should().HaveCount(2);
}
[Test]
public void getscenenames_should_use_seasonnumber_if_no_scene_seasonnumber_is_available()
{

@ -71,7 +71,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
//Multiply maxSize by Series.Runtime
maxSize = maxSize * subject.Series.Runtime * subject.Episodes.Count;
if (subject.Episodes.Count == 1)
if (subject.Episodes.Count == 1 && subject.Series.SeriesType == SeriesTypes.Standard)
{
Episode episode = subject.Episodes.First();
List<Episode> seasonEpisodes;
@ -79,7 +79,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
var seasonSearchCriteria = searchCriteria as SeasonSearchCriteria;
if (seasonSearchCriteria != null && !seasonSearchCriteria.Series.UseSceneNumbering && seasonSearchCriteria.Episodes.Any(v => v.Id == episode.Id))
{
seasonEpisodes = (searchCriteria as SeasonSearchCriteria).Episodes;
seasonEpisodes = seasonSearchCriteria.Episodes;
}
else
{

@ -0,0 +1,14 @@
using System;
namespace NzbDrone.Core.IndexerSearch.Definitions
{
public class DailySeasonSearchCriteria : SearchCriteriaBase
{
public int Year { get; set; }
public override string ToString()
{
return string.Format("[{0} : {1}]", Series.Title, Year);
}
}
}

@ -12,6 +12,7 @@ using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Tv;
using System.Linq;
using NzbDrone.Common.TPL;
using NzbDrone.Common.Extensions;
namespace NzbDrone.Core.IndexerSearch
{
@ -73,7 +74,7 @@ namespace NzbDrone.Core.IndexerSearch
if (episode.SeasonNumber == 0)
{
// search for special episodes in season 0
// search for special episodes in season 0
return SearchSpecial(series, new List<Episode> { episode }, userInvokedSearch);
}
@ -95,9 +96,14 @@ namespace NzbDrone.Core.IndexerSearch
return SearchAnimeSeason(series, episodes, userInvokedSearch);
}
if (series.SeriesType == SeriesTypes.Daily)
{
return SearchDailySeason(series, episodes, userInvokedSearch);
}
if (seasonNumber == 0)
{
// search for special episodes in season 0
// search for special episodes in season 0
return SearchSpecial(series, episodes, userInvokedSearch);
}
@ -228,6 +234,30 @@ namespace NzbDrone.Core.IndexerSearch
return downloadDecisions;
}
private List<DownloadDecision> SearchDailySeason(Series series, List<Episode> episodes, bool userInvokedSearch)
{
var downloadDecisions = new List<DownloadDecision>();
foreach (var yearGroup in episodes.Where(v => v.Monitored && v.AirDate.IsNotNullOrWhiteSpace())
.GroupBy(v => DateTime.ParseExact(v.AirDate, Episode.AIR_DATE_FORMAT, CultureInfo.InvariantCulture).Year))
{
var yearEpisodes = yearGroup.ToList();
if (yearEpisodes.Count > 1)
{
var searchSpec = Get<DailySeasonSearchCriteria>(series, yearEpisodes, userInvokedSearch);
searchSpec.Year = yearGroup.Key;
downloadDecisions.AddRange(Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec));
}
else
{
downloadDecisions.AddRange(SearchDaily(series, yearEpisodes.First(), userInvokedSearch));
}
}
return downloadDecisions;
}
private TSpec Get<TSpec>(Series series, List<Episode> episodes, bool userInvokedSearch) where TSpec : SearchCriteriaBase, new()
{
var spec = new TSpec();

@ -7,7 +7,7 @@ namespace NzbDrone.Core.Indexers.BitMeTv
public class BitMeTvRequestGenerator : IIndexerRequestGenerator
{
public BitMeTvSettings Settings { get; set; }
public virtual IndexerPageableRequestChain GetRecentRequests()
{
var pageableRequests = new IndexerPageableRequestChain();
@ -32,6 +32,11 @@ namespace NzbDrone.Core.Indexers.BitMeTv
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(DailySeasonSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(AnimeEpisodeSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();

@ -127,6 +127,34 @@ namespace NzbDrone.Core.Indexers.BroadcastheNet
return pageableRequests;
}
public virtual IndexerPageableRequestChain GetSearchRequests(DailySeasonSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
var parameters = new BroadcastheNetTorrentQuery();
if (AddSeriesSearchParameters(parameters, searchCriteria))
{
parameters.Category = "Episode";
parameters.Name = string.Format("{0}%", searchCriteria.Year);
pageableRequests.Add(GetPagedRequests(MaxPages, parameters));
pageableRequests.AddTier();
foreach (var episode in searchCriteria.Episodes)
{
parameters = parameters.Clone();
parameters.Category = "Episode";
parameters.Name = string.Format("S{0:00}E{1:00}", episode.SeasonNumber, episode.EpisodeNumber);
pageableRequests.Add(GetPagedRequests(MaxPages, parameters));
}
}
return pageableRequests;
}
public virtual IndexerPageableRequestChain GetSearchRequests(AnimeEpisodeSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();

@ -44,6 +44,11 @@ namespace NzbDrone.Core.Indexers.Fanzub
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(DailySeasonSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(AnimeEpisodeSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();

@ -58,6 +58,21 @@ namespace NzbDrone.Core.Indexers.HDBits
return pageableRequests;
}
public virtual IndexerPageableRequestChain GetSearchRequests(DailySeasonSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
var query = new TorrentQuery();
if (TryAddSearchParameters(query, searchCriteria))
{
query.Search = string.Format("{0}-", searchCriteria.Year);
pageableRequests.Add(GetRequest(query));
}
return pageableRequests;
}
public virtual IndexerPageableRequestChain GetSearchRequests(SeasonSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();

@ -79,6 +79,16 @@ namespace NzbDrone.Core.Indexers
return FetchReleases(g => g.GetSearchRequests(searchCriteria));
}
public override IList<ReleaseInfo> Fetch(DailySeasonSearchCriteria searchCriteria)
{
if (!SupportsSearch)
{
return new List<ReleaseInfo>();
}
return FetchReleases(g => g.GetSearchRequests(searchCriteria));
}
public override IList<ReleaseInfo> Fetch(AnimeEpisodeSearchCriteria searchCriteria)
{
if (!SupportsSearch)

@ -10,12 +10,13 @@ namespace NzbDrone.Core.Indexers
bool SupportsRss { get; }
bool SupportsSearch { get; }
DownloadProtocol Protocol { get; }
IList<ReleaseInfo> FetchRecent();
IList<ReleaseInfo> Fetch(SeasonSearchCriteria searchCriteria);
IList<ReleaseInfo> Fetch(SingleEpisodeSearchCriteria searchCriteria);
IList<ReleaseInfo> Fetch(DailyEpisodeSearchCriteria searchCriteria);
IList<ReleaseInfo> Fetch(DailySeasonSearchCriteria searchCriteria);
IList<ReleaseInfo> Fetch(AnimeEpisodeSearchCriteria searchCriteria);
IList<ReleaseInfo> Fetch(SpecialEpisodeSearchCriteria searchCriteria);
}
}
}

@ -8,7 +8,8 @@ namespace NzbDrone.Core.Indexers
IndexerPageableRequestChain GetSearchRequests(SingleEpisodeSearchCriteria searchCriteria);
IndexerPageableRequestChain GetSearchRequests(SeasonSearchCriteria searchCriteria);
IndexerPageableRequestChain GetSearchRequests(DailyEpisodeSearchCriteria searchCriteria);
IndexerPageableRequestChain GetSearchRequests(DailySeasonSearchCriteria searchCriteria);
IndexerPageableRequestChain GetSearchRequests(AnimeEpisodeSearchCriteria searchCriteria);
IndexerPageableRequestChain GetSearchRequests(SpecialEpisodeSearchCriteria searchCriteria);
}
}
}

@ -32,6 +32,11 @@ namespace NzbDrone.Core.Indexers.IPTorrents
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(DailySeasonSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(AnimeEpisodeSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();

@ -65,6 +65,7 @@ namespace NzbDrone.Core.Indexers
public abstract IList<ReleaseInfo> Fetch(SeasonSearchCriteria searchCriteria);
public abstract IList<ReleaseInfo> Fetch(SingleEpisodeSearchCriteria searchCriteria);
public abstract IList<ReleaseInfo> Fetch(DailyEpisodeSearchCriteria searchCriteria);
public abstract IList<ReleaseInfo> Fetch(DailySeasonSearchCriteria searchCriteria);
public abstract IList<ReleaseInfo> Fetch(AnimeEpisodeSearchCriteria searchCriteria);
public abstract IList<ReleaseInfo> Fetch(SpecialEpisodeSearchCriteria searchCriteria);

@ -146,6 +146,17 @@ namespace NzbDrone.Core.Indexers.Newznab
return pageableRequests;
}
public virtual IndexerPageableRequestChain GetSearchRequests(DailySeasonSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
AddTvIdPageableRequests(pageableRequests, MaxPages, Settings.Categories, searchCriteria,
string.Format("&season={0}",
searchCriteria.Year));
return pageableRequests;
}
public virtual IndexerPageableRequestChain GetSearchRequests(AnimeEpisodeSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();

@ -41,6 +41,11 @@ namespace NzbDrone.Core.Indexers.Nyaa
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(DailySeasonSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(AnimeEpisodeSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();

@ -68,6 +68,20 @@ namespace NzbDrone.Core.Indexers.Omgwtfnzbs
return pageableRequests;
}
public virtual IndexerPageableRequestChain GetSearchRequests(DailySeasonSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
foreach (var queryTitle in searchCriteria.QueryTitles)
{
pageableRequests.Add(GetPagedRequests(string.Format("{0}+{1}",
queryTitle,
searchCriteria.Year)));
}
return pageableRequests;
}
public virtual IndexerPageableRequestChain GetSearchRequests(AnimeEpisodeSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();

@ -52,6 +52,15 @@ namespace NzbDrone.Core.Indexers.Rarbg
return pageableRequests;
}
public virtual IndexerPageableRequestChain GetSearchRequests(DailySeasonSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests("search", searchCriteria.Series.TvdbId, "\"{0}\"", searchCriteria.Year));
return pageableRequests;
}
public virtual IndexerPageableRequestChain GetSearchRequests(AnimeEpisodeSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();

@ -37,6 +37,11 @@ namespace NzbDrone.Core.Indexers
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(DailySeasonSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(AnimeEpisodeSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();

@ -8,7 +8,7 @@ namespace NzbDrone.Core.Indexers.TorrentRss
public class TorrentRssIndexerRequestGenerator : IIndexerRequestGenerator
{
public TorrentRssIndexerSettings Settings { get; set; }
public virtual IndexerPageableRequestChain GetRecentRequests()
{
var pageableRequests = new IndexerPageableRequestChain();
@ -33,6 +33,11 @@ namespace NzbDrone.Core.Indexers.TorrentRss
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(DailySeasonSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(AnimeEpisodeSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();

@ -7,7 +7,7 @@ namespace NzbDrone.Core.Indexers.Torrentleech
public class TorrentleechRequestGenerator : IIndexerRequestGenerator
{
public TorrentleechSettings Settings { get; set; }
public virtual IndexerPageableRequestChain GetRecentRequests()
{
var pageableRequests = new IndexerPageableRequestChain();
@ -32,6 +32,11 @@ namespace NzbDrone.Core.Indexers.Torrentleech
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(DailySeasonSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(AnimeEpisodeSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();

@ -631,6 +631,7 @@
<Compile Include="Http\CloudFlare\CloudFlareHttpInterceptor.cs" />
<Compile Include="Http\HttpProxySettingsProvider.cs" />
<Compile Include="Http\TorcacheHttpInterceptor.cs" />
<Compile Include="IndexerSearch\Definitions\DailySeasonSearchCriteria.cs" />
<Compile Include="Indexers\BitMeTv\BitMeTv.cs" />
<Compile Include="Indexers\BitMeTv\BitMeTvSettings.cs" />
<Compile Include="Indexers\BitMeTv\BitMeTvRequestGenerator.cs" />

Loading…
Cancel
Save