mirror of
https://github.com/Prowlarr/Prowlarr.git
synced 2025-09-17 17:14:18 +02:00
Fixup Gazelle Parsing, Rework Auth to allow Indexer Override
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Core.Configuration;
|
||||
@@ -8,6 +9,7 @@ namespace NzbDrone.Core.Indexers.Gazelle
|
||||
{
|
||||
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
|
||||
public override string BaseUrl => "";
|
||||
protected virtual string LoginUrl => BaseUrl + "login.php";
|
||||
public override bool SupportsRss => true;
|
||||
public override bool SupportsSearch => true;
|
||||
public override int PageSize => 50;
|
||||
@@ -44,5 +46,50 @@ namespace NzbDrone.Core.Indexers.Gazelle
|
||||
|
||||
return caps;
|
||||
}
|
||||
|
||||
protected override void DoLogin()
|
||||
{
|
||||
var requestBuilder = new HttpRequestBuilder(LoginUrl)
|
||||
{
|
||||
LogResponseContent = true
|
||||
};
|
||||
|
||||
requestBuilder.Method = HttpMethod.POST;
|
||||
requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15);
|
||||
|
||||
var cookies = Cookies;
|
||||
|
||||
Cookies = null;
|
||||
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();
|
||||
|
||||
Cookies = cookies;
|
||||
|
||||
UpdateCookies(cookies, DateTime.Now + TimeSpan.FromDays(30));
|
||||
|
||||
_logger.Debug("Gazelle authentication succeeded.");
|
||||
|
||||
//Settings.AuthKey = index.Response.Authkey;
|
||||
//Settings.PassKey = index.Response.Passkey;
|
||||
}
|
||||
|
||||
protected override bool CheckIfLoginNeeded(HttpResponse response)
|
||||
{
|
||||
if (response.HasHttpRedirect || (response.Content != null && response.Content.Contains("\"bad credentials\"")))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -43,6 +43,13 @@ namespace NzbDrone.Core.Indexers.Gazelle
|
||||
{
|
||||
public string GroupId { get; set; }
|
||||
public string GroupName { get; set; }
|
||||
public int TorrentId { get; set; }
|
||||
public string Size { get; set; }
|
||||
public int FileCount { get; set; }
|
||||
public string Snatches { get; set; }
|
||||
public string Seeders { get; set; }
|
||||
public string Leechers { get; set; }
|
||||
public string Category { get; set; }
|
||||
public string Artist { get; set; }
|
||||
public string GroupYear { get; set; }
|
||||
public string Cover { get; set; }
|
||||
@@ -52,8 +59,12 @@ namespace NzbDrone.Core.Indexers.Gazelle
|
||||
public int TotalSeeders { get; set; }
|
||||
public int TotalSnatched { get; set; }
|
||||
public long MaxSize { get; set; }
|
||||
public string GroupTime { get; set; }
|
||||
public long GroupTime { get; set; }
|
||||
public List<GazelleTorrent> Torrents { get; set; }
|
||||
public bool IsFreeLeech { get; set; }
|
||||
public bool IsNeutralLeech { get; set; }
|
||||
public bool IsPersonalFreeLeech { get; set; }
|
||||
public bool CanUseToken { get; set; }
|
||||
}
|
||||
|
||||
public class GazelleResponse
|
||||
|
@@ -73,6 +73,7 @@ namespace NzbDrone.Core.Indexers.Gazelle
|
||||
Guid = string.Format("Gazelle-{0}", id),
|
||||
Title = WebUtility.HtmlDecode(title),
|
||||
Container = torrent.Encoding,
|
||||
Files = torrent.FileCount,
|
||||
Codec = torrent.Format,
|
||||
Size = long.Parse(torrent.Size),
|
||||
DownloadUrl = GetDownloadUrl(id),
|
||||
@@ -96,6 +97,36 @@ namespace NzbDrone.Core.Indexers.Gazelle
|
||||
torrentInfos.Add(release);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var id = result.TorrentId;
|
||||
var groupName = WebUtility.HtmlDecode(result.GroupName);
|
||||
|
||||
var release = new GazelleInfo()
|
||||
{
|
||||
Guid = string.Format("Gazelle-{0}", id),
|
||||
Title = groupName,
|
||||
Size = long.Parse(result.Size),
|
||||
DownloadUrl = GetDownloadUrl(id),
|
||||
InfoUrl = GetInfoUrl(result.GroupId, id),
|
||||
Seeders = int.Parse(result.Seeders),
|
||||
Peers = int.Parse(result.Leechers) + int.Parse(result.Seeders),
|
||||
Files = result.FileCount,
|
||||
PublishDate = DateTimeOffset.FromUnixTimeSeconds(result.GroupTime).UtcDateTime,
|
||||
};
|
||||
|
||||
var category = result.Category;
|
||||
if (category == null || category.Contains("Select Category"))
|
||||
{
|
||||
release.Category = _capabilities.Categories.MapTrackerCatToNewznab("1");
|
||||
}
|
||||
else
|
||||
{
|
||||
release.Category = _capabilities.Categories.MapTrackerCatDescToNewznab(category);
|
||||
}
|
||||
|
||||
torrentInfos.Add(release);
|
||||
}
|
||||
}
|
||||
|
||||
// order by date
|
||||
@@ -110,9 +141,7 @@ namespace NzbDrone.Core.Indexers.Gazelle
|
||||
var url = new HttpUri(_baseUrl)
|
||||
.CombinePath("/torrents.php")
|
||||
.AddQueryParam("action", "download")
|
||||
.AddQueryParam("id", torrentId)
|
||||
.AddQueryParam("authkey", _settings.AuthKey)
|
||||
.AddQueryParam("torrent_pass", _settings.PassKey);
|
||||
.AddQueryParam("id", torrentId);
|
||||
|
||||
return url.FullUri;
|
||||
}
|
||||
|
@@ -20,7 +20,6 @@ namespace NzbDrone.Core.Indexers.Gazelle
|
||||
public IndexerCapabilities Capabilities { get; set; }
|
||||
public Logger Logger { get; set; }
|
||||
|
||||
protected virtual string LoginUrl => BaseUrl + "login.php";
|
||||
protected virtual string APIUrl => BaseUrl + "ajax.php";
|
||||
protected virtual string DownloadUrl => BaseUrl + "torrents.php?action=download&usetoken=" + (Settings.UseFreeleechToken ? "1" : "0") + "&id=";
|
||||
protected virtual string DetailsUrl => BaseUrl + "torrents.php?torrentid=";
|
||||
@@ -40,10 +39,6 @@ namespace NzbDrone.Core.Indexers.Gazelle
|
||||
|
||||
private IEnumerable<IndexerRequest> GetRequest(string searchParameters)
|
||||
{
|
||||
AuthCookieCache = GetCookies();
|
||||
|
||||
Authenticate();
|
||||
|
||||
var filter = "";
|
||||
if (searchParameters == null)
|
||||
{
|
||||
@@ -51,91 +46,17 @@ namespace NzbDrone.Core.Indexers.Gazelle
|
||||
|
||||
var request =
|
||||
new IndexerRequest(
|
||||
$"{APIUrl}?action=browse{searchParameters}{filter}",
|
||||
$"{APIUrl}?{searchParameters}{filter}",
|
||||
HttpAccept.Json);
|
||||
|
||||
var cookies = AuthCookieCache;
|
||||
foreach (var cookie in cookies)
|
||||
{
|
||||
request.HttpRequest.Cookies[cookie.Key] = cookie.Value;
|
||||
}
|
||||
|
||||
yield return request;
|
||||
}
|
||||
|
||||
private GazelleAuthResponse GetIndex(IDictionary<string, string> cookies)
|
||||
{
|
||||
var indexRequestBuilder = new HttpRequestBuilder($"{APIUrl}?action=index")
|
||||
{
|
||||
LogResponseContent = true
|
||||
};
|
||||
|
||||
indexRequestBuilder.SetCookies(cookies);
|
||||
indexRequestBuilder.Method = HttpMethod.POST;
|
||||
|
||||
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(LoginUrl)
|
||||
{
|
||||
LogResponseContent = true
|
||||
};
|
||||
|
||||
requestBuilder.Method = HttpMethod.POST;
|
||||
requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15);
|
||||
|
||||
var cookies = AuthCookieCache;
|
||||
|
||||
if (cookies == null)
|
||||
{
|
||||
AuthCookieCache = null;
|
||||
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 = cookies;
|
||||
CookiesUpdater(cookies, DateTime.Now + TimeSpan.FromDays(30));
|
||||
}
|
||||
|
||||
var index = GetIndex(cookies);
|
||||
|
||||
if (index == null || index.Status.IsNullOrWhiteSpace() || index.Status != "success")
|
||||
{
|
||||
Logger.Debug("Gazelle authentication failed.");
|
||||
AuthCookieCache = null;
|
||||
CookiesUpdater(null, null);
|
||||
throw new Exception("Failed to authenticate with Gazelle.");
|
||||
}
|
||||
|
||||
Logger.Debug("Gazelle authentication succeeded.");
|
||||
|
||||
Settings.AuthKey = index.Response.Authkey;
|
||||
Settings.PassKey = index.Response.Passkey;
|
||||
}
|
||||
|
||||
private string GetBasicSearchParameters(string searchTerm, int[] categories)
|
||||
{
|
||||
var searchString = GetSearchTerm(searchTerm);
|
||||
|
||||
var parameters = "&action=browse&order_by=time&order_way=desc";
|
||||
var parameters = "action=browse&order_by=time&order_way=desc";
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(searchString))
|
||||
{
|
||||
|
@@ -22,6 +22,7 @@ namespace NzbDrone.Core.Indexers
|
||||
protected const int MaxNumResultsPerQuery = 1000;
|
||||
|
||||
protected readonly IHttpClient _httpClient;
|
||||
public IDictionary<string, string> Cookies { get; set; }
|
||||
|
||||
public override bool SupportsRss => true;
|
||||
public override bool SupportsSearch => true;
|
||||
@@ -111,6 +112,23 @@ namespace NzbDrone.Core.Indexers
|
||||
return generator;
|
||||
}
|
||||
|
||||
protected IDictionary<string, string> GetCookies()
|
||||
{
|
||||
var cookies = _indexerStatusService.GetIndexerCookies(Definition.Id);
|
||||
var expiration = _indexerStatusService.GetIndexerCookiesExpirationDate(Definition.Id);
|
||||
if (expiration < DateTime.Now)
|
||||
{
|
||||
cookies = null;
|
||||
}
|
||||
|
||||
return cookies;
|
||||
}
|
||||
|
||||
protected void UpdateCookies(IDictionary<string, string> cookies, DateTime? expiration)
|
||||
{
|
||||
_indexerStatusService.UpdateCookies(Definition.Id, cookies, expiration);
|
||||
}
|
||||
|
||||
protected virtual IndexerPageableQueryResult FetchReleases(Func<IIndexerRequestGenerator, IndexerPageableRequestChain> pageableRequestChainSelector, bool isRecent = false)
|
||||
{
|
||||
var releases = new List<ReleaseInfo>();
|
||||
@@ -333,6 +351,15 @@ namespace NzbDrone.Core.Indexers
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual bool CheckIfLoginNeeded(HttpResponse httpResponse)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected virtual void DoLogin()
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual IndexerResponse FetchIndexerResponse(IndexerRequest request)
|
||||
{
|
||||
_logger.Debug("Downloading Feed " + request.HttpRequest.ToString(false));
|
||||
@@ -342,7 +369,17 @@ namespace NzbDrone.Core.Indexers
|
||||
request.HttpRequest.RateLimit = RateLimit;
|
||||
}
|
||||
|
||||
request.HttpRequest.AllowAutoRedirect = true;
|
||||
request.HttpRequest.AllowAutoRedirect = false;
|
||||
|
||||
Cookies = GetCookies();
|
||||
|
||||
if (Cookies != null)
|
||||
{
|
||||
foreach (var cookie in Cookies)
|
||||
{
|
||||
request.HttpRequest.Cookies.Add(cookie.Key, cookie.Value);
|
||||
}
|
||||
}
|
||||
|
||||
var stopWatch = Stopwatch.StartNew();
|
||||
|
||||
@@ -350,6 +387,23 @@ namespace NzbDrone.Core.Indexers
|
||||
|
||||
stopWatch.Stop();
|
||||
|
||||
// Check reponse to see if auth is needed, if needed try again
|
||||
if (CheckIfLoginNeeded(response))
|
||||
{
|
||||
DoLogin();
|
||||
request.HttpRequest.Cookies.Clear();
|
||||
|
||||
if (Cookies != null)
|
||||
{
|
||||
foreach (var cookie in Cookies)
|
||||
{
|
||||
request.HttpRequest.Cookies.Add(cookie.Key, cookie.Value);
|
||||
}
|
||||
}
|
||||
|
||||
response = _httpClient.Execute(request.HttpRequest);
|
||||
}
|
||||
|
||||
return new IndexerResponse(request, response, stopWatch.ElapsedMilliseconds);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user