diff --git a/src/NzbDrone.Core/IndexerSearch/AlbumSearchCommand.cs b/src/NzbDrone.Core/IndexerSearch/AlbumSearchCommand.cs new file mode 100644 index 000000000..d4c7b7c22 --- /dev/null +++ b/src/NzbDrone.Core/IndexerSearch/AlbumSearchCommand.cs @@ -0,0 +1,11 @@ +using NzbDrone.Core.Messaging.Commands; + +namespace NzbDrone.Core.IndexerSearch +{ + class AlbumSearchCommand : Command + { + public int AlbumId { get; set; } + + public override bool SendUpdatesToClient => true; + } +} diff --git a/src/NzbDrone.Core/IndexerSearch/AlbumSearchService.cs b/src/NzbDrone.Core/IndexerSearch/AlbumSearchService.cs new file mode 100644 index 000000000..22a098421 --- /dev/null +++ b/src/NzbDrone.Core/IndexerSearch/AlbumSearchService.cs @@ -0,0 +1,31 @@ +using NLog; +using NzbDrone.Common.Instrumentation.Extensions; +using NzbDrone.Core.Download; +using NzbDrone.Core.Messaging.Commands; + +namespace NzbDrone.Core.IndexerSearch +{ + class AlbumSearchService : IExecute + { + 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) + { + var decisions = _nzbSearchService.AlbumSearch(message.AlbumId, false, message.Trigger == CommandTrigger.Manual); + var processed = _processDownloadDecisions.ProcessDecisions(decisions); + + _logger.ProgressInfo("Album search completed. {0} reports downloaded.", processed.Grabbed.Count); + } + } +} diff --git a/src/NzbDrone.Core/IndexerSearch/Definitions/AlbumSearchCriteria.cs b/src/NzbDrone.Core/IndexerSearch/Definitions/AlbumSearchCriteria.cs new file mode 100644 index 000000000..53542b5c5 --- /dev/null +++ b/src/NzbDrone.Core/IndexerSearch/Definitions/AlbumSearchCriteria.cs @@ -0,0 +1,12 @@ +using System; + +namespace NzbDrone.Core.IndexerSearch.Definitions +{ + public class AlbumSearchCriteria : SearchCriteriaBase + { + public override string ToString() + { + return $"[{Album.Title}]"; + } + } +} diff --git a/src/NzbDrone.Core/IndexerSearch/Definitions/SearchCriteriaBase.cs b/src/NzbDrone.Core/IndexerSearch/Definitions/SearchCriteriaBase.cs index 630f5edc1..00b802c68 100644 --- a/src/NzbDrone.Core/IndexerSearch/Definitions/SearchCriteriaBase.cs +++ b/src/NzbDrone.Core/IndexerSearch/Definitions/SearchCriteriaBase.cs @@ -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 SceneTitles { get; set; } + [System.Obsolete("Sonarr TV Stuff -- Shouldn't be needed for Lidarr")] public List 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 Tracks { get; set; } public List QueryTitles => SceneTitles.Select(GetQueryTitle).ToList(); diff --git a/src/NzbDrone.Core/IndexerSearch/NzbSearchService.cs b/src/NzbDrone.Core/IndexerSearch/NzbSearchService.cs index 3e552e7ae..c5019f638 100644 --- a/src/NzbDrone.Core/IndexerSearch/NzbSearchService.cs +++ b/src/NzbDrone.Core/IndexerSearch/NzbSearchService.cs @@ -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,14 +21,19 @@ namespace NzbDrone.Core.IndexerSearch List EpisodeSearch(int episodeId, bool userInvokedSearch); List EpisodeSearch(Episode episode, bool userInvokedSearch); List SeasonSearch(int seriesId, int seasonNumber, bool missingOnly, bool userInvokedSearch); + List AlbumSearch(int albumId, 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 IMakeDownloadDecision _makeDownloadDecision; private readonly Logger _logger; @@ -35,6 +41,7 @@ namespace NzbDrone.Core.IndexerSearch // ISceneMappingService sceneMapping, ISeriesService seriesService, IEpisodeService episodeService, + IAlbumService albumService, IMakeDownloadDecision makeDownloadDecision, Logger logger) { @@ -42,6 +49,7 @@ namespace NzbDrone.Core.IndexerSearch //_sceneMapping = sceneMapping; _seriesService = seriesService; _episodeService = episodeService; + _albumService = albumService; _makeDownloadDecision = makeDownloadDecision; _logger = logger; } @@ -158,6 +166,18 @@ namespace NzbDrone.Core.IndexerSearch return downloadDecisions; } + public List AlbumSearch(int albumId, bool missingOnly, bool userInvokedSearch) + { + var album = _albumService.GetAlbum(1); + return AlbumSearch(album, missingOnly, userInvokedSearch); + } + + public List AlbumSearch(Album album, bool missingOnly, bool userInvokedSearch) + { + var searchSpec = Get(album, userInvokedSearch); + return Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec); + } + private List SearchSingle(Series series, Episode episode, bool userInvokedSearch) { var searchSpec = Get(series, new List { episode }, userInvokedSearch); @@ -245,6 +265,16 @@ namespace NzbDrone.Core.IndexerSearch return spec; } + private TSpec Get(Album album, bool userInvokedSearch) where TSpec : SearchCriteriaBase, new() + { + var spec = new TSpec(); + + spec.Album = album; + spec.UserInvokedSearch = userInvokedSearch; + + return spec; + } + private List Dispatch(Func> searchAction, SearchCriteriaBase criteriaBase) { var indexers = _indexerFactory.SearchEnabled(); diff --git a/src/NzbDrone.Core/Indexers/BitMeTv/BitMeTvRequestGenerator.cs b/src/NzbDrone.Core/Indexers/BitMeTv/BitMeTvRequestGenerator.cs index e7966dcba..0bae81fee 100644 --- a/src/NzbDrone.Core/Indexers/BitMeTv/BitMeTvRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/BitMeTv/BitMeTvRequestGenerator.cs @@ -42,6 +42,11 @@ namespace NzbDrone.Core.Indexers.BitMeTv return new IndexerPageableRequestChain(); } + public IndexerPageableRequestChain GetSearchRequests(AlbumSearchCriteria searchCriteria) + { + throw new System.NotImplementedException(); + } + private IEnumerable GetRssRequests() { var request = new IndexerRequest(string.Format("{0}/rss.php?uid={1}&passkey={2}", Settings.BaseUrl.Trim().TrimEnd('/'), Settings.UserId, Settings.RssPasskey), HttpAccept.Html); diff --git a/src/NzbDrone.Core/Indexers/BroadcastheNet/BroadcastheNetRequestGenerator.cs b/src/NzbDrone.Core/Indexers/BroadcastheNet/BroadcastheNetRequestGenerator.cs index b5a39a94c..ce63db668 100644 --- a/src/NzbDrone.Core/Indexers/BroadcastheNet/BroadcastheNetRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/BroadcastheNet/BroadcastheNetRequestGenerator.cs @@ -160,6 +160,11 @@ namespace NzbDrone.Core.Indexers.BroadcastheNet return new IndexerPageableRequestChain(); } + public IndexerPageableRequestChain GetSearchRequests(AlbumSearchCriteria searchCriteria) + { + throw new System.NotImplementedException(); + } + private bool AddSeriesSearchParameters(BroadcastheNetTorrentQuery parameters, SearchCriteriaBase searchCriteria) { if (searchCriteria.Series.TvdbId != 0) diff --git a/src/NzbDrone.Core/Indexers/Fanzub/FanzubRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Fanzub/FanzubRequestGenerator.cs index 19585dad5..519a31da2 100644 --- a/src/NzbDrone.Core/Indexers/Fanzub/FanzubRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Fanzub/FanzubRequestGenerator.cs @@ -60,6 +60,11 @@ namespace NzbDrone.Core.Indexers.Fanzub return new IndexerPageableRequestChain(); } + public IndexerPageableRequestChain GetSearchRequests(AlbumSearchCriteria searchCriteria) + { + throw new System.NotImplementedException(); + } + private IEnumerable GetPagedRequests(string query) { var url = new StringBuilder(); diff --git a/src/NzbDrone.Core/Indexers/HDBits/HDBitsRequestGenerator.cs b/src/NzbDrone.Core/Indexers/HDBits/HDBitsRequestGenerator.cs index dacb87490..d2ab10be3 100644 --- a/src/NzbDrone.Core/Indexers/HDBits/HDBitsRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/HDBits/HDBitsRequestGenerator.cs @@ -43,6 +43,11 @@ namespace NzbDrone.Core.Indexers.HDBits return new IndexerPageableRequestChain(); } + public IndexerPageableRequestChain GetSearchRequests(AlbumSearchCriteria searchCriteria) + { + throw new System.NotImplementedException(); + } + public virtual IndexerPageableRequestChain GetSearchRequests(DailyEpisodeSearchCriteria searchCriteria) { var pageableRequests = new IndexerPageableRequestChain(); diff --git a/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs b/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs index b88158b14..8ac5fac32 100644 --- a/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs +++ b/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs @@ -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 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 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 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 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 Fetch(SpecialEpisodeSearchCriteria searchCriteria) { if (!SupportsSearch) @@ -111,6 +116,18 @@ namespace NzbDrone.Core.Indexers return FetchReleases(generator.GetSearchRequests(searchCriteria)); } + public override IList Fetch(AlbumSearchCriteria searchCriteria) + { + if (!SupportsSearch) + { + return new List(); + } + + var generator = GetRequestGenerator(); + + return FetchReleases(generator.GetSearchRequests(searchCriteria)); + } + protected virtual IList FetchReleases(IndexerPageableRequestChain pageableRequestChain, bool isRecent = false) { var releases = new List(); diff --git a/src/NzbDrone.Core/Indexers/IIndexer.cs b/src/NzbDrone.Core/Indexers/IIndexer.cs index 9f028b569..b716a90f8 100644 --- a/src/NzbDrone.Core/Indexers/IIndexer.cs +++ b/src/NzbDrone.Core/Indexers/IIndexer.cs @@ -17,5 +17,6 @@ namespace NzbDrone.Core.Indexers IList Fetch(DailyEpisodeSearchCriteria searchCriteria); IList Fetch(AnimeEpisodeSearchCriteria searchCriteria); IList Fetch(SpecialEpisodeSearchCriteria searchCriteria); + IList Fetch(AlbumSearchCriteria searchCriteria); } } \ No newline at end of file diff --git a/src/NzbDrone.Core/Indexers/IIndexerRequestGenerator.cs b/src/NzbDrone.Core/Indexers/IIndexerRequestGenerator.cs index 5ad2cc79e..5c660fd60 100644 --- a/src/NzbDrone.Core/Indexers/IIndexerRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/IIndexerRequestGenerator.cs @@ -10,5 +10,6 @@ namespace NzbDrone.Core.Indexers IndexerPageableRequestChain GetSearchRequests(DailyEpisodeSearchCriteria searchCriteria); IndexerPageableRequestChain GetSearchRequests(AnimeEpisodeSearchCriteria searchCriteria); IndexerPageableRequestChain GetSearchRequests(SpecialEpisodeSearchCriteria searchCriteria); + IndexerPageableRequestChain GetSearchRequests(AlbumSearchCriteria searchCriteria); } } \ No newline at end of file diff --git a/src/NzbDrone.Core/Indexers/IPTorrents/IPTorrentsRequestGenerator.cs b/src/NzbDrone.Core/Indexers/IPTorrents/IPTorrentsRequestGenerator.cs index bf4d9e7b8..725796596 100644 --- a/src/NzbDrone.Core/Indexers/IPTorrents/IPTorrentsRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/IPTorrents/IPTorrentsRequestGenerator.cs @@ -42,6 +42,11 @@ namespace NzbDrone.Core.Indexers.IPTorrents return new IndexerPageableRequestChain(); } + public IndexerPageableRequestChain GetSearchRequests(AlbumSearchCriteria searchCriteria) + { + throw new System.NotImplementedException(); + } + private IEnumerable GetRssRequests() { yield return new IndexerRequest(Settings.Url, HttpAccept.Rss); diff --git a/src/NzbDrone.Core/Indexers/IndexerBase.cs b/src/NzbDrone.Core/Indexers/IndexerBase.cs index 4e08e5aad..f6253a26f 100644 --- a/src/NzbDrone.Core/Indexers/IndexerBase.cs +++ b/src/NzbDrone.Core/Indexers/IndexerBase.cs @@ -67,6 +67,7 @@ namespace NzbDrone.Core.Indexers public abstract IList Fetch(DailyEpisodeSearchCriteria searchCriteria); public abstract IList Fetch(AnimeEpisodeSearchCriteria searchCriteria); public abstract IList Fetch(SpecialEpisodeSearchCriteria searchCriteria); + public abstract IList Fetch(AlbumSearchCriteria searchCriteria); protected virtual IList CleanupReleases(IEnumerable releases) { diff --git a/src/NzbDrone.Core/Indexers/Newznab/NewznabRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Newznab/NewznabRequestGenerator.cs index 915603c15..875490211 100644 --- a/src/NzbDrone.Core/Indexers/Newznab/NewznabRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Newznab/NewznabRequestGenerator.cs @@ -180,6 +180,11 @@ namespace NzbDrone.Core.Indexers.Newznab return pageableRequests; } + public IndexerPageableRequestChain GetSearchRequests(AlbumSearchCriteria searchCriteria) + { + throw new System.NotImplementedException(); + } + private void AddTvIdPageableRequests(IndexerPageableRequestChain chain, int maxPages, IEnumerable categories, SearchCriteriaBase searchCriteria, string parameters) { var includeTvdbSearch = SupportsTvdbSearch && searchCriteria.Series.TvdbId > 0; diff --git a/src/NzbDrone.Core/Indexers/Nyaa/NyaaRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Nyaa/NyaaRequestGenerator.cs index b54f4576f..b5a965424 100644 --- a/src/NzbDrone.Core/Indexers/Nyaa/NyaaRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Nyaa/NyaaRequestGenerator.cs @@ -74,6 +74,11 @@ namespace NzbDrone.Core.Indexers.Nyaa return pageableRequests; } + public IndexerPageableRequestChain GetSearchRequests(AlbumSearchCriteria searchCriteria) + { + throw new System.NotImplementedException(); + } + private IEnumerable GetPagedRequests(int maxPages, string term) { var baseUrl = string.Format("{0}/?page=rss{1}", Settings.BaseUrl.TrimEnd('/'), Settings.AdditionalParameters); diff --git a/src/NzbDrone.Core/Indexers/Omgwtfnzbs/OmgwtfnzbsRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Omgwtfnzbs/OmgwtfnzbsRequestGenerator.cs index 17663e8bf..d509f031d 100644 --- a/src/NzbDrone.Core/Indexers/Omgwtfnzbs/OmgwtfnzbsRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Omgwtfnzbs/OmgwtfnzbsRequestGenerator.cs @@ -88,6 +88,11 @@ namespace NzbDrone.Core.Indexers.Omgwtfnzbs return pageableRequests; } + public IndexerPageableRequestChain GetSearchRequests(AlbumSearchCriteria searchCriteria) + { + throw new System.NotImplementedException(); + } + private IEnumerable GetPagedRequests(string query) { var url = new StringBuilder(); diff --git a/src/NzbDrone.Core/Indexers/Rarbg/Rarbg.cs b/src/NzbDrone.Core/Indexers/Rarbg/Rarbg.cs index 049809dce..acf427eee 100644 --- a/src/NzbDrone.Core/Indexers/Rarbg/Rarbg.cs +++ b/src/NzbDrone.Core/Indexers/Rarbg/Rarbg.cs @@ -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) diff --git a/src/NzbDrone.Core/Indexers/Rarbg/RarbgRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Rarbg/RarbgRequestGenerator.cs index a416d789f..8bfaf9a2d 100644 --- a/src/NzbDrone.Core/Indexers/Rarbg/RarbgRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Rarbg/RarbgRequestGenerator.cs @@ -72,6 +72,15 @@ namespace NzbDrone.Core.Indexers.Rarbg return pageableRequests; } + public IndexerPageableRequestChain GetSearchRequests(AlbumSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests("search", null, "{0}", searchCriteria.Album.Title)); + + return pageableRequests; + } + private IEnumerable GetPagedRequests(string mode, int? tvdbId, string query, params object[] args) { var requestBuilder = new HttpRequestBuilder(Settings.BaseUrl) diff --git a/src/NzbDrone.Core/Indexers/RssIndexerRequestGenerator.cs b/src/NzbDrone.Core/Indexers/RssIndexerRequestGenerator.cs index 2ae5d4ed4..d14e1fb39 100644 --- a/src/NzbDrone.Core/Indexers/RssIndexerRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/RssIndexerRequestGenerator.cs @@ -46,5 +46,10 @@ namespace NzbDrone.Core.Indexers { return new IndexerPageableRequestChain(); } + + public IndexerPageableRequestChain GetSearchRequests(AlbumSearchCriteria searchCriteria) + { + throw new System.NotImplementedException(); + } } } diff --git a/src/NzbDrone.Core/Indexers/TorrentRss/TorrentRssIndexerRequestGenerator.cs b/src/NzbDrone.Core/Indexers/TorrentRss/TorrentRssIndexerRequestGenerator.cs index a0bf58cbc..62f165d91 100644 --- a/src/NzbDrone.Core/Indexers/TorrentRss/TorrentRssIndexerRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/TorrentRss/TorrentRssIndexerRequestGenerator.cs @@ -43,6 +43,11 @@ namespace NzbDrone.Core.Indexers.TorrentRss return new IndexerPageableRequestChain(); } + public IndexerPageableRequestChain GetSearchRequests(AlbumSearchCriteria searchCriteria) + { + throw new System.NotImplementedException(); + } + private IEnumerable GetRssRequests(string searchParameters) { var request = new IndexerRequest(Settings.BaseUrl.Trim().TrimEnd('/'), HttpAccept.Rss); diff --git a/src/NzbDrone.Core/Indexers/Torrentleech/TorrentleechRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Torrentleech/TorrentleechRequestGenerator.cs index ebfa73788..9d1d98ed4 100644 --- a/src/NzbDrone.Core/Indexers/Torrentleech/TorrentleechRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Torrentleech/TorrentleechRequestGenerator.cs @@ -42,6 +42,11 @@ namespace NzbDrone.Core.Indexers.Torrentleech return new IndexerPageableRequestChain(); } + public IndexerPageableRequestChain GetSearchRequests(AlbumSearchCriteria searchCriteria) + { + throw new System.NotImplementedException(); + } + private IEnumerable GetRssRequests(string searchParameters) { yield return new IndexerRequest(string.Format("{0}/{1}{2}", Settings.BaseUrl.Trim().TrimEnd('/'), Settings.ApiKey, searchParameters), HttpAccept.Rss); diff --git a/src/NzbDrone.Core/NzbDrone.Core.csproj b/src/NzbDrone.Core/NzbDrone.Core.csproj index a57e58607..98826ba87 100644 --- a/src/NzbDrone.Core/NzbDrone.Core.csproj +++ b/src/NzbDrone.Core/NzbDrone.Core.csproj @@ -605,6 +605,9 @@ + + +