mirror of
https://github.com/Radarr/Radarr.git
synced 2024-11-09 04:22:30 +01:00
Rewrote the RequestGenerator to support paging and other refactorings.
This commit is contained in:
parent
58b01b91d5
commit
fc75783fbe
@ -1,14 +1,14 @@
|
|||||||
using Moq;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using FluentAssertions;
|
||||||
|
using Moq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using NzbDrone.Common.Http;
|
using NzbDrone.Common.Http;
|
||||||
using NzbDrone.Core.Indexers;
|
using NzbDrone.Core.Indexers;
|
||||||
|
using NzbDrone.Core.Indexers.TitansOfTv;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
using NzbDrone.Core.Test.Framework;
|
using NzbDrone.Core.Test.Framework;
|
||||||
using NzbDrone.Test.Common;
|
using NzbDrone.Test.Common;
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using FluentAssertions;
|
|
||||||
using NzbDrone.Core.Indexers.TitansOfTv;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Test.IndexerTests.TitansOfTvTests
|
namespace NzbDrone.Core.Test.IndexerTests.TitansOfTvTests
|
||||||
{
|
{
|
||||||
@ -21,12 +21,12 @@ public void Setup()
|
|||||||
Subject.Definition = new IndexerDefinition
|
Subject.Definition = new IndexerDefinition
|
||||||
{
|
{
|
||||||
Name = "TitansOfTV",
|
Name = "TitansOfTV",
|
||||||
Settings = new TitansOfTvSettings { ApiKey = "abc", BaseUrl = "https://titansof.tv/api/torrents" }
|
Settings = new TitansOfTvSettings { ApiKey = "abc", BaseUrl = "https://titansof.tv/api" }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void should_parse_recent_feed_from_BroadcastheNet()
|
public void should_parse_recent_feed_from_TitansOfTv()
|
||||||
{
|
{
|
||||||
var recentFeed = ReadAllText(@"Files/Indexers/TitansOfTv/RecentFeed.json");
|
var recentFeed = ReadAllText(@"Files/Indexers/TitansOfTv/RecentFeed.json");
|
||||||
|
|
||||||
@ -59,7 +59,8 @@ public void should_parse_recent_feed_from_BroadcastheNet()
|
|||||||
|
|
||||||
private void VerifyBackOff()
|
private void VerifyBackOff()
|
||||||
{
|
{
|
||||||
// TODO How to detect (and implement) back-off logic.
|
Mocker.GetMock<IIndexerStatusService>()
|
||||||
|
.Verify(v => v.RecordFailure(It.IsAny<int>(), It.IsAny<TimeSpan>()), Times.Once());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -8,38 +8,30 @@ namespace NzbDrone.Core.Indexers.TitansOfTv
|
|||||||
{
|
{
|
||||||
public class TitansOfTv : HttpIndexerBase<TitansOfTvSettings>
|
public class TitansOfTv : HttpIndexerBase<TitansOfTvSettings>
|
||||||
{
|
{
|
||||||
public TitansOfTv(IHttpClient httpClient, IConfigService configService, IParsingService parsingService, Logger logger)
|
public TitansOfTv(IHttpClient httpClient, IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger)
|
||||||
: base(httpClient, configService, parsingService, logger)
|
: base(httpClient, indexerStatusService, configService, parsingService, logger)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string Name
|
public override string Name
|
||||||
{
|
{
|
||||||
get
|
get { return "Titans of TV"; }
|
||||||
{
|
|
||||||
return "Titans of TV";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override DownloadProtocol Protocol
|
public override DownloadProtocol Protocol { get { return DownloadProtocol.Torrent; } }
|
||||||
{
|
public override bool SupportsRss { get { return true; } }
|
||||||
get
|
public override bool SupportsSearch { get { return true; } }
|
||||||
{
|
public override int PageSize { get { return 100; } }
|
||||||
return DownloadProtocol.Torrent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override IIndexerRequestGenerator GetRequestGenerator()
|
public override IIndexerRequestGenerator GetRequestGenerator()
|
||||||
{
|
{
|
||||||
return new TitansOfTvRequestGenerator() { Settings = Settings };
|
return new TitansOfTvRequestGenerator() { Settings = Settings, PageSize = PageSize };
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IParseIndexerResponse GetParser()
|
public override IParseIndexerResponse GetParser()
|
||||||
{
|
{
|
||||||
return new TitansOfTvParser();
|
return new TitansOfTvParser();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Boolean SupportsSearch { get { return true; } }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,16 +3,26 @@
|
|||||||
|
|
||||||
namespace NzbDrone.Core.Indexers.TitansOfTv
|
namespace NzbDrone.Core.Indexers.TitansOfTv
|
||||||
{
|
{
|
||||||
public class Result
|
public class TitansOfTvApiResult
|
||||||
|
{
|
||||||
|
public string code { get; set; }
|
||||||
|
public int http_code { get; set; }
|
||||||
|
public int total { get; set; }
|
||||||
|
public int offset { get; set; }
|
||||||
|
public int limit { get; set; }
|
||||||
|
public List<TitansOfTvTorrent> results { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TitansOfTvTorrent
|
||||||
{
|
{
|
||||||
public string id { get; set; }
|
public string id { get; set; }
|
||||||
public string series_id { get; set; }
|
public string series_id { get; set; }
|
||||||
public string episode_id { get; set; }
|
public string episode_id { get; set; }
|
||||||
public string season_id { get; set; }
|
public string season_id { get; set; }
|
||||||
public string seeders { get; set; }
|
public int? seeders { get; set; }
|
||||||
public string leechers { get; set; }
|
public int? leechers { get; set; }
|
||||||
public string size { get; set; }
|
public long size { get; set; }
|
||||||
public string snatched { get; set; }
|
public int? snatched { get; set; }
|
||||||
public int user_id { get; set; }
|
public int user_id { get; set; }
|
||||||
public string anonymous { get; set; }
|
public string anonymous { get; set; }
|
||||||
public string container { get; set; }
|
public string container { get; set; }
|
||||||
@ -29,17 +39,10 @@ public class Result
|
|||||||
public string episode { get; set; }
|
public string episode { get; set; }
|
||||||
public string series { get; set; }
|
public string series { get; set; }
|
||||||
public string network { get; set; }
|
public string network { get; set; }
|
||||||
|
public string mediainfo { get; set; }
|
||||||
public string download { get; set; }
|
public string download { get; set; }
|
||||||
|
public string additional { get; set; }
|
||||||
public string episodeUrl { get; set; }
|
public string episodeUrl { get; set; }
|
||||||
}
|
public string commentUrl { get; set; }
|
||||||
|
|
||||||
public class ApiResult
|
|
||||||
{
|
|
||||||
public string code { get; set; }
|
|
||||||
public int http_code { get; set; }
|
|
||||||
public int total { get; set; }
|
|
||||||
public int offset { get; set; }
|
|
||||||
public int limit { get; set; }
|
|
||||||
public List<Result> results { get; set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using Newtonsoft.Json;
|
using NzbDrone.Common.Extensions;
|
||||||
|
using NzbDrone.Common.Serializer;
|
||||||
using NzbDrone.Core.Indexers.Exceptions;
|
using NzbDrone.Core.Indexers.Exceptions;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
|
||||||
@ -33,20 +33,24 @@ public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
|
|||||||
}
|
}
|
||||||
|
|
||||||
var content = indexerResponse.HttpResponse.Content;
|
var content = indexerResponse.HttpResponse.Content;
|
||||||
var parsed = JsonConvert.DeserializeObject<ApiResult>(content);
|
var parsed = Json.Deserialize<TitansOfTvApiResult>(content);
|
||||||
var protocol = indexerResponse.HttpRequest.Url.Scheme + ":";
|
var protocol = indexerResponse.HttpRequest.Url.Scheme + ":";
|
||||||
|
|
||||||
foreach (var parsedItem in parsed.results)
|
foreach (var parsedItem in parsed.results)
|
||||||
{
|
{
|
||||||
var release = new TorrentInfo();
|
var release = new TorrentInfo();
|
||||||
release.Guid = String.Format("ToTV-{0}", parsedItem.id);
|
release.Guid = string.Format("ToTV-{0}", parsedItem.id);
|
||||||
release.DownloadUrl = RegexProtocol.Replace(parsedItem.download, protocol);
|
release.DownloadUrl = RegexProtocol.Replace(parsedItem.download, protocol);
|
||||||
release.InfoUrl = RegexProtocol.Replace(parsedItem.episodeUrl, protocol);
|
release.InfoUrl = RegexProtocol.Replace(parsedItem.episodeUrl, protocol);
|
||||||
|
if (parsedItem.commentUrl.IsNotNullOrWhiteSpace())
|
||||||
|
{
|
||||||
|
release.CommentUrl = RegexProtocol.Replace(parsedItem.commentUrl, protocol);
|
||||||
|
}
|
||||||
release.DownloadProtocol = DownloadProtocol.Torrent;
|
release.DownloadProtocol = DownloadProtocol.Torrent;
|
||||||
release.Title = parsedItem.release_name;
|
release.Title = parsedItem.release_name;
|
||||||
release.Size = Convert.ToInt64(parsedItem.size);
|
release.Size = parsedItem.size;
|
||||||
release.Seeders = Convert.ToInt32(parsedItem.seeders);
|
release.Seeders = parsedItem.seeders;
|
||||||
release.Peers = Convert.ToInt32(parsedItem.leechers) + release.Seeders;
|
release.Peers = parsedItem.leechers + release.Seeders;
|
||||||
release.PublishDate = parsedItem.created_at;
|
release.PublishDate = parsedItem.created_at;
|
||||||
results.Add(release);
|
results.Add(release);
|
||||||
}
|
}
|
||||||
|
@ -1,111 +1,119 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Common.Http;
|
using NzbDrone.Common.Http;
|
||||||
|
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Indexers.TitansOfTv
|
namespace NzbDrone.Core.Indexers.TitansOfTv
|
||||||
{
|
{
|
||||||
public class TitansOfTvRequestGenerator : IIndexerRequestGenerator
|
public class TitansOfTvRequestGenerator : IIndexerRequestGenerator
|
||||||
{
|
{
|
||||||
|
public int MaxPages { get; set; }
|
||||||
|
public int PageSize { get; set; }
|
||||||
public TitansOfTvSettings Settings { get; set; }
|
public TitansOfTvSettings Settings { get; set; }
|
||||||
|
|
||||||
|
public TitansOfTvRequestGenerator()
|
||||||
|
{
|
||||||
|
MaxPages = 30;
|
||||||
|
PageSize = 100;
|
||||||
|
}
|
||||||
|
|
||||||
public IList<IEnumerable<IndexerRequest>> GetRecentRequests()
|
public IList<IEnumerable<IndexerRequest>> GetRecentRequests()
|
||||||
{
|
{
|
||||||
var pageableRequests = new List<IEnumerable<IndexerRequest>>();
|
var pageableRequests = new List<IEnumerable<IndexerRequest>>();
|
||||||
var innerList = new List<IndexerRequest>();
|
|
||||||
var httpRequest = BuildHttpRequest(GetBaseUrl());
|
|
||||||
|
|
||||||
innerList.Add(new IndexerRequest(httpRequest));
|
pageableRequests.AddIfNotNull(GetPagedRequests(MaxPages));
|
||||||
pageableRequests.Add(innerList);
|
|
||||||
|
|
||||||
return pageableRequests;
|
return pageableRequests;
|
||||||
}
|
}
|
||||||
|
|
||||||
private HttpRequest BuildHttpRequest(string url)
|
public IList<IEnumerable<IndexerRequest>> GetSearchRequests(SingleEpisodeSearchCriteria searchCriteria)
|
||||||
{
|
{
|
||||||
var httpRequest = new HttpRequest(url, HttpAccept.Json);
|
var pageableRequests = new List<IEnumerable<IndexerRequest>>();
|
||||||
httpRequest.Headers["X-Authorization"] = Settings.ApiKey;
|
|
||||||
|
|
||||||
return httpRequest;
|
pageableRequests.AddIfNotNull(GetPagedRequests(MaxPages,
|
||||||
|
series_id: searchCriteria.Series.TvdbId,
|
||||||
|
episode: string.Format("S{0:00}E{1:00}", searchCriteria.SeasonNumber, searchCriteria.EpisodeNumber)));
|
||||||
|
|
||||||
|
pageableRequests.AddIfNotNull(GetPagedRequests(MaxPages,
|
||||||
|
series_id: searchCriteria.Series.TvdbId,
|
||||||
|
season: string.Format("Season {0:00}", searchCriteria.SeasonNumber)));
|
||||||
|
|
||||||
|
return pageableRequests;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IList<IEnumerable<IndexerRequest>> GetSearchRequests(IndexerSearch.Definitions.SingleEpisodeSearchCriteria searchCriteria)
|
public IList<IEnumerable<IndexerRequest>> GetSearchRequests(SeasonSearchCriteria searchCriteria)
|
||||||
{
|
{
|
||||||
var url = GetBaseUrl() + "&series_id={series}&episode={episode}";
|
var pageableRequests = new List<IEnumerable<IndexerRequest>>();
|
||||||
var requests = new List<IEnumerable<IndexerRequest>>();
|
|
||||||
var innerList = new List<IndexerRequest>();
|
|
||||||
requests.Add(innerList);
|
|
||||||
|
|
||||||
var httpRequest = BuildHttpRequest(url);
|
// TODO: Search for all episodes?!?
|
||||||
var episodeString = String.Format("S{0:00}E{1:00}", searchCriteria.SeasonNumber, searchCriteria.EpisodeNumber);
|
|
||||||
httpRequest.AddSegment("series", searchCriteria.Series.TvdbId.ToString(CultureInfo.InvariantCulture));
|
|
||||||
httpRequest.AddSegment("episode", episodeString);
|
|
||||||
|
|
||||||
var request = new IndexerRequest(httpRequest);
|
pageableRequests.AddIfNotNull(GetPagedRequests(MaxPages,
|
||||||
innerList.Add(request);
|
series_id: searchCriteria.Series.TvdbId,
|
||||||
|
season: string.Format("Season {0:00}", searchCriteria.SeasonNumber)));
|
||||||
|
|
||||||
return requests;
|
return pageableRequests;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IList<IEnumerable<IndexerRequest>> GetSearchRequests(IndexerSearch.Definitions.SeasonSearchCriteria searchCriteria)
|
public IList<IEnumerable<IndexerRequest>> GetSearchRequests(DailyEpisodeSearchCriteria searchCriteria)
|
||||||
{
|
{
|
||||||
var url = GetBaseUrl() + "&series_id={series}&season={season}";
|
var pageableRequests = new List<IEnumerable<IndexerRequest>>();
|
||||||
var requests = new List<IEnumerable<IndexerRequest>>();
|
|
||||||
var innerList = new List<IndexerRequest>();
|
|
||||||
requests.Add(innerList);
|
|
||||||
|
|
||||||
var httpRequest = BuildHttpRequest(url);
|
pageableRequests.AddIfNotNull(GetPagedRequests(MaxPages,
|
||||||
var seasonString = String.Format("Season {0:00}", searchCriteria.SeasonNumber);
|
series_id: searchCriteria.Series.TvdbId,
|
||||||
httpRequest.AddSegment("series", searchCriteria.Series.TvdbId.ToString(CultureInfo.InvariantCulture));
|
air_date: searchCriteria.AirDate));
|
||||||
httpRequest.AddSegment("season", seasonString);
|
|
||||||
|
|
||||||
var request = new IndexerRequest(httpRequest);
|
return pageableRequests;
|
||||||
innerList.Add(request);
|
|
||||||
|
|
||||||
httpRequest = BuildHttpRequest(url);
|
|
||||||
seasonString = String.Format("Season {0}", searchCriteria.SeasonNumber);
|
|
||||||
httpRequest.AddSegment("series", searchCriteria.Series.TvdbId.ToString(CultureInfo.InvariantCulture));
|
|
||||||
httpRequest.AddSegment("season", seasonString);
|
|
||||||
|
|
||||||
request = new IndexerRequest(httpRequest);
|
|
||||||
innerList.Add(request);
|
|
||||||
|
|
||||||
return requests;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IList<IEnumerable<IndexerRequest>> GetSearchRequests(IndexerSearch.Definitions.DailyEpisodeSearchCriteria searchCriteria)
|
public IList<IEnumerable<IndexerRequest>> GetSearchRequests(AnimeEpisodeSearchCriteria searchCriteria)
|
||||||
{
|
|
||||||
var url = GetBaseUrl() + "&series_id={series}&air_date={air_date}";
|
|
||||||
var requests = new List<IEnumerable<IndexerRequest>>();
|
|
||||||
var innerList = new List<IndexerRequest>();
|
|
||||||
|
|
||||||
requests.Add(innerList);
|
|
||||||
|
|
||||||
var httpRequest = BuildHttpRequest(url);
|
|
||||||
var airDate = searchCriteria.AirDate.ToString("yyyy-MM-dd");
|
|
||||||
|
|
||||||
httpRequest.AddSegment("series", searchCriteria.Series.TvdbId.ToString(CultureInfo.InvariantCulture));
|
|
||||||
httpRequest.AddSegment("air_date", airDate);
|
|
||||||
|
|
||||||
var request = new IndexerRequest(httpRequest);
|
|
||||||
innerList.Add(request);
|
|
||||||
|
|
||||||
return requests;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IList<IEnumerable<IndexerRequest>> GetSearchRequests(IndexerSearch.Definitions.AnimeEpisodeSearchCriteria searchCriteria)
|
|
||||||
{
|
{
|
||||||
return new List<IEnumerable<IndexerRequest>>();
|
return new List<IEnumerable<IndexerRequest>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IList<IEnumerable<IndexerRequest>> GetSearchRequests(IndexerSearch.Definitions.SpecialEpisodeSearchCriteria searchCriteria)
|
public IList<IEnumerable<IndexerRequest>> GetSearchRequests(SpecialEpisodeSearchCriteria searchCriteria)
|
||||||
{
|
{
|
||||||
return new List<IEnumerable<IndexerRequest>>();
|
return new List<IEnumerable<IndexerRequest>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetBaseUrl()
|
private IEnumerable<IndexerRequest> GetPagedRequests(int maxPages, int? series_id = null, string episode = null, string season = null, DateTime? air_date = null)
|
||||||
{
|
{
|
||||||
return Settings.BaseUrl + "?limit=100";
|
var pageSize = PageSize;
|
||||||
|
|
||||||
|
if (pageSize == 0)
|
||||||
|
{
|
||||||
|
maxPages = 1;
|
||||||
|
pageSize = 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var page = 0; page < maxPages; page++)
|
||||||
|
{
|
||||||
|
var request = new IndexerRequest(string.Format("{0}/torrents?offset={1}&limit={2}", Settings.BaseUrl.TrimEnd('/'), page * pageSize, pageSize), HttpAccept.Json);
|
||||||
|
request.HttpRequest.Headers.Add("X-Authorization", Settings.ApiKey);
|
||||||
|
|
||||||
|
if (series_id.HasValue)
|
||||||
|
{
|
||||||
|
request.HttpRequest.AddQueryParam("series_id", series_id.Value.ToString(CultureInfo.InvariantCulture));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (season != null)
|
||||||
|
{
|
||||||
|
request.HttpRequest.AddQueryParam("season", season);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (episode != null)
|
||||||
|
{
|
||||||
|
request.HttpRequest.AddQueryParam("episode", episode);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (air_date.HasValue)
|
||||||
|
{
|
||||||
|
request.HttpRequest.AddQueryParam("air_date", air_date.Value.ToString("yyyy-MM-dd"));
|
||||||
|
}
|
||||||
|
|
||||||
|
yield return request;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,7 @@
|
|||||||
|
|
||||||
namespace NzbDrone.Core.Indexers.TitansOfTv
|
namespace NzbDrone.Core.Indexers.TitansOfTv
|
||||||
{
|
{
|
||||||
|
public class TitansOfTvSettingsValidator : AbstractValidator<TitansOfTvSettings>
|
||||||
public class TitansOfTvSettingsValidator : AbstractValidator<TitansOfTvSettings>
|
|
||||||
{
|
{
|
||||||
public TitansOfTvSettingsValidator()
|
public TitansOfTvSettingsValidator()
|
||||||
{
|
{
|
||||||
@ -20,7 +19,7 @@ public class TitansOfTvSettings : IProviderConfig
|
|||||||
|
|
||||||
public TitansOfTvSettings()
|
public TitansOfTvSettings()
|
||||||
{
|
{
|
||||||
BaseUrl = "http://titansof.tv/api/torrents";
|
BaseUrl = "http://titansof.tv/api";
|
||||||
}
|
}
|
||||||
|
|
||||||
[FieldDefinition(0, Label = "API URL", Advanced = true, HelpText = "Do not change this unless you know what you're doing. Since your API key will be sent to that host.")]
|
[FieldDefinition(0, Label = "API URL", Advanced = true, HelpText = "Do not change this unless you know what you're doing. Since your API key will be sent to that host.")]
|
||||||
|
Loading…
Reference in New Issue
Block a user