Fixed: (TorrentPotato) Allow use of custom APIs

pull/1759/head
Bogdan 12 months ago
parent 90e92c0b66
commit 6769055b6b

@ -1,32 +1,51 @@
using System;
using System.Collections.Generic;
using NLog;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.ThingiProvider;
namespace NzbDrone.Core.Indexers.Definitions.TorrentPotato
{
public class TorrentPotato : TorrentIndexerBase<TorrentPotatoSettings>
{
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 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)
: 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
{
Enable = true,
Name = name,
Description = description,
Implementation = GetType().Name,
Settings = settings,
Settings = new TorrentPotatoSettings { BaseUrl = baseUrl },
Protocol = DownloadProtocol.Torrent,
SupportsRss = SupportsRss,
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()
{
return new TorrentPotatoParser();
caps.Categories.AddCategoryMapping("1", NewznabStandardCategory.Movies);
return caps;
}
}
}

@ -1,52 +1,62 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text.RegularExpressions;
using NzbDrone.Common.Http;
using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Indexers.Definitions.TorrentPotato
{
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)
{
var results = new List<ReleaseInfo>();
var releaseInfos = new List<ReleaseInfo>();
switch (indexerResponse.HttpResponse.StatusCode)
if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK)
{
default:
if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK)
{
throw new IndexerException(indexerResponse, "Indexer API call returned an unexpected StatusCode [{0}]", indexerResponse.HttpResponse.StatusCode);
}
break;
throw new IndexerException(indexerResponse, "Indexer API call returned an unexpected StatusCode [{0}]", indexerResponse.HttpResponse.StatusCode);
}
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)
{
var torrentInfo = new TorrentInfo
{
Guid = GetGuid(torrent),
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,
InfoUrl = torrent.details_url,
ImdbId = ParseUtil.GetImdbId(torrent.imdb_id).GetValueOrDefault(),
PublishDate = torrent.publish_date.ToUniversalTime(),
Seeders = 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; }
@ -57,12 +67,10 @@ namespace NzbDrone.Core.Indexers.Definitions.TorrentPotato
if (match.Success)
{
return string.Format("potato-{0}", match.Groups[1].Value);
}
else
{
return string.Format("potato-{0}", torrent.download_url);
return $"potato-{match.Groups[1].Value}";
}
return $"potato-{torrent.download_url}";
}
}
}

@ -8,70 +8,19 @@ namespace NzbDrone.Core.Indexers.Definitions.TorrentPotato
{
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();
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());
_settings = settings;
}
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetMovieRequest(searchCriteria));
pageableRequests.Add(BuildRequest(searchCriteria.SearchTerm, searchCriteria.ImdbId));
return pageableRequests;
}
@ -92,7 +41,29 @@ namespace NzbDrone.Core.Indexers.Definitions.TorrentPotato
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; }

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

@ -1,30 +1,42 @@
using FluentValidation;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.Indexers.Settings;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Indexers.Definitions.TorrentPotato
{
public class TorrentPotatoSettingsValidator : NoAuthSettingsValidator<TorrentPotatoSettings>
public class TorrentPotatoSettingsValidator : AbstractValidator<TorrentPotatoSettings>
{
public TorrentPotatoSettingsValidator()
{
RuleFor(c => c.User).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 ();
[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)]
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 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));
}

Loading…
Cancel
Save