parent
7c3446baab
commit
1322633d0d
@ -0,0 +1,81 @@
|
||||
using NLog;
|
||||
using NzbDrone.Common.Cache;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.ThingiProvider;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace NzbDrone.Core.Indexers.Gazelle
|
||||
{
|
||||
public class Gazelle : HttpIndexerBase<GazelleSettings>
|
||||
{
|
||||
public override string Name => "Gazelle API";
|
||||
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
|
||||
public override bool SupportsRss => true;
|
||||
public override bool SupportsSearch => true;
|
||||
public override int PageSize => 50;
|
||||
|
||||
private readonly ICached<Dictionary<string, string>> _authCookieCache;
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public Gazelle(IHttpClient httpClient, ICacheManager cacheManager, IIndexerStatusService indexerStatusService,
|
||||
IConfigService configService, IParsingService parsingService, Logger logger)
|
||||
: base(httpClient, indexerStatusService, configService, parsingService, logger)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_logger = logger;
|
||||
_authCookieCache = cacheManager.GetCache<Dictionary<string, string>>(GetType(), "authCookies");
|
||||
}
|
||||
|
||||
public override IIndexerRequestGenerator GetRequestGenerator()
|
||||
{
|
||||
return new GazelleRequestGenerator()
|
||||
{
|
||||
Settings = Settings,
|
||||
HttpClient = _httpClient,
|
||||
Logger = _logger,
|
||||
AuthCookieCache = _authCookieCache
|
||||
};
|
||||
}
|
||||
|
||||
public override IParseIndexerResponse GetParser()
|
||||
{
|
||||
return new GazelleParser(Settings);
|
||||
}
|
||||
|
||||
public override IEnumerable<ProviderDefinition> DefaultDefinitions
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return GetDefinition("Apollo.Rip", GetSettings("https://apollo.rip"));
|
||||
yield return GetDefinition("REDacted", GetSettings("https://redacted.ch"));
|
||||
yield return GetDefinition("Not What CD", GetSettings("https://notwhat.cd"));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private IndexerDefinition GetDefinition(string name, GazelleSettings settings)
|
||||
{
|
||||
return new IndexerDefinition
|
||||
{
|
||||
EnableRss = false,
|
||||
EnableSearch = false,
|
||||
Name = name,
|
||||
Implementation = GetType().Name,
|
||||
Settings = settings,
|
||||
Protocol = DownloadProtocol.Torrent,
|
||||
SupportsRss = SupportsRss,
|
||||
SupportsSearch = SupportsSearch
|
||||
};
|
||||
}
|
||||
|
||||
private GazelleSettings GetSettings(string url)
|
||||
{
|
||||
var settings = new GazelleSettings { BaseUrl = url };
|
||||
|
||||
return settings;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,141 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Common.Cache;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Serializer;
|
||||
|
||||
namespace NzbDrone.Core.Indexers.Gazelle
|
||||
{
|
||||
public class GazelleRequestGenerator : IIndexerRequestGenerator
|
||||
{
|
||||
|
||||
public GazelleSettings Settings { get; set; }
|
||||
|
||||
public ICached<Dictionary<string, string>> AuthCookieCache { get; set; }
|
||||
public IHttpClient HttpClient { get; set; }
|
||||
public Logger Logger { get; set; }
|
||||
|
||||
public virtual IndexerPageableRequestChain GetRecentRequests()
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetRequest(null));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(AlbumSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
pageableRequests.Add(GetRequest(string.Format("&artistname={0}&groupname={1}", searchCriteria.Artist.Name, searchCriteria.AlbumTitle)));
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(ArtistSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
pageableRequests.Add(GetRequest(string.Format("&artistname={0}",searchCriteria.Artist.Name)));
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
private IEnumerable<IndexerRequest> GetRequest(string searchParameters)
|
||||
{
|
||||
Authenticate();
|
||||
|
||||
var filter = "";
|
||||
if (searchParameters == null)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
var request =
|
||||
new IndexerRequest(
|
||||
$"{Settings.BaseUrl.Trim().TrimEnd('/')}/ajax.php?action=browse&searchstr={searchParameters}{filter}",
|
||||
HttpAccept.Json);
|
||||
|
||||
var cookies = AuthCookieCache.Find(Settings.BaseUrl.Trim().TrimEnd('/'));
|
||||
foreach (var cookie in cookies)
|
||||
{
|
||||
request.HttpRequest.Cookies[cookie.Key] = cookie.Value;
|
||||
}
|
||||
|
||||
yield return request;
|
||||
}
|
||||
|
||||
private GazelleAuthResponse GetIndex(Dictionary<string,string> cookies)
|
||||
{
|
||||
var indexRequestBuilder = new HttpRequestBuilder($"{Settings.BaseUrl.Trim().TrimEnd('/')}")
|
||||
{
|
||||
LogResponseContent = true
|
||||
};
|
||||
|
||||
indexRequestBuilder.SetCookies(cookies);
|
||||
indexRequestBuilder.Method = HttpMethod.GET;
|
||||
indexRequestBuilder.Resource("ajax.php?action=index");
|
||||
|
||||
var authIndexRequest = indexRequestBuilder
|
||||
.Accept(HttpAccept.Json)
|
||||
.Build();
|
||||
|
||||
var indexResponse = HttpClient.Execute(authIndexRequest);
|
||||
|
||||
var result = Json.Deserialize<GazelleAuthResponse>(indexResponse.Content);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void Authenticate()
|
||||
{
|
||||
|
||||
var requestBuilder = new HttpRequestBuilder($"{Settings.BaseUrl.Trim().TrimEnd('/')}")
|
||||
{
|
||||
LogResponseContent = true
|
||||
};
|
||||
|
||||
requestBuilder.Method = HttpMethod.POST;
|
||||
requestBuilder.Resource("login.php");
|
||||
requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15);
|
||||
|
||||
var authKey = Settings.BaseUrl.Trim().TrimEnd('/');
|
||||
var cookies = AuthCookieCache.Find(authKey);
|
||||
|
||||
if (cookies == null)
|
||||
{
|
||||
AuthCookieCache.Remove(authKey);
|
||||
var authLoginRequest = requestBuilder
|
||||
.AddFormParameter("username", Settings.Username)
|
||||
.AddFormParameter("password", Settings.Password)
|
||||
.AddFormParameter("keeplogged", "1")
|
||||
.SetHeader("Content-Type", "multipart/form-data")
|
||||
.Accept(HttpAccept.Json)
|
||||
.Build();
|
||||
|
||||
var response = HttpClient.Execute(authLoginRequest);
|
||||
|
||||
cookies = response.GetCookies();
|
||||
AuthCookieCache.Set(authKey, cookies, new TimeSpan(7, 0, 0, 0, 0)); // re-auth every 7 days
|
||||
requestBuilder.SetCookies(cookies);
|
||||
}
|
||||
else
|
||||
{
|
||||
requestBuilder.SetCookies(cookies);
|
||||
}
|
||||
|
||||
var index = GetIndex(cookies);
|
||||
|
||||
if (index.Status != "success" || string.IsNullOrWhiteSpace(index.Status))
|
||||
{
|
||||
Logger.Debug("Gazelle authentication failed.");
|
||||
throw new Exception("Failed to authenticate with Gazelle.");
|
||||
}
|
||||
|
||||
Logger.Debug("Gazelle authentication succeeded.");
|
||||
|
||||
Settings.AuthKey = index.Response.Authkey;
|
||||
Settings.PassKey = index.Response.Passkey;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
using FluentValidation;
|
||||
using NzbDrone.Core.Annotations;
|
||||
using NzbDrone.Core.ThingiProvider;
|
||||
using NzbDrone.Core.Validation;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace NzbDrone.Core.Indexers.Gazelle
|
||||
{
|
||||
public class GazelleSettingsValidator : AbstractValidator<GazelleSettings>
|
||||
{
|
||||
public GazelleSettingsValidator()
|
||||
{
|
||||
RuleFor(c => c.BaseUrl).ValidRootUrl();
|
||||
RuleFor(c => c.Username).NotEmpty();
|
||||
RuleFor(c => c.Password).NotEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
public class GazelleSettings : IProviderConfig
|
||||
{
|
||||
private static readonly GazelleSettingsValidator Validator = new GazelleSettingsValidator();
|
||||
|
||||
public GazelleSettings()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public string AuthKey;
|
||||
public string PassKey;
|
||||
|
||||
[FieldDefinition(0, Label = "URL", Advanced = true, HelpText = "Do not change this unless you know what you're doing. Since your cookie will be sent to that host.")]
|
||||
public string BaseUrl { get; set; }
|
||||
|
||||
[FieldDefinition(1, Label = "Username", HelpText = "Username")]
|
||||
public string Username { get; set; }
|
||||
|
||||
[FieldDefinition(2, Label = "Password", Type = FieldType.Password, HelpText = "Password")]
|
||||
public string Password { get; set; }
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
{
|
||||
return new NzbDroneValidationResult(Validator.Validate(this));
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in new issue