Merge pull request #18 from lidarr/feature/indexers

Added: Indexer search and release processing
pull/38/head
Qstick 7 years ago committed by GitHub
commit ae8c766b57

@ -77,26 +77,26 @@ namespace NzbDrone.Api.Indexers
private List<ReleaseResource> GetReleases()
{
if (Request.Query.episodeId != null)
if (Request.Query.albumId != null)
{
return GetEpisodeReleases(Request.Query.episodeId);
return GetAlbumReleases(Request.Query.albumId);
}
return GetRss();
}
private List<ReleaseResource> GetEpisodeReleases(int episodeId)
private List<ReleaseResource> GetAlbumReleases(int albumId)
{
try
{
var decisions = _nzbSearchService.EpisodeSearch(episodeId, true);
var decisions = _nzbSearchService.AlbumSearch(albumId, true, true);
var prioritizedDecisions = _prioritizeDownloadDecision.PrioritizeDecisions(decisions);
return MapDecisions(prioritizedDecisions);
}
catch (Exception ex)
{
_logger.Error(ex, "Episode search failed");
_logger.Error(ex, "Album search failed");
}
return new List<ReleaseResource>();

@ -9,15 +9,11 @@
<audio-search available="yes"/>
</searching>
<categories>
<category id="5000" name="TV">
<subcat id="5070" name="Anime"/>
<subcat id="5080" name="Documentary"/>
<subcat id="5020" name="Foreign"/>
<subcat id="5040" name="HD"/>
<subcat id="5050" name="Other"/>
<subcat id="5030" name="SD"/>
<subcat id="5060" name="Sport"/>
<subcat id="5010" name="WEB-DL"/>
<category id="3000" name="Audio">
<subcat id="3010" name="MP3" description="Audio"/>
<subcat id="3020" name="Video" description="Audio"/>
<subcat id="3030" name="Audiobook" description="Audio"/>
<subcat id="3040" name="Lossless" description="Audio"/>
</category>
<category id="7000" name="Other">
<subcat id="7010" name="Misc"/>

@ -0,0 +1,56 @@
using System.Collections.Generic;
using System.Linq;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Download;
using NzbDrone.Core.IndexerSearch;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
using NzbDrone.Core.Messaging.Commands;
using NzbDrone.Core.Music;
namespace NzbDrone.Core.Test.IndexerSearchTests
{
[TestFixture]
public class ArtistSearchServiceFixture : CoreTest<ArtistSearchService>
{
private Artist _artist;
[SetUp]
public void Setup()
{
_artist = new Artist();
Mocker.GetMock<IArtistService>()
.Setup(s => s.GetArtist(It.IsAny<int>()))
.Returns(_artist);
Mocker.GetMock<ISearchForNzb>()
.Setup(s => s.ArtistSearch(_artist.Id, false, true))
.Returns(new List<DownloadDecision>());
Mocker.GetMock<IProcessDownloadDecisions>()
.Setup(s => s.ProcessDecisions(It.IsAny<List<DownloadDecision>>()))
.Returns(new ProcessedDecisions(new List<DownloadDecision>(), new List<DownloadDecision>(),
new List<DownloadDecision>()));
}
[Test]
public void should_only_include_monitored_albums()
{
_artist.Albums = new List<Album>
{
new Album {Monitored = false},
new Album {Monitored = true}
};
Subject.Execute(new ArtistSearchCommand {ArtistId = _artist.Id, Trigger = CommandTrigger.Manual});
Mocker.GetMock<ISearchForNzb>()
.Verify(v => v.ArtistSearch(_artist.Id, false, true),
Times.Exactly(_artist.Albums.Count(s => s.Monitored)));
}
}
}

@ -12,6 +12,7 @@ using NzbDrone.Core.Messaging.Commands;
namespace NzbDrone.Core.Test.IndexerSearchTests
{
[System.Obsolete("Sonarr TV stuff. Not needed in lidarr.")]
[TestFixture]
public class SeriesSearchServiceFixture : CoreTest<SeriesSearchService>
{

@ -89,7 +89,7 @@ namespace NzbDrone.Core.Test.IndexerTests.NewznabTests
[Test]
public void should_not_throw_on_xml_data_unexpected()
{
GivenCapsResponse(_caps.Replace("5030", "asdf"));
GivenCapsResponse(_caps.Replace("3040", "asdf"));
var result = Subject.GetCapabilities(_settings);

@ -50,15 +50,15 @@ namespace NzbDrone.Core.Test.IndexerTests.NewznabTests
var releaseInfo = releases.First();
releaseInfo.Title.Should().Be("White.Collar.S03E05.720p.HDTV.X264-DIMENSION");
releaseInfo.Title.Should().Be("Brainstorm-Scary Creatures-CD-FLAC-2016-NBFLAC");
releaseInfo.DownloadProtocol.Should().Be(DownloadProtocol.Usenet);
releaseInfo.DownloadUrl.Should().Be("http://nzb.su/getnzb/24967ef4c2e26296c65d3bbfa97aa8fe.nzb&i=37292&r=xxx");
releaseInfo.InfoUrl.Should().Be("http://nzb.su/details/24967ef4c2e26296c65d3bbfa97aa8fe");
releaseInfo.CommentUrl.Should().Be("http://nzb.su/details/24967ef4c2e26296c65d3bbfa97aa8fe#comments");
releaseInfo.DownloadUrl.Should().Be("https://api.nzbgeek.info/api?t=get&id=38884827e1e56b9336278a449e0a38ec&apikey=xxx");
releaseInfo.InfoUrl.Should().Be("https://nzbgeek.info/geekseek.php?guid=38884827e1e56b9336278a449e0a38ec");
releaseInfo.CommentUrl.Should().Be("https://nzbgeek.info/geekseek.php?guid=38884827e1e56b9336278a449e0a38ec");
releaseInfo.IndexerId.Should().Be(Subject.Definition.Id);
releaseInfo.Indexer.Should().Be(Subject.Definition.Name);
releaseInfo.PublishDate.Should().Be(DateTime.Parse("2012/02/27 16:09:39"));
releaseInfo.Size.Should().Be(1183105773);
releaseInfo.PublishDate.Should().Be(DateTime.Parse("2017/05/26 05:54:31"));
releaseInfo.Size.Should().Be(492735000);
}
[Test]

@ -12,7 +12,7 @@ namespace NzbDrone.Core.Test.IndexerTests.NewznabTests
public class NewznabRequestGeneratorFixture : CoreTest<NewznabRequestGenerator>
{
private SingleEpisodeSearchCriteria _singleEpisodeSearchCriteria;
private AnimeEpisodeSearchCriteria _animeSearchCriteria;
private AlbumSearchCriteria _singleAlbumSearchCriteria;
private NewznabCapabilities _capabilities;
[SetUp]
@ -22,7 +22,6 @@ namespace NzbDrone.Core.Test.IndexerTests.NewznabTests
{
Url = "http://127.0.0.1:1234/",
Categories = new [] { 1, 2 },
AnimeCategories = new [] { 3, 4 },
ApiKey = "abcd",
};
@ -34,10 +33,11 @@ namespace NzbDrone.Core.Test.IndexerTests.NewznabTests
EpisodeNumber = 2
};
_animeSearchCriteria = new AnimeEpisodeSearchCriteria()
_singleAlbumSearchCriteria = new AlbumSearchCriteria
{
SceneTitles = new List<string>() { "Monkey+Island" },
AbsoluteEpisodeNumber = 100
Artist = new Music.Artist { Name = "Alien Ant Farm" },
Album = new Music.Album { Title = "TruANT" }
};
_capabilities = new NewznabCapabilities();
@ -56,212 +56,21 @@ namespace NzbDrone.Core.Test.IndexerTests.NewznabTests
var page = results.GetAllTiers().First().First();
page.Url.Query.Should().Contain("&cat=1,2,3,4&");
}
[Test]
public void should_not_have_duplicate_categories()
{
Subject.Settings.Categories = new[] { 1, 2, 3 };
var results = Subject.GetRecentRequests();
results.GetAllTiers().Should().HaveCount(1);
var page = results.GetAllTiers().First().First();
page.Url.FullUri.Should().Contain("&cat=1,2,3,4&");
page.Url.Query.Should().Contain("&cat=1,2&");
}
[Test]
public void should_use_only_anime_categories_for_anime_search()
public void should_search_by_artist_and_album_if_supported()
{
var results = Subject.GetSearchRequests(_animeSearchCriteria);
results.GetAllTiers().Should().HaveCount(1);
var page = results.GetAllTiers().First().First();
page.Url.FullUri.Should().Contain("&cat=3,4&");
}
[Test]
public void should_use_mode_search_for_anime()
{
var results = Subject.GetSearchRequests(_animeSearchCriteria);
results.GetAllTiers().Should().HaveCount(1);
var page = results.GetAllTiers().First().First();
page.Url.FullUri.Should().Contain("?t=search&");
}
[Test]
public void should_return_subsequent_pages()
{
var results = Subject.GetSearchRequests(_animeSearchCriteria);
results.GetAllTiers().Should().HaveCount(1);
_capabilities.SupportedAudioSearchParameters = new[] { "q", "artist", "album"};
var pages = results.GetAllTiers().First().Take(3).ToList();
pages[0].Url.FullUri.Should().Contain("&offset=0&");
pages[1].Url.FullUri.Should().Contain("&offset=100&");
pages[2].Url.FullUri.Should().Contain("&offset=200&");
}
[Test]
public void should_not_get_unlimited_pages()
{
var results = Subject.GetSearchRequests(_animeSearchCriteria);
results.GetAllTiers().Should().HaveCount(1);
var pages = results.GetAllTiers().First().Take(500).ToList();
pages.Count.Should().BeLessThan(500);
}
[Test]
public void should_not_search_by_rid_if_not_supported()
{
_capabilities.SupportedTvSearchParameters = new[] { "q", "season", "ep" };
var results = Subject.GetSearchRequests(_singleEpisodeSearchCriteria);
results.GetAllTiers().Should().HaveCount(1);
var page = results.GetAllTiers().First().First();
page.Url.Query.Should().NotContain("rid=10");
page.Url.Query.Should().Contain("q=Monkey");
}
[Test]
public void should_search_by_rid_if_supported()
{
var results = Subject.GetSearchRequests(_singleEpisodeSearchCriteria);
var results = Subject.GetSearchRequests(_singleAlbumSearchCriteria);
results.GetTier(0).Should().HaveCount(1);
var page = results.GetAllTiers().First().First();
page.Url.Query.Should().Contain("rid=10");
}
[Test]
public void should_not_search_by_tvdbid_if_not_supported()
{
_capabilities.SupportedTvSearchParameters = new[] { "q", "season", "ep" };
var results = Subject.GetSearchRequests(_singleEpisodeSearchCriteria);
results.GetTier(0).Should().HaveCount(1);
var page = results.GetAllTiers().First().First();
page.Url.Query.Should().NotContain("rid=10");
page.Url.Query.Should().Contain("q=Monkey");
}
[Test]
public void should_search_by_tvdbid_if_supported()
{
_capabilities.SupportedTvSearchParameters = new[] { "q", "tvdbid", "season", "ep" };
var results = Subject.GetSearchRequests(_singleEpisodeSearchCriteria);
results.GetTier(0).Should().HaveCount(1);
var page = results.GetAllTiers().First().First();
page.Url.Query.Should().Contain("tvdbid=20");
}
[Test]
public void should_search_by_tvmaze_if_supported()
{
_capabilities.SupportedTvSearchParameters = new[] { "q", "tvmazeid", "season", "ep" };
var results = Subject.GetSearchRequests(_singleEpisodeSearchCriteria);
results.GetTier(0).Should().HaveCount(1);
var page = results.GetAllTiers().First().First();
page.Url.Query.Should().Contain("tvmazeid=30");
}
[Test]
public void should_prefer_search_by_tvdbid_if_rid_supported()
{
_capabilities.SupportedTvSearchParameters = new[] { "q", "tvdbid", "rid", "season", "ep" };
var results = Subject.GetSearchRequests(_singleEpisodeSearchCriteria);
results.GetTier(0).Should().HaveCount(1);
var page = results.GetAllTiers().First().First();
page.Url.Query.Should().Contain("tvdbid=20");
page.Url.Query.Should().NotContain("rid=10");
}
[Test]
public void should_use_aggregrated_id_search_if_supported()
{
_capabilities.SupportedTvSearchParameters = new[] { "q", "tvdbid", "rid", "season", "ep" };
_capabilities.SupportsAggregateIdSearch = true;
var results = Subject.GetSearchRequests(_singleEpisodeSearchCriteria);
results.GetTier(0).Should().HaveCount(1);
var page = results.GetTier(0).First().First();
page.Url.Query.Should().Contain("tvdbid=20");
page.Url.Query.Should().Contain("rid=10");
}
[Test]
public void should_not_use_aggregrated_id_search_if_no_ids_supported()
{
_capabilities.SupportedTvSearchParameters = new[] { "q", "season", "ep" };
_capabilities.SupportsAggregateIdSearch = true; // Turns true if indexer supplies supportedParams.
var results = Subject.GetSearchRequests(_singleEpisodeSearchCriteria);
results.Tiers.Should().Be(1);
results.GetTier(0).Should().HaveCount(1);
var page = results.GetTier(0).First().First();
page.Url.Query.Should().Contain("q=");
}
[Test]
public void should_not_use_aggregrated_id_search_if_no_ids_are_known()
{
_capabilities.SupportedTvSearchParameters = new[] { "q", "rid", "season", "ep" };
_capabilities.SupportsAggregateIdSearch = true; // Turns true if indexer supplies supportedParams.
_singleEpisodeSearchCriteria.Series.TvRageId = 0;
var results = Subject.GetSearchRequests(_singleEpisodeSearchCriteria);
var page = results.GetTier(0).First().First();
page.Url.Query.Should().Contain("q=");
}
[Test]
public void should_fallback_to_q()
{
_capabilities.SupportedTvSearchParameters = new[] { "q", "tvdbid", "rid", "season", "ep" };
_capabilities.SupportsAggregateIdSearch = true;
var results = Subject.GetSearchRequests(_singleEpisodeSearchCriteria);
results.Tiers.Should().Be(2);
var pageTier2 = results.GetTier(1).First().First();
pageTier2.Url.Query.Should().NotContain("tvdbid=20");
pageTier2.Url.Query.Should().NotContain("rid=10");
pageTier2.Url.Query.Should().Contain("q=");
page.Url.Query.Should().Contain("artist=Alien Ant Farm");
page.Url.Query.Should().Contain("album=TruANT");
}
}
}

@ -246,6 +246,7 @@
<Compile Include="Housekeeping\Housekeepers\FixFutureRunScheduledTasksFixture.cs" />
<Compile Include="Http\HttpProxySettingsProviderFixture.cs" />
<Compile Include="Http\TorCacheHttpRequestInterceptorFixture.cs" />
<Compile Include="IndexerSearchTests\ArtistSearchServiceFixture.cs" />
<Compile Include="IndexerSearchTests\SeriesSearchServiceFixture.cs" />
<Compile Include="IndexerSearchTests\NzbSearchServiceFixture.cs" />
<Compile Include="IndexerSearchTests\SearchDefinitionFixture.cs" />

@ -0,0 +1,21 @@
using System.Collections.Generic;
using NzbDrone.Core.Messaging.Commands;
namespace NzbDrone.Core.IndexerSearch
{
class AlbumSearchCommand : Command
{
public List<int> AlbumIds { get; set; }
public override bool SendUpdatesToClient => true;
public AlbumSearchCommand()
{
}
public AlbumSearchCommand(List<int> albumIds)
{
AlbumIds = albumIds;
}
}
}

@ -0,0 +1,35 @@
using NLog;
using NzbDrone.Common.Instrumentation.Extensions;
using NzbDrone.Core.Download;
using NzbDrone.Core.Messaging.Commands;
namespace NzbDrone.Core.IndexerSearch
{
class AlbumSearchService : IExecute<AlbumSearchCommand>
{
private readonly ISearchForNzb _nzbSearchService;
private readonly IProcessDownloadDecisions _processDownloadDecisions;
private readonly Logger _logger;
public AlbumSearchService(ISearchForNzb nzbSearchService,
IProcessDownloadDecisions processDownloadDecisions,
Logger logger)
{
_nzbSearchService = nzbSearchService;
_processDownloadDecisions = processDownloadDecisions;
_logger = logger;
}
public void Execute(AlbumSearchCommand message)
{
foreach (var albumId in message.AlbumIds)
{
var decisions =
_nzbSearchService.AlbumSearch(albumId, false, message.Trigger == CommandTrigger.Manual);
var processed = _processDownloadDecisions.ProcessDecisions(decisions);
_logger.ProgressInfo("Album search completed. {0} reports downloaded.", processed.Grabbed.Count);
}
}
}
}

@ -0,0 +1,11 @@
using NzbDrone.Core.Messaging.Commands;
namespace NzbDrone.Core.IndexerSearch
{
public class ArtistSearchCommand : Command
{
public int ArtistId { get; set; }
public override bool SendUpdatesToClient => true;
}
}

@ -0,0 +1,31 @@
using NLog;
using NzbDrone.Common.Instrumentation.Extensions;
using NzbDrone.Core.Download;
using NzbDrone.Core.Messaging.Commands;
namespace NzbDrone.Core.IndexerSearch
{
public class ArtistSearchService : IExecute<ArtistSearchCommand>
{
private readonly ISearchForNzb _nzbSearchService;
private readonly IProcessDownloadDecisions _processDownloadDecisions;
private readonly Logger _logger;
public ArtistSearchService(ISearchForNzb nzbSearchService,
IProcessDownloadDecisions processDownloadDecisions,
Logger logger)
{
_nzbSearchService = nzbSearchService;
_processDownloadDecisions = processDownloadDecisions;
_logger = logger;
}
public void Execute(ArtistSearchCommand message)
{
var decisions = _nzbSearchService.ArtistSearch(message.ArtistId, false, message.Trigger == CommandTrigger.Manual);
var processed = _processDownloadDecisions.ProcessDecisions(decisions);
_logger.ProgressInfo("Artist search completed. {0} reports downloaded.", processed.Grabbed.Count);
}
}
}

@ -0,0 +1,21 @@
using System;
namespace NzbDrone.Core.IndexerSearch.Definitions
{
public class AlbumSearchCriteria : SearchCriteriaBase
{
public override string ToString()
{
var baseRepresentation = $"[{Artist.Name} - {Album.Title}]";
if (Album.ReleaseDate.HasValue)
{
var beforeLast = baseRepresentation.Length - 1;
return baseRepresentation.Insert(beforeLast, $" ({Album.ReleaseDate.Value.Year})");
}
else
{
return baseRepresentation;
}
}
}
}

@ -0,0 +1,12 @@
using System;
namespace NzbDrone.Core.IndexerSearch.Definitions
{
public class ArtistSearchCriteria : SearchCriteriaBase
{
public override string ToString()
{
return $"[{Artist.Name}]";
}
}
}

@ -14,13 +14,17 @@ namespace NzbDrone.Core.IndexerSearch.Definitions
private static readonly Regex NonWord = new Regex(@"[\W]", RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static readonly Regex BeginningThe = new Regex(@"^the\s", RegexOptions.IgnoreCase | RegexOptions.Compiled);
[System.Obsolete("Sonarr TV Stuff -- Shouldn't be needed for Lidarr")]
public Series Series { get; set; }
[System.Obsolete("Sonarr TV Stuff -- Shouldn't be needed for Lidarr")]
public List<string> SceneTitles { get; set; }
[System.Obsolete("Sonarr TV Stuff -- Shouldn't be needed for Lidarr")]
public List<Episode> Episodes { get; set; }
public virtual bool MonitoredEpisodesOnly { get; set; }
public virtual bool UserInvokedSearch { get; set; }
public Artist Artist { get; set; }
public Album Album { get; set; }
public List<Track> Tracks { get; set; }
public List<string> QueryTitles => SceneTitles.Select(GetQueryTitle).ToList();

@ -12,6 +12,7 @@ using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Tv;
using System.Linq;
using NzbDrone.Common.TPL;
using NzbDrone.Core.Music;
namespace NzbDrone.Core.IndexerSearch
{
@ -20,21 +21,28 @@ namespace NzbDrone.Core.IndexerSearch
List<DownloadDecision> EpisodeSearch(int episodeId, bool userInvokedSearch);
List<DownloadDecision> EpisodeSearch(Episode episode, bool userInvokedSearch);
List<DownloadDecision> SeasonSearch(int seriesId, int seasonNumber, bool missingOnly, bool userInvokedSearch);
List<DownloadDecision> AlbumSearch(int albumId, bool missingOnly, bool userInvokedSearch);
List<DownloadDecision> ArtistSearch(int artistId, bool missingOnly, bool userInvokedSearch);
}
public class NzbSearchService : ISearchForNzb
{
private readonly IIndexerFactory _indexerFactory;
// private readonly ISceneMappingService _sceneMapping;
[System.Obsolete("Used for sonarr, not lidarr")]
private readonly ISeriesService _seriesService;
[System.Obsolete("Used for sonarr, not lidarr")]
private readonly IEpisodeService _episodeService;
private readonly IAlbumService _albumService;
private readonly IArtistService _artistService;
private readonly IMakeDownloadDecision _makeDownloadDecision;
private readonly Logger _logger;
public NzbSearchService(IIndexerFactory indexerFactory,
// ISceneMappingService sceneMapping,
ISeriesService seriesService,
IEpisodeService episodeService,
IAlbumService albumService,
IArtistService artistService,
IMakeDownloadDecision makeDownloadDecision,
Logger logger)
{
@ -42,6 +50,8 @@ namespace NzbDrone.Core.IndexerSearch
//_sceneMapping = sceneMapping;
_seriesService = seriesService;
_episodeService = episodeService;
_albumService = albumService;
_artistService = artistService;
_makeDownloadDecision = makeDownloadDecision;
_logger = logger;
}
@ -158,6 +168,30 @@ namespace NzbDrone.Core.IndexerSearch
return downloadDecisions;
}
public List<DownloadDecision> AlbumSearch(int albumId, bool missingOnly, bool userInvokedSearch)
{
var album = _albumService.GetAlbum(albumId);
return AlbumSearch(album, missingOnly, userInvokedSearch);
}
public List<DownloadDecision> ArtistSearch(int artistId, bool missingOnly, bool userInvokedSearch)
{
var artist = _artistService.GetArtist(artistId);
return ArtistSearch(artist, missingOnly, userInvokedSearch);
}
public List<DownloadDecision> ArtistSearch(Artist artist, bool missingOnly, bool userInvokedSearch)
{
var searchSpec = Get<ArtistSearchCriteria>(artist, userInvokedSearch);
return Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec);
}
public List<DownloadDecision> AlbumSearch(Album album, bool missingOnly, bool userInvokedSearch)
{
var searchSpec = Get<AlbumSearchCriteria>(album, userInvokedSearch);
return Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec);
}
private List<DownloadDecision> SearchSingle(Series series, Episode episode, bool userInvokedSearch)
{
var searchSpec = Get<SingleEpisodeSearchCriteria>(series, new List<Episode> { episode }, userInvokedSearch);
@ -245,6 +279,26 @@ namespace NzbDrone.Core.IndexerSearch
return spec;
}
private TSpec Get<TSpec>(Album album, bool userInvokedSearch) where TSpec : SearchCriteriaBase, new()
{
var spec = new TSpec();
spec.Album = album;
spec.Artist = _artistService.GetArtist(album.ArtistId);
spec.UserInvokedSearch = userInvokedSearch;
return spec;
}
private static TSpec Get<TSpec>(Artist artist, bool userInvokedSearch) where TSpec : SearchCriteriaBase, new()
{
var spec = new TSpec();
spec.Artist = artist;
spec.UserInvokedSearch = userInvokedSearch;
return spec;
}
private List<DownloadDecision> Dispatch(Func<IIndexer, IEnumerable<ReleaseInfo>> searchAction, SearchCriteriaBase criteriaBase)
{
var indexers = _indexerFactory.SearchEnabled();

@ -42,6 +42,16 @@ namespace NzbDrone.Core.Indexers.BitMeTv
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(AlbumSearchCriteria searchCriteria)
{
throw new System.NotImplementedException();
}
public virtual IndexerPageableRequestChain GetSearchRequests(ArtistSearchCriteria searchCriteria)
{
throw new System.NotImplementedException();
}
private IEnumerable<IndexerRequest> GetRssRequests()
{
var request = new IndexerRequest(string.Format("{0}/rss.php?uid={1}&passkey={2}", Settings.BaseUrl.Trim().TrimEnd('/'), Settings.UserId, Settings.RssPasskey), HttpAccept.Html);

@ -160,6 +160,16 @@ namespace NzbDrone.Core.Indexers.BroadcastheNet
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(AlbumSearchCriteria searchCriteria)
{
throw new System.NotImplementedException();
}
public virtual IndexerPageableRequestChain GetSearchRequests(ArtistSearchCriteria searchCriteria)
{
throw new System.NotImplementedException();
}
private bool AddSeriesSearchParameters(BroadcastheNetTorrentQuery parameters, SearchCriteriaBase searchCriteria)
{
if (searchCriteria.Series.TvdbId != 0)

@ -60,6 +60,16 @@ namespace NzbDrone.Core.Indexers.Fanzub
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(AlbumSearchCriteria searchCriteria)
{
throw new System.NotImplementedException();
}
public virtual IndexerPageableRequestChain GetSearchRequests(ArtistSearchCriteria searchCriteria)
{
throw new System.NotImplementedException();
}
private IEnumerable<IndexerRequest> GetPagedRequests(string query)
{
var url = new StringBuilder();

@ -43,6 +43,16 @@ namespace NzbDrone.Core.Indexers.HDBits
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(AlbumSearchCriteria searchCriteria)
{
throw new System.NotImplementedException();
}
public virtual IndexerPageableRequestChain GetSearchRequests(ArtistSearchCriteria searchCriteria)
{
throw new System.NotImplementedException();
}
public virtual IndexerPageableRequestChain GetSearchRequests(DailyEpisodeSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();

@ -51,6 +51,7 @@ namespace NzbDrone.Core.Indexers
return FetchReleases(generator.GetRecentRequests(), true);
}
[System.Obsolete("Sonarr TV Stuff -- Shouldn't be needed for Lidarr")]
public override IList<ReleaseInfo> Fetch(SingleEpisodeSearchCriteria searchCriteria)
{
if (!SupportsSearch)
@ -63,6 +64,7 @@ namespace NzbDrone.Core.Indexers
return FetchReleases(generator.GetSearchRequests(searchCriteria));
}
[System.Obsolete("Sonarr TV Stuff -- Shouldn't be needed for Lidarr")]
public override IList<ReleaseInfo> Fetch(SeasonSearchCriteria searchCriteria)
{
if (!SupportsSearch)
@ -75,6 +77,7 @@ namespace NzbDrone.Core.Indexers
return FetchReleases(generator.GetSearchRequests(searchCriteria));
}
[System.Obsolete("Sonarr TV Stuff -- Shouldn't be needed for Lidarr")]
public override IList<ReleaseInfo> Fetch(DailyEpisodeSearchCriteria searchCriteria)
{
if (!SupportsSearch)
@ -87,6 +90,7 @@ namespace NzbDrone.Core.Indexers
return FetchReleases(generator.GetSearchRequests(searchCriteria));
}
[System.Obsolete("Sonarr TV Stuff -- Shouldn't be needed for Lidarr")]
public override IList<ReleaseInfo> Fetch(AnimeEpisodeSearchCriteria searchCriteria)
{
if (!SupportsSearch)
@ -99,6 +103,7 @@ namespace NzbDrone.Core.Indexers
return FetchReleases(generator.GetSearchRequests(searchCriteria));
}
[System.Obsolete("Sonarr TV Stuff -- Shouldn't be needed for Lidarr")]
public override IList<ReleaseInfo> Fetch(SpecialEpisodeSearchCriteria searchCriteria)
{
if (!SupportsSearch)
@ -111,6 +116,30 @@ namespace NzbDrone.Core.Indexers
return FetchReleases(generator.GetSearchRequests(searchCriteria));
}
public override IList<ReleaseInfo> Fetch(AlbumSearchCriteria searchCriteria)
{
if (!SupportsSearch)
{
return new List<ReleaseInfo>();
}
var generator = GetRequestGenerator();
return FetchReleases(generator.GetSearchRequests(searchCriteria));
}
public override IList<ReleaseInfo> Fetch(ArtistSearchCriteria searchCriteria)
{
if (!SupportsSearch)
{
return new List<ReleaseInfo>();
}
var generator = GetRequestGenerator();
return FetchReleases(generator.GetSearchRequests(searchCriteria));
}
protected virtual IList<ReleaseInfo> FetchReleases(IndexerPageableRequestChain pageableRequestChain, bool isRecent = false)
{
var releases = new List<ReleaseInfo>();

@ -12,10 +12,17 @@ namespace NzbDrone.Core.Indexers
DownloadProtocol Protocol { get; }
IList<ReleaseInfo> FetchRecent();
[System.Obsolete("Sonarr TV Stuff -- Shouldn't be needed for Lidarr")]
IList<ReleaseInfo> Fetch(SeasonSearchCriteria searchCriteria);
[System.Obsolete("Sonarr TV Stuff -- Shouldn't be needed for Lidarr")]
IList<ReleaseInfo> Fetch(SingleEpisodeSearchCriteria searchCriteria);
[System.Obsolete("Sonarr TV Stuff -- Shouldn't be needed for Lidarr")]
IList<ReleaseInfo> Fetch(DailyEpisodeSearchCriteria searchCriteria);
[System.Obsolete("Sonarr TV Stuff -- Shouldn't be needed for Lidarr")]
IList<ReleaseInfo> Fetch(AnimeEpisodeSearchCriteria searchCriteria);
[System.Obsolete("Sonarr TV Stuff -- Shouldn't be needed for Lidarr")]
IList<ReleaseInfo> Fetch(SpecialEpisodeSearchCriteria searchCriteria);
IList<ReleaseInfo> Fetch(AlbumSearchCriteria searchCriteria);
IList<ReleaseInfo> Fetch(ArtistSearchCriteria searchCriteria);
}
}

@ -10,5 +10,7 @@ namespace NzbDrone.Core.Indexers
IndexerPageableRequestChain GetSearchRequests(DailyEpisodeSearchCriteria searchCriteria);
IndexerPageableRequestChain GetSearchRequests(AnimeEpisodeSearchCriteria searchCriteria);
IndexerPageableRequestChain GetSearchRequests(SpecialEpisodeSearchCriteria searchCriteria);
IndexerPageableRequestChain GetSearchRequests(AlbumSearchCriteria searchCriteria);
IndexerPageableRequestChain GetSearchRequests(ArtistSearchCriteria searchCriteria);
}
}

@ -42,6 +42,16 @@ namespace NzbDrone.Core.Indexers.IPTorrents
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(AlbumSearchCriteria searchCriteria)
{
throw new System.NotImplementedException();
}
public virtual IndexerPageableRequestChain GetSearchRequests(ArtistSearchCriteria searchCriteria)
{
throw new System.NotImplementedException();
}
private IEnumerable<IndexerRequest> GetRssRequests()
{
yield return new IndexerRequest(Settings.Url, HttpAccept.Rss);

@ -62,11 +62,19 @@ namespace NzbDrone.Core.Indexers
protected TSettings Settings => (TSettings)Definition.Settings;
public abstract IList<ReleaseInfo> FetchRecent();
[System.Obsolete("Sonarr TV Stuff -- Shouldn't be needed for Lidarr")]
public abstract IList<ReleaseInfo> Fetch(SeasonSearchCriteria searchCriteria);
[System.Obsolete("Sonarr TV Stuff -- Shouldn't be needed for Lidarr")]
public abstract IList<ReleaseInfo> Fetch(SingleEpisodeSearchCriteria searchCriteria);
[System.Obsolete("Sonarr TV Stuff -- Shouldn't be needed for Lidarr")]
public abstract IList<ReleaseInfo> Fetch(DailyEpisodeSearchCriteria searchCriteria);
[System.Obsolete("Sonarr TV Stuff -- Shouldn't be needed for Lidarr")]
public abstract IList<ReleaseInfo> Fetch(AnimeEpisodeSearchCriteria searchCriteria);
[System.Obsolete("Sonarr TV Stuff -- Shouldn't be needed for Lidarr")]
public abstract IList<ReleaseInfo> Fetch(SpecialEpisodeSearchCriteria searchCriteria);
public abstract IList<ReleaseInfo> Fetch(AlbumSearchCriteria searchCriteria);
public abstract IList<ReleaseInfo> Fetch(ArtistSearchCriteria searchCriteria);
protected virtual IList<ReleaseInfo> CleanupReleases(IEnumerable<ReleaseInfo> releases)
{

@ -106,6 +106,12 @@ namespace NzbDrone.Core.Indexers.Newznab
return null;
}
if (capabilities.SupportedAudioSearchParameters != null &&
new[] { "artist", "album" }.All(v => capabilities.SupportedAudioSearchParameters.Contains(v)))
{
return null;
}
if (capabilities.SupportedTvSearchParameters != null &&
new[] { "q", "tvdbid", "rid" }.Any(v => capabilities.SupportedTvSearchParameters.Contains(v)) &&
new[] { "season", "ep" }.All(v => capabilities.SupportedTvSearchParameters.Contains(v)))

@ -8,6 +8,7 @@ namespace NzbDrone.Core.Indexers.Newznab
public int MaxPageSize { get; set; }
public string[] SupportedSearchParameters { get; set; }
public string[] SupportedTvSearchParameters { get; set; }
public string[] SupportedAudioSearchParameters { get; set; }
public bool SupportsAggregateIdSearch { get; set; }
public List<NewznabCategory> Categories { get; set; }
@ -17,6 +18,7 @@ namespace NzbDrone.Core.Indexers.Newznab
MaxPageSize = 100;
SupportedSearchParameters = new[] { "q" };
SupportedTvSearchParameters = new[] { "q", "rid", "season", "ep" }; // This should remain 'rid' for older newznab installs.
SupportedAudioSearchParameters = new[] { "q", "artist", "album" };
SupportsAggregateIdSearch = false;
Categories = new List<NewznabCategory>();
}

@ -115,6 +115,16 @@ namespace NzbDrone.Core.Indexers.Newznab
capabilities.SupportedTvSearchParameters = xmlTvSearch.Attribute("supportedParams").Value.Split(',');
capabilities.SupportsAggregateIdSearch = true;
}
var xmlAudioSearch = xmlSearching.Element("audio-search");
if (xmlAudioSearch == null || xmlAudioSearch.Attribute("available").Value != "yes")
{
capabilities.SupportedAudioSearchParameters = null;
}
else if (xmlAudioSearch.Attribute("supportedParams") != null)
{
capabilities.SupportedAudioSearchParameters = xmlAudioSearch.Attribute("supportedParams").Value.Split(',');
}
}
var xmlCategories = xmlRoot.Element("categories");

@ -45,6 +45,21 @@ namespace NzbDrone.Core.Indexers.Newznab
}
}
private bool SupportsAudioSearch
{
get
{
var capabilities = _capabilitiesProvider.GetCapabilities(Settings);
return capabilities.SupportedAudioSearchParameters != null &&
capabilities.SupportedAudioSearchParameters.Contains("q") &&
capabilities.SupportedAudioSearchParameters.Contains("artist") &&
capabilities.SupportedAudioSearchParameters.Contains("album");
}
}
private bool SupportsTvdbSearch
{
get
@ -100,9 +115,9 @@ namespace NzbDrone.Core.Indexers.Newznab
var capabilities = _capabilitiesProvider.GetCapabilities(Settings);
if (capabilities.SupportedTvSearchParameters != null)
if (capabilities.SupportedAudioSearchParameters != null)
{
pageableRequests.Add(GetPagedRequests(MaxPages, Settings.Categories.Concat(Settings.AnimeCategories), "tvsearch", ""));
pageableRequests.Add(GetPagedRequests(MaxPages, Settings.Categories, "music", ""));
}
return pageableRequests;
@ -180,6 +195,29 @@ namespace NzbDrone.Core.Indexers.Newznab
return pageableRequests;
}
public virtual IndexerPageableRequestChain GetSearchRequests(AlbumSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
AddAudioPageableRequests(pageableRequests,
string.Format("&artist={0}&album={1}",
searchCriteria.Artist.Name,
searchCriteria.Album.Title));
return pageableRequests;
}
public virtual IndexerPageableRequestChain GetSearchRequests(ArtistSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
AddAudioPageableRequests(pageableRequests,
string.Format("&artist={0}",
searchCriteria.Artist.Name));
return pageableRequests;
}
private void AddTvIdPageableRequests(IndexerPageableRequestChain chain, int maxPages, IEnumerable<int> categories, SearchCriteriaBase searchCriteria, string parameters)
{
var includeTvdbSearch = SupportsTvdbSearch && searchCriteria.Series.TvdbId > 0;
@ -240,6 +278,20 @@ namespace NzbDrone.Core.Indexers.Newznab
}
}
private void AddAudioPageableRequests(IndexerPageableRequestChain chain, string parameters)
{
if (SupportsAudioSearch)
{
chain.AddTier();
chain.Add(GetPagedRequests(MaxPages, Settings.Categories, "music",
string.Format("&q={0}",
parameters)));
}
}
private IEnumerable<IndexerRequest> GetPagedRequests(int maxPages, IEnumerable<int> categories, string searchType, string parameters)
{
if (categories.Empty())

@ -74,6 +74,16 @@ namespace NzbDrone.Core.Indexers.Nyaa
return pageableRequests;
}
public virtual IndexerPageableRequestChain GetSearchRequests(AlbumSearchCriteria searchCriteria)
{
throw new System.NotImplementedException();
}
public virtual IndexerPageableRequestChain GetSearchRequests(ArtistSearchCriteria searchCriteria)
{
throw new System.NotImplementedException();
}
private IEnumerable<IndexerRequest> GetPagedRequests(int maxPages, string term)
{
var baseUrl = string.Format("{0}/?page=rss{1}", Settings.BaseUrl.TrimEnd('/'), Settings.AdditionalParameters);

@ -88,10 +88,37 @@ namespace NzbDrone.Core.Indexers.Omgwtfnzbs
return pageableRequests;
}
public virtual IndexerPageableRequestChain GetSearchRequests(AlbumSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests(string.Format("{0}+{1}",
searchCriteria.Artist.Name,
searchCriteria.Album.Title)));
return pageableRequests;
}
public virtual IndexerPageableRequestChain GetSearchRequests(ArtistSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests(string.Format("{0}",
searchCriteria.Artist.Name)));
return pageableRequests;
}
private IEnumerable<IndexerRequest> GetPagedRequests(string query)
{
var url = new StringBuilder();
url.AppendFormat("{0}?catid=19,20&user={1}&api={2}&eng=1&delay={3}", BaseUrl, Settings.Username, Settings.ApiKey, Settings.Delay);
// Category 22 is Music-FLAC, category 7 is Music-MP3
url.AppendFormat("{0}?catid=22,7&user={1}&api={2}&eng=1&delay={3}", BaseUrl, Settings.Username, Settings.ApiKey, Settings.Delay);
if (query.IsNotNullOrWhiteSpace())
{

@ -18,6 +18,7 @@ namespace NzbDrone.Core.Indexers.Rarbg
public override string Name => "Rarbg";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override TimeSpan RateLimit => TimeSpan.FromSeconds(2);
public Rarbg(IRarbgTokenProvider tokenProvider, IHttpClient httpClient, IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger)

@ -25,6 +25,7 @@ namespace NzbDrone.Core.Indexers.Rarbg
return pageableRequests;
}
[System.Obsolete("Sonarr TV Stuff -- Shouldn't be needed for Lidarr")]
public virtual IndexerPageableRequestChain GetSearchRequests(SingleEpisodeSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
@ -34,6 +35,7 @@ namespace NzbDrone.Core.Indexers.Rarbg
return pageableRequests;
}
[System.Obsolete("Sonarr TV Stuff -- Shouldn't be needed for Lidarr")]
public virtual IndexerPageableRequestChain GetSearchRequests(SeasonSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
@ -43,6 +45,7 @@ namespace NzbDrone.Core.Indexers.Rarbg
return pageableRequests;
}
[System.Obsolete("Sonarr TV Stuff -- Shouldn't be needed for Lidarr")]
public virtual IndexerPageableRequestChain GetSearchRequests(DailyEpisodeSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
@ -52,11 +55,13 @@ namespace NzbDrone.Core.Indexers.Rarbg
return pageableRequests;
}
[System.Obsolete("Sonarr TV Stuff -- Shouldn't be needed for Lidarr")]
public virtual IndexerPageableRequestChain GetSearchRequests(AnimeEpisodeSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();
}
[System.Obsolete("Sonarr TV Stuff -- Shouldn't be needed for Lidarr")]
public virtual IndexerPageableRequestChain GetSearchRequests(SpecialEpisodeSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
@ -72,6 +77,24 @@ namespace NzbDrone.Core.Indexers.Rarbg
return pageableRequests;
}
public virtual IndexerPageableRequestChain GetSearchRequests(AlbumSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests("search", null, "{0}+{1}", searchCriteria.Artist.Name, searchCriteria.Album.Title));
return pageableRequests;
}
public virtual IndexerPageableRequestChain GetSearchRequests(ArtistSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests("search", null, "{0}", searchCriteria.Artist.Name));
return pageableRequests;
}
private IEnumerable<IndexerRequest> GetPagedRequests(string mode, int? tvdbId, string query, params object[] args)
{
var requestBuilder = new HttpRequestBuilder(Settings.BaseUrl)
@ -101,7 +124,7 @@ namespace NzbDrone.Core.Indexers.Rarbg
requestBuilder.AddQueryParam("ranked", "0");
}
requestBuilder.AddQueryParam("category", "18;41;49");
requestBuilder.AddQueryParam("category", "1;23;24;25;26");
requestBuilder.AddQueryParam("limit", "100");
requestBuilder.AddQueryParam("token", _tokenProvider.GetToken(Settings));
requestBuilder.AddQueryParam("format", "json_extended");

@ -46,5 +46,15 @@ namespace NzbDrone.Core.Indexers
{
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(AlbumSearchCriteria searchCriteria)
{
throw new System.NotImplementedException();
}
public virtual IndexerPageableRequestChain GetSearchRequests(ArtistSearchCriteria searchCriteria)
{
throw new System.NotImplementedException();
}
}
}

@ -43,6 +43,16 @@ namespace NzbDrone.Core.Indexers.TorrentRss
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(AlbumSearchCriteria searchCriteria)
{
throw new System.NotImplementedException();
}
public virtual IndexerPageableRequestChain GetSearchRequests(ArtistSearchCriteria searchCriteria)
{
throw new System.NotImplementedException();
}
private IEnumerable<IndexerRequest> GetRssRequests(string searchParameters)
{
var request = new IndexerRequest(Settings.BaseUrl.Trim().TrimEnd('/'), HttpAccept.Rss);

@ -42,6 +42,16 @@ namespace NzbDrone.Core.Indexers.Torrentleech
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(AlbumSearchCriteria searchCriteria)
{
throw new System.NotImplementedException();
}
public virtual IndexerPageableRequestChain GetSearchRequests(ArtistSearchCriteria searchCriteria)
{
throw new System.NotImplementedException();
}
private IEnumerable<IndexerRequest> GetRssRequests(string searchParameters)
{
yield return new IndexerRequest(string.Format("{0}/{1}{2}", Settings.BaseUrl.Trim().TrimEnd('/'), Settings.ApiKey, searchParameters), HttpAccept.Rss);

@ -605,6 +605,12 @@
<Compile Include="Http\CloudFlare\CloudFlareHttpInterceptor.cs" />
<Compile Include="Http\HttpProxySettingsProvider.cs" />
<Compile Include="Http\TorcacheHttpInterceptor.cs" />
<Compile Include="IndexerSearch\AlbumSearchCommand.cs" />
<Compile Include="IndexerSearch\AlbumSearchService.cs" />
<Compile Include="IndexerSearch\ArtistSearchCommand.cs" />
<Compile Include="IndexerSearch\ArtistSearchService.cs" />
<Compile Include="IndexerSearch\Definitions\AlbumSearchCriteria.cs" />
<Compile Include="IndexerSearch\Definitions\ArtistSearchCriteria.cs" />
<Compile Include="Indexers\BitMeTv\BitMeTv.cs" />
<Compile Include="Indexers\BitMeTv\BitMeTvSettings.cs" />
<Compile Include="Indexers\BitMeTv\BitMeTvRequestGenerator.cs" />

@ -42,8 +42,8 @@ module.exports = Marionette.Layout.extend({
e.preventDefault();
}
CommandController.Execute('episodeSearch', {
episodeIds : [this.model.get('id')] //TODO Refactor for Albums search
CommandController.Execute('albumSearch', {
albumId : this.model.get('id')
});
vent.trigger(vent.Commands.CloseModalCommand);
@ -56,7 +56,7 @@ module.exports = Marionette.Layout.extend({
this.mainView = new LoadingView();
this._showMainView();
this.releaseCollection.fetchEpisodeReleases(this.model.id); //TODO Refactor for Albums
this.releaseCollection.fetchAlbumReleases(this.model.id);
},
_showMainView : function() {

@ -154,7 +154,7 @@ module.exports = Marionette.Layout.extend({
command : {
name : 'albumSearch',
artistId : this.artist.id,
albumId : this.model.get('id')
albumIds : [this.model.get('id')]
}
});
@ -182,7 +182,7 @@ module.exports = Marionette.Layout.extend({
CommandController.Execute('albumSearch', {
name : 'albumSearch',
artistId : this.artist.id,
albumId : this.model.get('id')
albumIds : [this.model.get('id')]
});
},

@ -46,8 +46,8 @@ var Collection = PagableCollection.extend({
}
},
fetchEpisodeReleases : function(episodeId) {
return this.fetch({ data : { episodeId : episodeId } });
fetchAlbumReleases : function(albumId) {
return this.fetch({ data : { albumId : albumId } });
}
});

Loading…
Cancel
Save