Fixed: (TorrentPotato) Allow use of custom APIs

pull/1759/head
Bogdan 1 year ago
parent 90e92c0b66
commit 6769055b6b

@ -1,32 +1,51 @@
using System; using System.Collections.Generic;
using NLog; using NLog;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.ThingiProvider;
namespace NzbDrone.Core.Indexers.Definitions.TorrentPotato namespace NzbDrone.Core.Indexers.Definitions.TorrentPotato
{ {
public class TorrentPotato : TorrentIndexerBase<TorrentPotatoSettings> public class TorrentPotato : TorrentIndexerBase<TorrentPotatoSettings>
{ {
public override string Name => "TorrentPotato"; public override string Name => "TorrentPotato";
public override string[] IndexerUrls => new[] { "http://127.0.0.1" }; public override string[] IndexerUrls => new[] { "" };
public override string Description => "A JSON based torrent provider previously developed for CouchPotato"; public override string Description => "A JSON based torrent provider previously developed for CouchPotato";
public override IndexerPrivacy Privacy => IndexerPrivacy.Private; public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override TimeSpan RateLimit => TimeSpan.FromSeconds(2); public override IndexerCapabilities Capabilities => SetCapabilities();
public TorrentPotato(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) public TorrentPotato(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, configService, logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{ {
} }
private IndexerDefinition GetDefinition(string name, TorrentPotatoSettings settings) public override IIndexerRequestGenerator GetRequestGenerator()
{
return new TorrentPotatoRequestGenerator(Settings);
}
public override IParseIndexerResponse GetParser()
{
return new TorrentPotatoParser();
}
public override IEnumerable<ProviderDefinition> DefaultDefinitions
{
get
{
yield return GetDefinition("TorrentPotato", "A JSON based torrent provider previously developed for CouchPotato", "http://127.0.0.1");
}
}
private IndexerDefinition GetDefinition(string name, string description, string baseUrl)
{ {
return new IndexerDefinition return new IndexerDefinition
{ {
Enable = true, Enable = true,
Name = name, Name = name,
Description = description,
Implementation = GetType().Name, Implementation = GetType().Name,
Settings = settings, Settings = new TorrentPotatoSettings { BaseUrl = baseUrl },
Protocol = DownloadProtocol.Torrent, Protocol = DownloadProtocol.Torrent,
SupportsRss = SupportsRss, SupportsRss = SupportsRss,
SupportsSearch = SupportsSearch, SupportsSearch = SupportsSearch,
@ -35,14 +54,19 @@ namespace NzbDrone.Core.Indexers.Definitions.TorrentPotato
}; };
} }
public override IIndexerRequestGenerator GetRequestGenerator() private IndexerCapabilities SetCapabilities()
{ {
return new TorrentPotatoRequestGenerator() { Settings = Settings }; var caps = new IndexerCapabilities
} {
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q, MovieSearchParam.ImdbId
}
};
public override IParseIndexerResponse GetParser() caps.Categories.AddCategoryMapping("1", NewznabStandardCategory.Movies);
{
return new TorrentPotatoParser(); return caps;
} }
} }
} }

@ -1,52 +1,62 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Net; using System.Net;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.Indexers.Exceptions; using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Indexers.Definitions.TorrentPotato namespace NzbDrone.Core.Indexers.Definitions.TorrentPotato
{ {
public class TorrentPotatoParser : IParseIndexerResponse public class TorrentPotatoParser : IParseIndexerResponse
{ {
private static readonly Regex RegexGuid = new Regex(@"^magnet:\?xt=urn:btih:([a-f0-9]+)", RegexOptions.Compiled); private static readonly Regex RegexGuid = new (@"^magnet:\?xt=urn:btih:([a-f0-9]+)", RegexOptions.Compiled);
public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
{ {
var results = new List<ReleaseInfo>(); var releaseInfos = new List<ReleaseInfo>();
switch (indexerResponse.HttpResponse.StatusCode) if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK)
{ {
default: throw new IndexerException(indexerResponse, "Indexer API call returned an unexpected StatusCode [{0}]", indexerResponse.HttpResponse.StatusCode);
if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK)
{
throw new IndexerException(indexerResponse, "Indexer API call returned an unexpected StatusCode [{0}]", indexerResponse.HttpResponse.StatusCode);
}
break;
} }
var jsonResponse = new HttpResponse<TorrentPotatoResponse>(indexerResponse.HttpResponse); var jsonResponse = new HttpResponse<TorrentPotatoResponse>(indexerResponse.HttpResponse);
if (jsonResponse.Resource?.error != null)
{
throw new IndexerException(indexerResponse, "Indexer API call returned an error [{0}]", jsonResponse.Resource.error);
}
if (jsonResponse.Resource?.results == null)
{
return releaseInfos;
}
foreach (var torrent in jsonResponse.Resource.results) foreach (var torrent in jsonResponse.Resource.results)
{ {
var torrentInfo = new TorrentInfo var torrentInfo = new TorrentInfo
{ {
Guid = GetGuid(torrent), Guid = GetGuid(torrent),
Title = torrent.release_name, Title = torrent.release_name,
Size = (long)torrent.size * 1000 * 1000, Categories = new List<IndexerCategory> { NewznabStandardCategory.Movies },
Size = torrent.size * 1000 * 1000,
DownloadUrl = torrent.download_url, DownloadUrl = torrent.download_url,
InfoUrl = torrent.details_url, InfoUrl = torrent.details_url,
ImdbId = ParseUtil.GetImdbId(torrent.imdb_id).GetValueOrDefault(),
PublishDate = torrent.publish_date.ToUniversalTime(), PublishDate = torrent.publish_date.ToUniversalTime(),
Seeders = torrent.seeders, Seeders = torrent.seeders,
Peers = torrent.leechers + torrent.seeders Peers = torrent.leechers + torrent.seeders
}; };
results.Add(torrentInfo); releaseInfos.Add(torrentInfo);
} }
return results; return releaseInfos
.OrderByDescending(o => o.PublishDate)
.ToArray();
} }
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
@ -57,12 +67,10 @@ namespace NzbDrone.Core.Indexers.Definitions.TorrentPotato
if (match.Success) if (match.Success)
{ {
return string.Format("potato-{0}", match.Groups[1].Value); return $"potato-{match.Groups[1].Value}";
}
else
{
return string.Format("potato-{0}", torrent.download_url);
} }
return $"potato-{torrent.download_url}";
} }
} }
} }

@ -8,70 +8,19 @@ namespace NzbDrone.Core.Indexers.Definitions.TorrentPotato
{ {
public class TorrentPotatoRequestGenerator : IIndexerRequestGenerator public class TorrentPotatoRequestGenerator : IIndexerRequestGenerator
{ {
public TorrentPotatoSettings Settings { get; set; } private readonly TorrentPotatoSettings _settings;
public virtual IndexerPageableRequestChain GetRecentRequests() public TorrentPotatoRequestGenerator(TorrentPotatoSettings settings)
{ {
var pageableRequests = new IndexerPageableRequestChain(); _settings = settings;
pageableRequests.Add(GetPagedRequests("list", null, null));
return pageableRequests;
}
private IEnumerable<IndexerRequest> GetPagedRequests(string mode, int? tvdbId, string query, params object[] args)
{
var requestBuilder = new HttpRequestBuilder(Settings.BaseUrl)
.Accept(HttpAccept.Json);
requestBuilder.AddQueryParam("passkey", Settings.Passkey);
if (!string.IsNullOrWhiteSpace(Settings.User))
{
requestBuilder.AddQueryParam("user", Settings.User);
}
else
{
requestBuilder.AddQueryParam("user", "");
}
requestBuilder.AddQueryParam("search", "-");
yield return new IndexerRequest(requestBuilder.Build());
}
private IEnumerable<IndexerRequest> GetMovieRequest(MovieSearchCriteria searchCriteria)
{
var requestBuilder = new HttpRequestBuilder(Settings.BaseUrl)
.Accept(HttpAccept.Json);
requestBuilder.AddQueryParam("passkey", Settings.Passkey);
if (!string.IsNullOrWhiteSpace(Settings.User))
{
requestBuilder.AddQueryParam("user", Settings.User);
}
else
{
requestBuilder.AddQueryParam("user", "");
}
if (searchCriteria.ImdbId.IsNotNullOrWhiteSpace())
{
requestBuilder.AddQueryParam("imdbid", searchCriteria.ImdbId);
}
else if (searchCriteria.SearchTerm.IsNotNullOrWhiteSpace())
{
//TODO: Hack for now
requestBuilder.AddQueryParam("search", $"{searchCriteria.SearchTerm}");
}
yield return new IndexerRequest(requestBuilder.Build());
} }
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
{ {
var pageableRequests = new IndexerPageableRequestChain(); var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetMovieRequest(searchCriteria));
pageableRequests.Add(BuildRequest(searchCriteria.SearchTerm, searchCriteria.ImdbId));
return pageableRequests; return pageableRequests;
} }
@ -92,7 +41,29 @@ namespace NzbDrone.Core.Indexers.Definitions.TorrentPotato
public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria) public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria)
{ {
return new IndexerPageableRequestChain(); var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(BuildRequest(searchCriteria.SearchTerm));
return pageableRequests;
}
private IEnumerable<IndexerRequest> BuildRequest(string searchTerm, string imdbId = null)
{
var requestBuilder = new HttpRequestBuilder(_settings.BaseUrl)
.Accept(HttpAccept.Json);
requestBuilder.AddQueryParam("passkey", _settings.Passkey);
requestBuilder.AddQueryParam("user", _settings.User.IsNotNullOrWhiteSpace() ? _settings.User : "");
if (imdbId.IsNotNullOrWhiteSpace())
{
requestBuilder.AddQueryParam("imdbid", imdbId);
}
requestBuilder.AddQueryParam("search", searchTerm.IsNotNullOrWhiteSpace() ? $"{searchTerm}" : " ");
yield return new IndexerRequest(requestBuilder.Build());
} }
public Func<IDictionary<string, string>> GetCookies { get; set; } public Func<IDictionary<string, string>> GetCookies { get; set; }

@ -4,8 +4,9 @@ namespace NzbDrone.Core.Indexers.Definitions.TorrentPotato
{ {
public class TorrentPotatoResponse public class TorrentPotatoResponse
{ {
public Result[] results { get; set; }
public int total_results { get; set; } public int total_results { get; set; }
public Result[] results { get; set; }
public string error { get; set; }
} }
public class Result public class Result
@ -14,9 +15,10 @@ namespace NzbDrone.Core.Indexers.Definitions.TorrentPotato
public string torrent_id { get; set; } public string torrent_id { get; set; }
public string details_url { get; set; } public string details_url { get; set; }
public string download_url { get; set; } public string download_url { get; set; }
public string imdb_id { get; set; }
public bool freeleech { get; set; } public bool freeleech { get; set; }
public string type { get; set; } public string type { get; set; }
public int size { get; set; } public long size { get; set; }
public int leechers { get; set; } public int leechers { get; set; }
public int seeders { get; set; } public int seeders { get; set; }
public DateTime publish_date { get; set; } public DateTime publish_date { get; set; }

@ -1,30 +1,42 @@
using FluentValidation; using FluentValidation;
using NzbDrone.Core.Annotations; using NzbDrone.Core.Annotations;
using NzbDrone.Core.Indexers.Settings;
using NzbDrone.Core.Validation; using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Indexers.Definitions.TorrentPotato namespace NzbDrone.Core.Indexers.Definitions.TorrentPotato
{ {
public class TorrentPotatoSettingsValidator : NoAuthSettingsValidator<TorrentPotatoSettings> public class TorrentPotatoSettingsValidator : AbstractValidator<TorrentPotatoSettings>
{ {
public TorrentPotatoSettingsValidator() public TorrentPotatoSettingsValidator()
{ {
RuleFor(c => c.User).NotEmpty(); RuleFor(c => c.User).NotEmpty();
RuleFor(c => c.Passkey).NotEmpty(); RuleFor(c => c.Passkey).NotEmpty();
RuleFor(c => c.BaseUrl).ValidRootUrl();
RuleFor(c => c.BaseSettings).SetValidator(new IndexerCommonSettingsValidator());
RuleFor(c => c.TorrentBaseSettings).SetValidator(new IndexerTorrentSettingsValidator());
} }
} }
public class TorrentPotatoSettings : NoAuthTorrentBaseSettings public class TorrentPotatoSettings : IIndexerSettings
{ {
private static readonly TorrentPotatoSettingsValidator Validator = new (); private static readonly TorrentPotatoSettingsValidator Validator = new ();
[FieldDefinition(0, Label = "API URL", HelpText = "URL to TorrentPotato API")]
public string BaseUrl { get; set; }
[FieldDefinition(2, Label = "Username", HelpText = "Indexer Username", Privacy = PrivacyLevel.UserName)] [FieldDefinition(2, Label = "Username", HelpText = "Indexer Username", Privacy = PrivacyLevel.UserName)]
public string User { get; set; } public string User { get; set; }
[FieldDefinition(3, Label = "Passkey", HelpText = "Indexer Password", Privacy = PrivacyLevel.Password, Type = FieldType.Password)] [FieldDefinition(3, Label = "Passkey", HelpText = "Indexer Passkey", Privacy = PrivacyLevel.Password, Type = FieldType.Password)]
public string Passkey { get; set; } public string Passkey { get; set; }
public override NzbDroneValidationResult Validate() [FieldDefinition(20)]
public IndexerBaseSettings BaseSettings { get; set; } = new ();
[FieldDefinition(21)]
public IndexerTorrentBaseSettings TorrentBaseSettings { get; set; } = new ();
public virtual NzbDroneValidationResult Validate()
{ {
return new NzbDroneValidationResult(Validator.Validate(this)); return new NzbDroneValidationResult(Validator.Validate(this));
} }

Loading…
Cancel
Save