mirror of
https://github.com/lidarr/lidarr.git
synced 2025-08-20 13:33:34 -07:00
Added TorrentPotato Indexer.
This commit is contained in:
parent
a63587bb19
commit
7a5fe59dbf
7 changed files with 321 additions and 0 deletions
64
src/NzbDrone.Core/Indexers/TorrentPotato/TorrentPotato.cs
Normal file
64
src/NzbDrone.Core/Indexers/TorrentPotato/TorrentPotato.cs
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using NLog;
|
||||||
|
using NzbDrone.Common.Extensions;
|
||||||
|
using NzbDrone.Common.Http;
|
||||||
|
using NzbDrone.Core.Configuration;
|
||||||
|
using NzbDrone.Core.Exceptions;
|
||||||
|
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||||
|
using NzbDrone.Core.ThingiProvider;
|
||||||
|
using NzbDrone.Core.Http.CloudFlare;
|
||||||
|
using NzbDrone.Core.Parser;
|
||||||
|
using NzbDrone.Core.Validation;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Indexers.TorrentPotato
|
||||||
|
{
|
||||||
|
public class TorrentPotato : HttpIndexerBase<TorrentPotatoSettings>
|
||||||
|
{
|
||||||
|
public override string Name => "TorrentPotato";
|
||||||
|
|
||||||
|
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
|
||||||
|
public override TimeSpan RateLimit => TimeSpan.FromSeconds(2);
|
||||||
|
|
||||||
|
public TorrentPotato(IHttpClient httpClient, IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger)
|
||||||
|
: base(httpClient, indexerStatusService, configService, parsingService, logger)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<ProviderDefinition> DefaultDefinitions
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
yield return GetDefinition("Jackett", new TorrentPotatoSettings { BaseUrl = "http://localhost:9117/potato/YOURINDEXER"});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IndexerDefinition GetDefinition(string name, TorrentPotatoSettings settings)
|
||||||
|
{
|
||||||
|
return new IndexerDefinition
|
||||||
|
{
|
||||||
|
EnableRss = false,
|
||||||
|
EnableSearch = false,
|
||||||
|
Name = name,
|
||||||
|
Implementation = GetType().Name,
|
||||||
|
Settings = settings,
|
||||||
|
Protocol = DownloadProtocol.Torrent,
|
||||||
|
SupportsRss = SupportsRss,
|
||||||
|
SupportsSearch = SupportsSearch
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IIndexerRequestGenerator GetRequestGenerator()
|
||||||
|
{
|
||||||
|
return new TorrentPotatoRequestGenerator() { Settings = Settings };
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IParseIndexerResponse GetParser()
|
||||||
|
{
|
||||||
|
return new TorrentPotatoParser();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Net;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using NzbDrone.Common.Http;
|
||||||
|
using NzbDrone.Core.Indexers.Exceptions;
|
||||||
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Indexers.TorrentPotato
|
||||||
|
{
|
||||||
|
public class TorrentPotatoParser : IParseIndexerResponse
|
||||||
|
{
|
||||||
|
private static readonly Regex RegexGuid = new Regex(@"^magnet:\?xt=urn:btih:([a-f0-9]+)", RegexOptions.Compiled);
|
||||||
|
|
||||||
|
public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
|
||||||
|
{
|
||||||
|
var results = new List<ReleaseInfo>();
|
||||||
|
|
||||||
|
switch (indexerResponse.HttpResponse.StatusCode)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
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);
|
||||||
|
|
||||||
|
foreach (var torrent in jsonResponse.Resource.results)
|
||||||
|
{
|
||||||
|
var torrentInfo = new TorrentInfo();
|
||||||
|
|
||||||
|
torrentInfo.Guid = GetGuid(torrent);
|
||||||
|
torrentInfo.Title = torrent.release_name;
|
||||||
|
torrentInfo.Size = (long)torrent.size*1000*1000;
|
||||||
|
torrentInfo.DownloadUrl = torrent.download_url;
|
||||||
|
torrentInfo.InfoUrl = torrent.details_url;
|
||||||
|
torrentInfo.PublishDate = new System.DateTime();
|
||||||
|
torrentInfo.Seeders = torrent.seeders;
|
||||||
|
torrentInfo.Peers = torrent.leechers + torrent.seeders;
|
||||||
|
torrentInfo.Freeleech = torrent.freeleech;
|
||||||
|
|
||||||
|
results.Add(torrentInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetGuid(Result torrent)
|
||||||
|
{
|
||||||
|
var match = RegexGuid.Match(torrent.download_url);
|
||||||
|
|
||||||
|
if (match.Success)
|
||||||
|
{
|
||||||
|
return string.Format("potato-{0}", match.Groups[1].Value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return string.Format("potato-{0}", torrent.download_url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,122 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using NzbDrone.Common.Extensions;
|
||||||
|
using NzbDrone.Common.Http;
|
||||||
|
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Indexers.TorrentPotato
|
||||||
|
{
|
||||||
|
public class TorrentPotatoRequestGenerator : IIndexerRequestGenerator
|
||||||
|
{
|
||||||
|
|
||||||
|
public TorrentPotatoSettings Settings { get; set; }
|
||||||
|
|
||||||
|
public TorrentPotatoRequestGenerator()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual IndexerPageableRequestChain GetRecentRequests()
|
||||||
|
{
|
||||||
|
var pageableRequests = new IndexerPageableRequestChain();
|
||||||
|
|
||||||
|
pageableRequests.Add(GetPagedRequests("list", null, null));
|
||||||
|
|
||||||
|
return pageableRequests;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual IndexerPageableRequestChain GetSearchRequests(SingleEpisodeSearchCriteria searchCriteria)
|
||||||
|
{
|
||||||
|
var pageableRequests = new IndexerPageableRequestChain();
|
||||||
|
|
||||||
|
pageableRequests.Add(GetPagedRequests("search", searchCriteria.Series.TvdbId, "S{0:00}E{1:00}", searchCriteria.SeasonNumber, searchCriteria.EpisodeNumber));
|
||||||
|
|
||||||
|
return pageableRequests;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual IndexerPageableRequestChain GetSearchRequests(SeasonSearchCriteria searchCriteria)
|
||||||
|
{
|
||||||
|
var pageableRequests = new IndexerPageableRequestChain();
|
||||||
|
|
||||||
|
pageableRequests.Add(GetPagedRequests("search", searchCriteria.Series.TvdbId, "S{0:00}", searchCriteria.SeasonNumber));
|
||||||
|
|
||||||
|
return pageableRequests;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual IndexerPageableRequestChain GetSearchRequests(DailyEpisodeSearchCriteria searchCriteria)
|
||||||
|
{
|
||||||
|
var pageableRequests = new IndexerPageableRequestChain();
|
||||||
|
|
||||||
|
pageableRequests.Add(GetPagedRequests("search", searchCriteria.Series.TvdbId, "\"{0:yyyy MM dd}\"", searchCriteria.AirDate));
|
||||||
|
|
||||||
|
return pageableRequests;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual IndexerPageableRequestChain GetSearchRequests(AnimeEpisodeSearchCriteria searchCriteria)
|
||||||
|
{
|
||||||
|
return new IndexerPageableRequestChain();
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual IndexerPageableRequestChain GetSearchRequests(SpecialEpisodeSearchCriteria searchCriteria)
|
||||||
|
{
|
||||||
|
var pageableRequests = new IndexerPageableRequestChain();
|
||||||
|
|
||||||
|
foreach (var queryTitle in searchCriteria.EpisodeQueryTitles)
|
||||||
|
{
|
||||||
|
var query = queryTitle.Replace('+', ' ');
|
||||||
|
query = System.Web.HttpUtility.UrlEncode(query);
|
||||||
|
|
||||||
|
pageableRequests.Add(GetPagedRequests("search", searchCriteria.Series.TvdbId, query));
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
requestBuilder.AddQueryParam("user", Settings.User);
|
||||||
|
requestBuilder.AddQueryParam("imdbid", "tt0076759"); //For now just search for Star Wars.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
requestBuilder.AddQueryParam("user", Settings.User);
|
||||||
|
|
||||||
|
if (searchCriteria.Movie.ImdbId.IsNotNullOrWhiteSpace())
|
||||||
|
{
|
||||||
|
requestBuilder.AddQueryParam("imdbid", searchCriteria.Movie.ImdbId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
requestBuilder.AddQueryParam("search", searchCriteria.Movie.Title);
|
||||||
|
}
|
||||||
|
|
||||||
|
yield return new IndexerRequest(requestBuilder.Build());
|
||||||
|
}
|
||||||
|
|
||||||
|
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
var pageableRequests = new IndexerPageableRequestChain();
|
||||||
|
|
||||||
|
pageableRequests.Add(GetMovieRequest(searchCriteria));
|
||||||
|
|
||||||
|
return pageableRequests;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Indexers.TorrentPotato
|
||||||
|
{
|
||||||
|
|
||||||
|
public class TorrentPotatoResponse
|
||||||
|
{
|
||||||
|
public Result[] results { get; set; }
|
||||||
|
public int total_results { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Result
|
||||||
|
{
|
||||||
|
public string release_name { get; set; }
|
||||||
|
public string torrent_id { get; set; }
|
||||||
|
public string details_url { get; set; }
|
||||||
|
public string download_url { get; set; }
|
||||||
|
public bool freeleech { get; set; }
|
||||||
|
public string type { get; set; }
|
||||||
|
public int size { get; set; }
|
||||||
|
public int leechers { get; set; }
|
||||||
|
public int seeders { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
using FluentValidation;
|
||||||
|
using NzbDrone.Core.Annotations;
|
||||||
|
using NzbDrone.Core.ThingiProvider;
|
||||||
|
using NzbDrone.Core.Validation;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Indexers.TorrentPotato
|
||||||
|
{
|
||||||
|
public class TorrentPotatoSettingsValidator : AbstractValidator<TorrentPotatoSettings>
|
||||||
|
{
|
||||||
|
public TorrentPotatoSettingsValidator()
|
||||||
|
{
|
||||||
|
RuleFor(c => c.BaseUrl).ValidRootUrl();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TorrentPotatoSettings : IProviderConfig
|
||||||
|
{
|
||||||
|
private static readonly TorrentPotatoSettingsValidator Validator = new TorrentPotatoSettingsValidator();
|
||||||
|
|
||||||
|
public TorrentPotatoSettings()
|
||||||
|
{
|
||||||
|
BaseUrl = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
[FieldDefinition(0, Label = "API URL", HelpText = "URL to TorrentPotato api.")]
|
||||||
|
public string BaseUrl { get; set; }
|
||||||
|
|
||||||
|
[FieldDefinition(1, Label = "Username", HelpText = "The username you use at your indexer.")]
|
||||||
|
public string User { get; set; }
|
||||||
|
|
||||||
|
[FieldDefinition(2, Label = "Passkey", HelpText = "The password you use at your Indexer,")]
|
||||||
|
public string Passkey { get; set; }
|
||||||
|
public NzbDroneValidationResult Validate()
|
||||||
|
{
|
||||||
|
return new NzbDroneValidationResult(Validator.Validate(this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -633,6 +633,11 @@
|
||||||
<Compile Include="Indexers\Omgwtfnzbs\OmgwtfnzbsRssParser.cs" />
|
<Compile Include="Indexers\Omgwtfnzbs\OmgwtfnzbsRssParser.cs" />
|
||||||
<Compile Include="Indexers\Omgwtfnzbs\OmgwtfnzbsSettings.cs" />
|
<Compile Include="Indexers\Omgwtfnzbs\OmgwtfnzbsSettings.cs" />
|
||||||
<Compile Include="Indexers\HttpIndexerBase.cs" />
|
<Compile Include="Indexers\HttpIndexerBase.cs" />
|
||||||
|
<Compile Include="Indexers\TorrentPotato\TorrentPotato.cs" />
|
||||||
|
<Compile Include="Indexers\TorrentPotato\TorrentPotatoParser.cs" />
|
||||||
|
<Compile Include="Indexers\TorrentPotato\TorrentPotatoRequestGenerator.cs" />
|
||||||
|
<Compile Include="Indexers\TorrentPotato\TorrentPotatoResponse.cs" />
|
||||||
|
<Compile Include="Indexers\TorrentPotato\TorrentPotatoSettings.cs" />
|
||||||
<Compile Include="Indexers\Rarbg\Rarbg.cs" />
|
<Compile Include="Indexers\Rarbg\Rarbg.cs" />
|
||||||
<Compile Include="Indexers\Rarbg\RarbgRequestGenerator.cs" />
|
<Compile Include="Indexers\Rarbg\RarbgRequestGenerator.cs" />
|
||||||
<Compile Include="Indexers\Rarbg\RarbgResponse.cs" />
|
<Compile Include="Indexers\Rarbg\RarbgResponse.cs" />
|
||||||
|
|
|
@ -8,6 +8,7 @@ namespace NzbDrone.Core.Parser.Model
|
||||||
public string InfoHash { get; set; }
|
public string InfoHash { get; set; }
|
||||||
public int? Seeders { get; set; }
|
public int? Seeders { get; set; }
|
||||||
public int? Peers { get; set; }
|
public int? Peers { get; set; }
|
||||||
|
public bool Freeleech { get; set; }
|
||||||
|
|
||||||
public static int? GetSeeders(ReleaseInfo release)
|
public static int? GetSeeders(ReleaseInfo release)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue