Rewrote the RequestGenerator to support paging and other refactorings.

pull/6/head
Taloth Saldono 9 years ago
parent 58b01b91d5
commit fc75783fbe

@ -1,14 +1,14 @@
using Moq;
using System;
using System.Linq;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Common.Http;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Indexers.TitansOfTv;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common;
using System;
using System.Linq;
using FluentAssertions;
using NzbDrone.Core.Indexers.TitansOfTv;
namespace NzbDrone.Core.Test.IndexerTests.TitansOfTvTests
{
@ -21,12 +21,12 @@ namespace NzbDrone.Core.Test.IndexerTests.TitansOfTvTests
Subject.Definition = new IndexerDefinition
{
Name = "TitansOfTV",
Settings = new TitansOfTvSettings { ApiKey = "abc", BaseUrl = "https://titansof.tv/api/torrents" }
Settings = new TitansOfTvSettings { ApiKey = "abc", BaseUrl = "https://titansof.tv/api" }
};
}
[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");
@ -59,7 +59,8 @@ namespace NzbDrone.Core.Test.IndexerTests.TitansOfTvTests
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]

@ -8,38 +8,30 @@ namespace NzbDrone.Core.Indexers.TitansOfTv
{
public class TitansOfTv : HttpIndexerBase<TitansOfTvSettings>
{
public TitansOfTv(IHttpClient httpClient, IConfigService configService, IParsingService parsingService, Logger logger)
: base(httpClient, configService, parsingService, logger)
public TitansOfTv(IHttpClient httpClient, IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger)
: base(httpClient, indexerStatusService, configService, parsingService, logger)
{
}
public override string Name
{
get
{
return "Titans of TV";
}
get { return "Titans of TV"; }
}
public override DownloadProtocol Protocol
{
get
{
return DownloadProtocol.Torrent;
}
}
public override DownloadProtocol Protocol { get { return DownloadProtocol.Torrent; } }
public override bool SupportsRss { get { return true; } }
public override bool SupportsSearch { get { return true; } }
public override int PageSize { get { return 100; } }
public override IIndexerRequestGenerator GetRequestGenerator()
{
return new TitansOfTvRequestGenerator() { Settings = Settings };
return new TitansOfTvRequestGenerator() { Settings = Settings, PageSize = PageSize };
}
public override IParseIndexerResponse GetParser()
{
return new TitansOfTvParser();
}
public override Boolean SupportsSearch { get { return true; } }
}
}

@ -3,16 +3,26 @@ using System.Collections.Generic;
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 series_id { get; set; }
public string episode_id { get; set; }
public string season_id { get; set; }
public string seeders { get; set; }
public string leechers { get; set; }
public string size { get; set; }
public string snatched { get; set; }
public int? seeders { get; set; }
public int? leechers { get; set; }
public long size { get; set; }
public int? snatched { get; set; }
public int user_id { get; set; }
public string anonymous { get; set; }
public string container { get; set; }
@ -29,17 +39,10 @@ namespace NzbDrone.Core.Indexers.TitansOfTv
public string episode { get; set; }
public string series { get; set; }
public string network { get; set; }
public string mediainfo { get; set; }
public string download { get; set; }
public string additional { get; set; }
public string episodeUrl { 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; }
public string commentUrl { get; set; }
}
}

@ -1,8 +1,8 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Net;
using System.Text.RegularExpressions;
using Newtonsoft.Json;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Parser.Model;
@ -33,20 +33,24 @@ namespace NzbDrone.Core.Indexers.TitansOfTv
}
var content = indexerResponse.HttpResponse.Content;
var parsed = JsonConvert.DeserializeObject<ApiResult>(content);
var parsed = Json.Deserialize<TitansOfTvApiResult>(content);
var protocol = indexerResponse.HttpRequest.Url.Scheme + ":";
foreach (var parsedItem in parsed.results)
{
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.InfoUrl = RegexProtocol.Replace(parsedItem.episodeUrl, protocol);
if (parsedItem.commentUrl.IsNotNullOrWhiteSpace())
{
release.CommentUrl = RegexProtocol.Replace(parsedItem.commentUrl, protocol);
}
release.DownloadProtocol = DownloadProtocol.Torrent;
release.Title = parsedItem.release_name;
release.Size = Convert.ToInt64(parsedItem.size);
release.Seeders = Convert.ToInt32(parsedItem.seeders);
release.Peers = Convert.ToInt32(parsedItem.leechers) + release.Seeders;
release.Size = parsedItem.size;
release.Seeders = parsedItem.seeders;
release.Peers = parsedItem.leechers + release.Seeders;
release.PublishDate = parsedItem.created_at;
results.Add(release);
}

@ -1,111 +1,119 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Core.IndexerSearch.Definitions;
namespace NzbDrone.Core.Indexers.TitansOfTv
{
public class TitansOfTvRequestGenerator : IIndexerRequestGenerator
{
public int MaxPages { get; set; }
public int PageSize { get; set; }
public TitansOfTvSettings Settings { get; set; }
public TitansOfTvRequestGenerator()
{
MaxPages = 30;
PageSize = 100;
}
public IList<IEnumerable<IndexerRequest>> GetRecentRequests()
{
var pageableRequests = new List<IEnumerable<IndexerRequest>>();
var innerList = new List<IndexerRequest>();
var httpRequest = BuildHttpRequest(GetBaseUrl());
innerList.Add(new IndexerRequest(httpRequest));
pageableRequests.Add(innerList);
pageableRequests.AddIfNotNull(GetPagedRequests(MaxPages));
return pageableRequests;
}
private HttpRequest BuildHttpRequest(string url)
public IList<IEnumerable<IndexerRequest>> GetSearchRequests(SingleEpisodeSearchCriteria searchCriteria)
{
var httpRequest = new HttpRequest(url, HttpAccept.Json);
httpRequest.Headers["X-Authorization"] = Settings.ApiKey;
return httpRequest;
}
public IList<IEnumerable<IndexerRequest>> GetSearchRequests(IndexerSearch.Definitions.SingleEpisodeSearchCriteria searchCriteria)
{
var url = GetBaseUrl() + "&series_id={series}&episode={episode}";
var requests = new List<IEnumerable<IndexerRequest>>();
var innerList = new List<IndexerRequest>();
requests.Add(innerList);
var pageableRequests = new List<IEnumerable<IndexerRequest>>();
var httpRequest = BuildHttpRequest(url);
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);
pageableRequests.AddIfNotNull(GetPagedRequests(MaxPages,
series_id: searchCriteria.Series.TvdbId,
episode: string.Format("S{0:00}E{1:00}", searchCriteria.SeasonNumber, searchCriteria.EpisodeNumber)));
var request = new IndexerRequest(httpRequest);
innerList.Add(request);
pageableRequests.AddIfNotNull(GetPagedRequests(MaxPages,
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(SeasonSearchCriteria searchCriteria)
{
var url = GetBaseUrl() + "&series_id={series}&season={season}";
var requests = new List<IEnumerable<IndexerRequest>>();
var innerList = new List<IndexerRequest>();
requests.Add(innerList);
var httpRequest = BuildHttpRequest(url);
var seasonString = String.Format("Season {0:00}", searchCriteria.SeasonNumber);
httpRequest.AddSegment("series", searchCriteria.Series.TvdbId.ToString(CultureInfo.InvariantCulture));
httpRequest.AddSegment("season", seasonString);
var request = new IndexerRequest(httpRequest);
innerList.Add(request);
var pageableRequests = new List<IEnumerable<IndexerRequest>>();
httpRequest = BuildHttpRequest(url);
seasonString = String.Format("Season {0}", searchCriteria.SeasonNumber);
httpRequest.AddSegment("series", searchCriteria.Series.TvdbId.ToString(CultureInfo.InvariantCulture));
httpRequest.AddSegment("season", seasonString);
// TODO: Search for all episodes?!?
request = new IndexerRequest(httpRequest);
innerList.Add(request);
pageableRequests.AddIfNotNull(GetPagedRequests(MaxPages,
series_id: searchCriteria.Series.TvdbId,
season: string.Format("Season {0:00}", searchCriteria.SeasonNumber)));
return requests;
return pageableRequests;
}
public IList<IEnumerable<IndexerRequest>> GetSearchRequests(IndexerSearch.Definitions.DailyEpisodeSearchCriteria searchCriteria)
public IList<IEnumerable<IndexerRequest>> GetSearchRequests(DailyEpisodeSearchCriteria 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 pageableRequests = new List<IEnumerable<IndexerRequest>>();
var request = new IndexerRequest(httpRequest);
innerList.Add(request);
pageableRequests.AddIfNotNull(GetPagedRequests(MaxPages,
series_id: searchCriteria.Series.TvdbId,
air_date: searchCriteria.AirDate));
return requests;
return pageableRequests;
}
public IList<IEnumerable<IndexerRequest>> GetSearchRequests(IndexerSearch.Definitions.AnimeEpisodeSearchCriteria searchCriteria)
public IList<IEnumerable<IndexerRequest>> GetSearchRequests(AnimeEpisodeSearchCriteria searchCriteria)
{
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>>();
}
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 @@ using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Indexers.TitansOfTv
{
public class TitansOfTvSettingsValidator : AbstractValidator<TitansOfTvSettings>
public class TitansOfTvSettingsValidator : AbstractValidator<TitansOfTvSettings>
{
public TitansOfTvSettingsValidator()
{
@ -20,7 +19,7 @@ namespace NzbDrone.Core.Indexers.TitansOfTv
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.")]

Loading…
Cancel
Save