From 6b533ef2f95ad8dbfa75cf42fbf958e61fdeb59b Mon Sep 17 00:00:00 2001 From: ttran913 <122418320+ttran913@users.noreply.github.com> Date: Wed, 9 Aug 2023 17:13:35 -0700 Subject: [PATCH] New: Season pack searching with 'Anime Standard Format Search' --- .../ReleaseSearchServiceFixture.cs | 75 +++++++++++++++++++ .../FanzubRequestGeneratorFixture.cs | 22 +++++- .../NewznabRequestGeneratorFixture.cs | 21 ++++++ .../NyaaTests/NyaaRequestGeneratorFixture.cs | 22 +++++- .../Definitions/AnimeEpisodeSearchCriteria.cs | 2 +- .../Definitions/AnimeSeasonSearchCriteria.cs | 12 +++ .../IndexerSearch/ReleaseSearchService.cs | 15 ++++ .../BroadcastheNetRequestGenerator.cs | 38 ++++++++-- .../Indexers/Fanzub/FanzubRequestGenerator.cs | 15 +++- .../FileList/FileListRequestGenerator.cs | 11 +++ .../Indexers/HDBits/HDBitsRequestGenerator.cs | 30 ++++++-- src/NzbDrone.Core/Indexers/HttpIndexerBase.cs | 10 +++ src/NzbDrone.Core/Indexers/IIndexer.cs | 1 + .../Indexers/IIndexerRequestGenerator.cs | 3 +- .../IPTorrents/IPTorrentsRequestGenerator.cs | 7 +- src/NzbDrone.Core/Indexers/IndexerBase.cs | 1 + .../Newznab/NewznabRequestGenerator.cs | 25 +++++++ .../Indexers/Nyaa/NyaaRequestGenerator.cs | 17 ++++- .../Indexers/RssIndexerRequestGenerator.cs | 7 +- .../TorrentRssIndexerRequestGenerator.cs | 7 +- .../TorrentleechRequestGenerator.cs | 7 +- 21 files changed, 327 insertions(+), 21 deletions(-) create mode 100644 src/NzbDrone.Core/IndexerSearch/Definitions/AnimeSeasonSearchCriteria.cs diff --git a/src/NzbDrone.Core.Test/IndexerSearchTests/ReleaseSearchServiceFixture.cs b/src/NzbDrone.Core.Test/IndexerSearchTests/ReleaseSearchServiceFixture.cs index f0eef026e..6a7c04f8f 100644 --- a/src/NzbDrone.Core.Test/IndexerSearchTests/ReleaseSearchServiceFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerSearchTests/ReleaseSearchServiceFixture.cs @@ -128,6 +128,10 @@ namespace NzbDrone.Core.Test.IndexerSearchTests .Callback(s => result.Add(s)) .Returns(new List()); + _mockIndexer.Setup(v => v.Fetch(It.IsAny())) + .Callback(s => result.Add(s)) + .Returns(new List()); + _mockIndexer.Setup(v => v.Fetch(It.IsAny())) .Callback(s => result.Add(s)) .Returns(new List()); @@ -414,6 +418,77 @@ namespace NzbDrone.Core.Test.IndexerSearchTests criteria.ForEach(c => c.IsSeasonSearch.Should().BeTrue()); } + [Test] + public void season_search_for_anime_should_search_for_each_monitored_season() + { + WithEpisodes(); + _xemSeries.SeriesType = SeriesTypes.Anime; + _xemEpisodes.ForEach(e => e.EpisodeFileId = 0); + + var seasonNumber = 1; + var allCriteria = WatchForSearchCriteria(); + + Subject.SeasonSearch(_xemSeries.Id, seasonNumber, true, false, true, false); + + var criteria = allCriteria.OfType().ToList(); + + var episodesForSeason1 = _xemEpisodes.Where(e => e.SeasonNumber == seasonNumber); + criteria.Count.Should().Be(episodesForSeason1.Select(e => e.SeasonNumber).Distinct().Count()); + } + + [Test] + public void season_search_for_anime_should_not_search_for_unmonitored_season() + { + WithEpisodes(); + _xemSeries.SeriesType = SeriesTypes.Anime; + _xemEpisodes.ForEach(e => e.Monitored = false); + _xemEpisodes.ForEach(e => e.EpisodeFileId = 0); + + var seasonNumber = 1; + var allCriteria = WatchForSearchCriteria(); + + Subject.SeasonSearch(_xemSeries.Id, seasonNumber, false, true, true, false); + + var criteria = allCriteria.OfType().ToList(); + + criteria.Count.Should().Be(0); + } + + [Test] + public void season_search_for_anime_should_not_search_for_unaired_season() + { + WithEpisodes(); + _xemSeries.SeriesType = SeriesTypes.Anime; + _xemEpisodes.ForEach(e => e.AirDateUtc = DateTime.UtcNow.AddDays(5)); + _xemEpisodes.ForEach(e => e.EpisodeFileId = 0); + + var seasonNumber = 1; + var allCriteria = WatchForSearchCriteria(); + + Subject.SeasonSearch(_xemSeries.Id, seasonNumber, false, false, true, false); + + var criteria = allCriteria.OfType().ToList(); + + criteria.Count.Should().Be(0); + } + + [Test] + public void season_search_for_anime_should_not_search_for_season_with_files() + { + WithEpisodes(); + _xemSeries.SeriesType = SeriesTypes.Anime; + _xemEpisodes.ForEach(e => e.EpisodeFileId = 1); + + var seasonNumber = 1; + var allCriteria = WatchForSearchCriteria(); + + Subject.SeasonSearch(_xemSeries.Id, seasonNumber, true, false, true, false); + + var criteria = allCriteria.OfType().ToList(); + + criteria.Count.Should().Be(0); + } + [Test] public void season_search_for_daily_should_search_multiple_years() { diff --git a/src/NzbDrone.Core.Test/IndexerTests/FanzubTests/FanzubRequestGeneratorFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/FanzubTests/FanzubRequestGeneratorFixture.cs index b13e972fd..1391febe0 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/FanzubTests/FanzubRequestGeneratorFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/FanzubTests/FanzubRequestGeneratorFixture.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using FluentAssertions; using NUnit.Framework; @@ -12,6 +12,7 @@ namespace NzbDrone.Core.Test.IndexerTests.FanzubTests { private SeasonSearchCriteria _seasonSearchCriteria; private AnimeEpisodeSearchCriteria _animeSearchCriteria; + private AnimeSeasonSearchCriteria _animeSeasonSearchCriteria; [SetUp] public void SetUp() @@ -34,6 +35,12 @@ namespace NzbDrone.Core.Test.IndexerTests.FanzubTests SeasonNumber = 1, EpisodeNumber = 9 }; + + _animeSeasonSearchCriteria = new AnimeSeasonSearchCriteria() + { + SceneTitles = new List() { "Naruto Shippuuden" }, + SeasonNumber = 3, + }; } [Test] @@ -81,5 +88,18 @@ namespace NzbDrone.Core.Test.IndexerTests.FanzubTests page.Url.FullUri.Should().Contain("q=\"Naruto+Shippuuden%2009\"|\"Naruto+Shippuuden%20-%2009\"|\"Naruto+Shippuuden%20S01E09\"|\"Naruto+Shippuuden%20-%20S01E09\""); } + + [Test] + public void should_search_by_standard_season_number() + { + Subject.Settings.AnimeStandardFormatSearch = true; + var results = Subject.GetSearchRequests(_animeSeasonSearchCriteria); + + results.GetAllTiers().Should().HaveCount(1); + + var page = results.GetAllTiers().First().First(); + + page.Url.FullUri.Should().Contain("q=\"Naruto+Shippuuden%20S03\"|\"Naruto+Shippuuden%20-%20S03\""); + } } } diff --git a/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabRequestGeneratorFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabRequestGeneratorFixture.cs index a33ee7562..47bd40c99 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabRequestGeneratorFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabRequestGeneratorFixture.cs @@ -15,6 +15,7 @@ namespace NzbDrone.Core.Test.IndexerTests.NewznabTests private SingleEpisodeSearchCriteria _singleEpisodeSearchCriteria; private SeasonSearchCriteria _seasonSearchCriteria; private AnimeEpisodeSearchCriteria _animeSearchCriteria; + private AnimeSeasonSearchCriteria _animeSeasonSearchCriteria; private NewznabCapabilities _capabilities; [SetUp] @@ -57,6 +58,13 @@ namespace NzbDrone.Core.Test.IndexerTests.NewznabTests EpisodeNumber = 4 }; + _animeSeasonSearchCriteria = new AnimeSeasonSearchCriteria() + { + Series = new Tv.Series { TvRageId = 10, TvdbId = 20, TvMazeId = 30, ImdbId = "t40" }, + SceneTitles = new List { "Monkey Island" }, + SeasonNumber = 3, + }; + _capabilities = new NewznabCapabilities(); Mocker.GetMock() @@ -168,6 +176,19 @@ namespace NzbDrone.Core.Test.IndexerTests.NewznabTests pages[3].Url.FullUri.Should().Contain("q=Monkey%20Island&season=5&ep=4"); } + [Test] + public void should_search_by_standard_season_number() + { + Subject.Settings.AnimeStandardFormatSearch = true; + var results = Subject.GetSearchRequests(_animeSeasonSearchCriteria); + + results.GetTier(0).Should().HaveCount(2); + var pages = results.GetTier(0).Select(t => t.First()).ToList(); + + pages[0].Url.FullUri.Should().Contain("rid=10&season=3"); + pages[1].Url.FullUri.Should().Contain("q=Monkey%20Island&season=3"); + } + [Test] public void should_not_search_by_rid_if_not_supported() { diff --git a/src/NzbDrone.Core.Test/IndexerTests/NyaaTests/NyaaRequestGeneratorFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/NyaaTests/NyaaRequestGeneratorFixture.cs index cca362dc8..5ac2bffc3 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/NyaaTests/NyaaRequestGeneratorFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/NyaaTests/NyaaRequestGeneratorFixture.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using FluentAssertions; using NUnit.Framework; @@ -12,6 +12,7 @@ namespace NzbDrone.Core.Test.IndexerTests.NyaaTests { private SeasonSearchCriteria _seasonSearchCriteria; private AnimeEpisodeSearchCriteria _animeSearchCriteria; + private AnimeSeasonSearchCriteria _animeSeasonSearchCriteria; [SetUp] public void SetUp() @@ -34,6 +35,12 @@ namespace NzbDrone.Core.Test.IndexerTests.NyaaTests SeasonNumber = 1, EpisodeNumber = 9 }; + + _animeSeasonSearchCriteria = new AnimeSeasonSearchCriteria() + { + SceneTitles = new List() { "Naruto Shippuuden" }, + SeasonNumber = 3 + }; } [Test] @@ -82,5 +89,18 @@ namespace NzbDrone.Core.Test.IndexerTests.NyaaTests pages[1].Url.FullUri.Should().Contain("term=Naruto+Shippuuden+09"); pages[2].Url.FullUri.Should().Contain("term=Naruto+Shippuuden+s01e09"); } + + [Test] + public void should_search_by_standard_season_number() + { + Subject.Settings.AnimeStandardFormatSearch = true; + var results = Subject.GetSearchRequests(_animeSeasonSearchCriteria); + + results.GetAllTiers().Should().HaveCount(1); + + var page = results.GetAllTiers().First().First(); + + page.Url.FullUri.Should().Contain("term=Naruto+Shippuuden+s03"); + } } } diff --git a/src/NzbDrone.Core/IndexerSearch/Definitions/AnimeEpisodeSearchCriteria.cs b/src/NzbDrone.Core/IndexerSearch/Definitions/AnimeEpisodeSearchCriteria.cs index 8d7ed5b2a..b71662cdc 100644 --- a/src/NzbDrone.Core/IndexerSearch/Definitions/AnimeEpisodeSearchCriteria.cs +++ b/src/NzbDrone.Core/IndexerSearch/Definitions/AnimeEpisodeSearchCriteria.cs @@ -1,4 +1,4 @@ -namespace NzbDrone.Core.IndexerSearch.Definitions +namespace NzbDrone.Core.IndexerSearch.Definitions { public class AnimeEpisodeSearchCriteria : SearchCriteriaBase { diff --git a/src/NzbDrone.Core/IndexerSearch/Definitions/AnimeSeasonSearchCriteria.cs b/src/NzbDrone.Core/IndexerSearch/Definitions/AnimeSeasonSearchCriteria.cs new file mode 100644 index 000000000..efd510f3d --- /dev/null +++ b/src/NzbDrone.Core/IndexerSearch/Definitions/AnimeSeasonSearchCriteria.cs @@ -0,0 +1,12 @@ +namespace NzbDrone.Core.IndexerSearch.Definitions +{ + public class AnimeSeasonSearchCriteria : SearchCriteriaBase + { + public int SeasonNumber { get; set; } + + public override string ToString() + { + return $"[{Series.Title} : S{SeasonNumber:00}]"; + } + } +} diff --git a/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs b/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs index 3135eced8..6b7de029a 100644 --- a/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs +++ b/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs @@ -388,6 +388,8 @@ namespace NzbDrone.Core.IndexerSearch { var downloadDecisions = new List(); + var searchSpec = Get(series, episodes, monitoredOnly, userInvokedSearch, interactiveSearch); + // Episode needs to be monitored if it's not an interactive search // and Ensure episode has an airdate and has already aired var episodesToSearch = episodes @@ -395,6 +397,19 @@ namespace NzbDrone.Core.IndexerSearch .Where(ep => ep.AirDateUtc.HasValue && ep.AirDateUtc.Value.Before(DateTime.UtcNow)) .ToList(); + var seasonsToSearch = GetSceneSeasonMappings(series, episodesToSearch) + .GroupBy(ep => ep.SeasonNumber) + .Select(epList => epList.First()) + .ToList(); + + foreach (var season in seasonsToSearch) + { + searchSpec.SeasonNumber = season.SeasonNumber; + + var decisions = Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec); + downloadDecisions.AddRange(decisions); + } + foreach (var episode in episodesToSearch) { downloadDecisions.AddRange(SearchAnime(series, episode, monitoredOnly, userInvokedSearch, interactiveSearch, true)); diff --git a/src/NzbDrone.Core/Indexers/BroadcastheNet/BroadcastheNetRequestGenerator.cs b/src/NzbDrone.Core/Indexers/BroadcastheNet/BroadcastheNetRequestGenerator.cs index 4b511d855..dc887b5a9 100644 --- a/src/NzbDrone.Core/Indexers/BroadcastheNet/BroadcastheNetRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/BroadcastheNet/BroadcastheNetRequestGenerator.cs @@ -42,8 +42,8 @@ namespace NzbDrone.Core.Indexers.BroadcastheNet public virtual IndexerPageableRequestChain GetSearchRequests(SingleEpisodeSearchCriteria searchCriteria) { var pageableRequests = new IndexerPageableRequestChain(); - var parameters = new BroadcastheNetTorrentQuery(); + if (AddSeriesSearchParameters(parameters, searchCriteria)) { foreach (var episode in searchCriteria.Episodes) @@ -63,8 +63,8 @@ namespace NzbDrone.Core.Indexers.BroadcastheNet public virtual IndexerPageableRequestChain GetSearchRequests(SeasonSearchCriteria searchCriteria) { var pageableRequests = new IndexerPageableRequestChain(); - var parameters = new BroadcastheNetTorrentQuery(); + if (AddSeriesSearchParameters(parameters, searchCriteria)) { foreach (var seasonNumber in searchCriteria.Episodes.Select(v => v.SeasonNumber).Distinct()) @@ -89,8 +89,8 @@ namespace NzbDrone.Core.Indexers.BroadcastheNet public virtual IndexerPageableRequestChain GetSearchRequests(DailyEpisodeSearchCriteria searchCriteria) { var pageableRequests = new IndexerPageableRequestChain(); - var parameters = new BroadcastheNetTorrentQuery(); + if (AddSeriesSearchParameters(parameters, searchCriteria)) { parameters.Category = "Episode"; @@ -117,8 +117,8 @@ namespace NzbDrone.Core.Indexers.BroadcastheNet public virtual IndexerPageableRequestChain GetSearchRequests(DailySeasonSearchCriteria searchCriteria) { var pageableRequests = new IndexerPageableRequestChain(); - var parameters = new BroadcastheNetTorrentQuery(); + if (AddSeriesSearchParameters(parameters, searchCriteria)) { parameters.Category = "Episode"; @@ -145,8 +145,8 @@ namespace NzbDrone.Core.Indexers.BroadcastheNet public virtual IndexerPageableRequestChain GetSearchRequests(AnimeEpisodeSearchCriteria searchCriteria) { var pageableRequests = new IndexerPageableRequestChain(); - var parameters = new BroadcastheNetTorrentQuery(); + if (AddSeriesSearchParameters(parameters, searchCriteria)) { foreach (var episode in searchCriteria.Episodes) @@ -173,11 +173,37 @@ namespace NzbDrone.Core.Indexers.BroadcastheNet return pageableRequests; } + public virtual IndexerPageableRequestChain GetSearchRequests(AnimeSeasonSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + var parameters = new BroadcastheNetTorrentQuery(); + + if (AddSeriesSearchParameters(parameters, searchCriteria)) + { + foreach (var seasonNumber in searchCriteria.Episodes.Select(v => v.SeasonNumber).Distinct()) + { + parameters.Category = "Season"; + parameters.Name = string.Format("Season {0}%", seasonNumber); + + pageableRequests.Add(GetPagedRequests(MaxPages, parameters)); + + parameters = parameters.Clone(); + + parameters.Category = "Episode"; + parameters.Name = string.Format("S{0:00}E%", seasonNumber); + + pageableRequests.Add(GetPagedRequests(MaxPages, parameters)); + } + } + + return pageableRequests; + } + public virtual IndexerPageableRequestChain GetSearchRequests(SpecialEpisodeSearchCriteria searchCriteria) { var pageableRequests = new IndexerPageableRequestChain(); - var parameters = new BroadcastheNetTorrentQuery(); + if (AddSeriesSearchParameters(parameters, searchCriteria)) { var episodeQueryTitle = searchCriteria.Episodes.Where(e => !string.IsNullOrWhiteSpace(e.Title)) diff --git a/src/NzbDrone.Core/Indexers/Fanzub/FanzubRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Fanzub/FanzubRequestGenerator.cs index 831649c55..d74ecaea1 100644 --- a/src/NzbDrone.Core/Indexers/Fanzub/FanzubRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Fanzub/FanzubRequestGenerator.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.RegularExpressions; @@ -73,6 +73,19 @@ namespace NzbDrone.Core.Indexers.Fanzub return pageableRequests; } + public virtual IndexerPageableRequestChain GetSearchRequests(AnimeSeasonSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + if (Settings.AnimeStandardFormatSearch && searchCriteria.SeasonNumber > 0) + { + var searchTitles = searchCriteria.CleanSceneTitles.SelectMany(v => GetSeasonSearchStrings(v, searchCriteria.SeasonNumber)).ToList(); + pageableRequests.Add(GetPagedRequests(string.Join("|", searchTitles))); + } + + return pageableRequests; + } + public virtual IndexerPageableRequestChain GetSearchRequests(SpecialEpisodeSearchCriteria searchCriteria) { return new IndexerPageableRequestChain(); diff --git a/src/NzbDrone.Core/Indexers/FileList/FileListRequestGenerator.cs b/src/NzbDrone.Core/Indexers/FileList/FileListRequestGenerator.cs index d6a62c2f0..df96576fb 100644 --- a/src/NzbDrone.Core/Indexers/FileList/FileListRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/FileList/FileListRequestGenerator.cs @@ -103,6 +103,17 @@ namespace NzbDrone.Core.Indexers.FileList return pageableRequests; } + public IndexerPageableRequestChain GetSearchRequests(AnimeSeasonSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + AddImdbRequests(pageableRequests, searchCriteria, "search-torrents", Settings.AnimeCategories, $"&season={searchCriteria.SeasonNumber}"); + pageableRequests.AddTier(); + AddNameRequests(pageableRequests, searchCriteria, "search-torrents", Settings.AnimeCategories, $"&season={searchCriteria.SeasonNumber}"); + + return pageableRequests; + } + public IndexerPageableRequestChain GetSearchRequests(SpecialEpisodeSearchCriteria searchCriteria) { return new IndexerPageableRequestChain(); diff --git a/src/NzbDrone.Core/Indexers/HDBits/HDBitsRequestGenerator.cs b/src/NzbDrone.Core/Indexers/HDBits/HDBitsRequestGenerator.cs index 1a8d2bc6d..315376b72 100644 --- a/src/NzbDrone.Core/Indexers/HDBits/HDBitsRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/HDBits/HDBitsRequestGenerator.cs @@ -24,8 +24,8 @@ namespace NzbDrone.Core.Indexers.HDBits public virtual IndexerPageableRequestChain GetSearchRequests(AnimeEpisodeSearchCriteria searchCriteria) { var pageableRequests = new IndexerPageableRequestChain(); - var queryBase = new TorrentQuery(); + if (TryAddSearchParameters(queryBase, searchCriteria)) { foreach (var episode in searchCriteria.Episodes) @@ -40,6 +40,26 @@ namespace NzbDrone.Core.Indexers.HDBits return pageableRequests; } + public virtual IndexerPageableRequestChain GetSearchRequests(AnimeSeasonSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + var queryBase = new TorrentQuery(); + + if (TryAddSearchParameters(queryBase, searchCriteria)) + { + foreach (var seasonNumber in searchCriteria.Episodes.Select(e => e.SeasonNumber).Distinct()) + { + var query = queryBase.Clone(); + + query.TvdbInfo.Season = seasonNumber; + + pageableRequests.Add(GetRequest(query)); + } + } + + return pageableRequests; + } + public virtual IndexerPageableRequestChain GetSearchRequests(SpecialEpisodeSearchCriteria searchCriteria) { return new IndexerPageableRequestChain(); @@ -48,8 +68,8 @@ namespace NzbDrone.Core.Indexers.HDBits public virtual IndexerPageableRequestChain GetSearchRequests(DailyEpisodeSearchCriteria searchCriteria) { var pageableRequests = new IndexerPageableRequestChain(); - var query = new TorrentQuery(); + if (TryAddSearchParameters(query, searchCriteria)) { query.Search = string.Format("{0:yyyy}-{0:MM}-{0:dd}", searchCriteria.AirDate); @@ -63,8 +83,8 @@ namespace NzbDrone.Core.Indexers.HDBits 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); @@ -78,8 +98,8 @@ namespace NzbDrone.Core.Indexers.HDBits public virtual IndexerPageableRequestChain GetSearchRequests(SeasonSearchCriteria searchCriteria) { var pageableRequests = new IndexerPageableRequestChain(); - var queryBase = new TorrentQuery(); + if (TryAddSearchParameters(queryBase, searchCriteria)) { foreach (var seasonNumber in searchCriteria.Episodes.Select(e => e.SeasonNumber).Distinct()) @@ -98,8 +118,8 @@ namespace NzbDrone.Core.Indexers.HDBits public virtual IndexerPageableRequestChain GetSearchRequests(SingleEpisodeSearchCriteria searchCriteria) { var pageableRequests = new IndexerPageableRequestChain(); - var queryBase = new TorrentQuery(); + if (TryAddSearchParameters(queryBase, searchCriteria)) { foreach (var episode in searchCriteria.Episodes) diff --git a/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs b/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs index 7bb843e6d..cc33df756 100644 --- a/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs +++ b/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs @@ -100,6 +100,16 @@ namespace NzbDrone.Core.Indexers return FetchReleases(g => g.GetSearchRequests(searchCriteria)); } + public override IList Fetch(AnimeSeasonSearchCriteria searchCriteria) + { + if (!SupportsSearch) + { + return Array.Empty(); + } + + return FetchReleases(g => g.GetSearchRequests(searchCriteria)); + } + public override IList Fetch(SpecialEpisodeSearchCriteria searchCriteria) { if (!SupportsSearch) diff --git a/src/NzbDrone.Core/Indexers/IIndexer.cs b/src/NzbDrone.Core/Indexers/IIndexer.cs index 420f4d29f..e593e9ba8 100644 --- a/src/NzbDrone.Core/Indexers/IIndexer.cs +++ b/src/NzbDrone.Core/Indexers/IIndexer.cs @@ -18,6 +18,7 @@ namespace NzbDrone.Core.Indexers IList Fetch(DailyEpisodeSearchCriteria searchCriteria); IList Fetch(DailySeasonSearchCriteria searchCriteria); IList Fetch(AnimeEpisodeSearchCriteria searchCriteria); + IList Fetch(AnimeSeasonSearchCriteria searchCriteria); IList Fetch(SpecialEpisodeSearchCriteria searchCriteria); HttpRequest GetDownloadRequest(string link); } diff --git a/src/NzbDrone.Core/Indexers/IIndexerRequestGenerator.cs b/src/NzbDrone.Core/Indexers/IIndexerRequestGenerator.cs index 1f167f98f..ed153ef9d 100644 --- a/src/NzbDrone.Core/Indexers/IIndexerRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/IIndexerRequestGenerator.cs @@ -1,4 +1,4 @@ -using NzbDrone.Core.IndexerSearch.Definitions; +using NzbDrone.Core.IndexerSearch.Definitions; namespace NzbDrone.Core.Indexers { @@ -10,6 +10,7 @@ namespace NzbDrone.Core.Indexers IndexerPageableRequestChain GetSearchRequests(DailyEpisodeSearchCriteria searchCriteria); IndexerPageableRequestChain GetSearchRequests(DailySeasonSearchCriteria searchCriteria); IndexerPageableRequestChain GetSearchRequests(AnimeEpisodeSearchCriteria searchCriteria); + IndexerPageableRequestChain GetSearchRequests(AnimeSeasonSearchCriteria searchCriteria); IndexerPageableRequestChain GetSearchRequests(SpecialEpisodeSearchCriteria searchCriteria); } } diff --git a/src/NzbDrone.Core/Indexers/IPTorrents/IPTorrentsRequestGenerator.cs b/src/NzbDrone.Core/Indexers/IPTorrents/IPTorrentsRequestGenerator.cs index c352d072c..9e757d59d 100644 --- a/src/NzbDrone.Core/Indexers/IPTorrents/IPTorrentsRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/IPTorrents/IPTorrentsRequestGenerator.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using NzbDrone.Common.Http; using NzbDrone.Core.IndexerSearch.Definitions; @@ -42,6 +42,11 @@ namespace NzbDrone.Core.Indexers.IPTorrents return new IndexerPageableRequestChain(); } + public virtual IndexerPageableRequestChain GetSearchRequests(AnimeSeasonSearchCriteria searchCriteria) + { + return new IndexerPageableRequestChain(); + } + public virtual IndexerPageableRequestChain GetSearchRequests(SpecialEpisodeSearchCriteria searchCriteria) { return new IndexerPageableRequestChain(); diff --git a/src/NzbDrone.Core/Indexers/IndexerBase.cs b/src/NzbDrone.Core/Indexers/IndexerBase.cs index 91b3cb8f6..8613dd233 100644 --- a/src/NzbDrone.Core/Indexers/IndexerBase.cs +++ b/src/NzbDrone.Core/Indexers/IndexerBase.cs @@ -73,6 +73,7 @@ namespace NzbDrone.Core.Indexers public abstract IList Fetch(DailyEpisodeSearchCriteria searchCriteria); public abstract IList Fetch(DailySeasonSearchCriteria searchCriteria); public abstract IList Fetch(AnimeEpisodeSearchCriteria searchCriteria); + public abstract IList Fetch(AnimeSeasonSearchCriteria searchCriteria); public abstract IList Fetch(SpecialEpisodeSearchCriteria searchCriteria); public abstract HttpRequest GetDownloadRequest(string link); diff --git a/src/NzbDrone.Core/Indexers/Newznab/NewznabRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Newznab/NewznabRequestGenerator.cs index ef7f0c498..b3e0090cd 100644 --- a/src/NzbDrone.Core/Indexers/Newznab/NewznabRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Newznab/NewznabRequestGenerator.cs @@ -432,6 +432,31 @@ namespace NzbDrone.Core.Indexers.Newznab return pageableRequests; } + public virtual IndexerPageableRequestChain GetSearchRequests(AnimeSeasonSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + if (SupportsSearch && Settings.AnimeStandardFormatSearch && searchCriteria.SeasonNumber > 0) + { + AddTvIdPageableRequests(pageableRequests, + Settings.AnimeCategories, + searchCriteria, + $"&season={NewznabifySeasonNumber(searchCriteria.SeasonNumber)}"); + + var queryTitles = TextSearchEngine == "raw" ? searchCriteria.SceneTitles : searchCriteria.CleanSceneTitles; + + foreach (var queryTitle in queryTitles) + { + pageableRequests.Add(GetPagedRequests(MaxPages, + Settings.AnimeCategories, + "tvsearch", + $"&q={NewsnabifyTitle(queryTitle)}&season={NewznabifySeasonNumber(searchCriteria.SeasonNumber)}")); + } + } + + return pageableRequests; + } + public virtual IndexerPageableRequestChain GetSearchRequests(SpecialEpisodeSearchCriteria searchCriteria) { var pageableRequests = new IndexerPageableRequestChain(); diff --git a/src/NzbDrone.Core/Indexers/Nyaa/NyaaRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Nyaa/NyaaRequestGenerator.cs index 9340f0a53..8ef5fb0c7 100644 --- a/src/NzbDrone.Core/Indexers/Nyaa/NyaaRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Nyaa/NyaaRequestGenerator.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using NzbDrone.Common.Http; using NzbDrone.Core.IndexerSearch.Definitions; @@ -92,6 +92,21 @@ namespace NzbDrone.Core.Indexers.Nyaa return pageableRequests; } + public virtual IndexerPageableRequestChain GetSearchRequests(AnimeSeasonSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + foreach (var searchTitle in searchCriteria.SceneTitles.Select(PrepareQuery)) + { + if (Settings.AnimeStandardFormatSearch && searchCriteria.SeasonNumber > 0) + { + pageableRequests.Add(GetPagedRequests(MaxPages, $"{searchTitle}+s{searchCriteria.SeasonNumber:00}")); + } + } + + return pageableRequests; + } + public virtual IndexerPageableRequestChain GetSearchRequests(SpecialEpisodeSearchCriteria searchCriteria) { var pageableRequests = new IndexerPageableRequestChain(); diff --git a/src/NzbDrone.Core/Indexers/RssIndexerRequestGenerator.cs b/src/NzbDrone.Core/Indexers/RssIndexerRequestGenerator.cs index 5be7f884e..31687c00a 100644 --- a/src/NzbDrone.Core/Indexers/RssIndexerRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/RssIndexerRequestGenerator.cs @@ -1,4 +1,4 @@ -using NzbDrone.Common.Http; +using NzbDrone.Common.Http; using NzbDrone.Core.IndexerSearch.Definitions; namespace NzbDrone.Core.Indexers @@ -46,6 +46,11 @@ namespace NzbDrone.Core.Indexers return new IndexerPageableRequestChain(); } + public virtual IndexerPageableRequestChain GetSearchRequests(AnimeSeasonSearchCriteria searchCriteria) + { + return new IndexerPageableRequestChain(); + } + public virtual IndexerPageableRequestChain GetSearchRequests(SpecialEpisodeSearchCriteria searchCriteria) { return new IndexerPageableRequestChain(); diff --git a/src/NzbDrone.Core/Indexers/TorrentRss/TorrentRssIndexerRequestGenerator.cs b/src/NzbDrone.Core/Indexers/TorrentRss/TorrentRssIndexerRequestGenerator.cs index 64df2ca9b..f30bfe6de 100644 --- a/src/NzbDrone.Core/Indexers/TorrentRss/TorrentRssIndexerRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/TorrentRss/TorrentRssIndexerRequestGenerator.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; using NzbDrone.Core.IndexerSearch.Definitions; @@ -43,6 +43,11 @@ namespace NzbDrone.Core.Indexers.TorrentRss return new IndexerPageableRequestChain(); } + public virtual IndexerPageableRequestChain GetSearchRequests(AnimeSeasonSearchCriteria searchCriteria) + { + return new IndexerPageableRequestChain(); + } + public virtual IndexerPageableRequestChain GetSearchRequests(SpecialEpisodeSearchCriteria searchCriteria) { return new IndexerPageableRequestChain(); diff --git a/src/NzbDrone.Core/Indexers/Torrentleech/TorrentleechRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Torrentleech/TorrentleechRequestGenerator.cs index d50e25011..094fd4ce2 100644 --- a/src/NzbDrone.Core/Indexers/Torrentleech/TorrentleechRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Torrentleech/TorrentleechRequestGenerator.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using NzbDrone.Common.Http; using NzbDrone.Core.IndexerSearch.Definitions; @@ -42,6 +42,11 @@ namespace NzbDrone.Core.Indexers.Torrentleech return new IndexerPageableRequestChain(); } + public virtual IndexerPageableRequestChain GetSearchRequests(AnimeSeasonSearchCriteria searchCriteria) + { + return new IndexerPageableRequestChain(); + } + public virtual IndexerPageableRequestChain GetSearchRequests(SpecialEpisodeSearchCriteria searchCriteria) { return new IndexerPageableRequestChain();