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 NLog;
|
||||||
using NzbDrone.Common.Http;
|
using NzbDrone.Common.Http;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
@@ -8,6 +9,7 @@ namespace NzbDrone.Core.Indexers.Gazelle
|
|||||||
{
|
{
|
||||||
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
|
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
|
||||||
public override string BaseUrl => "";
|
public override string BaseUrl => "";
|
||||||
|
protected virtual string LoginUrl => BaseUrl + "login.php";
|
||||||
public override bool SupportsRss => true;
|
public override bool SupportsRss => true;
|
||||||
public override bool SupportsSearch => true;
|
public override bool SupportsSearch => true;
|
||||||
public override int PageSize => 50;
|
public override int PageSize => 50;
|
||||||
@@ -44,5 +46,50 @@ namespace NzbDrone.Core.Indexers.Gazelle
|
|||||||
|
|
||||||
return caps;
|
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 GroupId { get; set; }
|
||||||
public string GroupName { 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 Artist { get; set; }
|
||||||
public string GroupYear { get; set; }
|
public string GroupYear { get; set; }
|
||||||
public string Cover { get; set; }
|
public string Cover { get; set; }
|
||||||
@@ -52,8 +59,12 @@ namespace NzbDrone.Core.Indexers.Gazelle
|
|||||||
public int TotalSeeders { get; set; }
|
public int TotalSeeders { get; set; }
|
||||||
public int TotalSnatched { get; set; }
|
public int TotalSnatched { get; set; }
|
||||||
public long MaxSize { get; set; }
|
public long MaxSize { get; set; }
|
||||||
public string GroupTime { get; set; }
|
public long GroupTime { get; set; }
|
||||||
public List<GazelleTorrent> Torrents { 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
|
public class GazelleResponse
|
||||||
|
@@ -73,6 +73,7 @@ namespace NzbDrone.Core.Indexers.Gazelle
|
|||||||
Guid = string.Format("Gazelle-{0}", id),
|
Guid = string.Format("Gazelle-{0}", id),
|
||||||
Title = WebUtility.HtmlDecode(title),
|
Title = WebUtility.HtmlDecode(title),
|
||||||
Container = torrent.Encoding,
|
Container = torrent.Encoding,
|
||||||
|
Files = torrent.FileCount,
|
||||||
Codec = torrent.Format,
|
Codec = torrent.Format,
|
||||||
Size = long.Parse(torrent.Size),
|
Size = long.Parse(torrent.Size),
|
||||||
DownloadUrl = GetDownloadUrl(id),
|
DownloadUrl = GetDownloadUrl(id),
|
||||||
@@ -96,6 +97,36 @@ namespace NzbDrone.Core.Indexers.Gazelle
|
|||||||
torrentInfos.Add(release);
|
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
|
// order by date
|
||||||
@@ -110,9 +141,7 @@ namespace NzbDrone.Core.Indexers.Gazelle
|
|||||||
var url = new HttpUri(_baseUrl)
|
var url = new HttpUri(_baseUrl)
|
||||||
.CombinePath("/torrents.php")
|
.CombinePath("/torrents.php")
|
||||||
.AddQueryParam("action", "download")
|
.AddQueryParam("action", "download")
|
||||||
.AddQueryParam("id", torrentId)
|
.AddQueryParam("id", torrentId);
|
||||||
.AddQueryParam("authkey", _settings.AuthKey)
|
|
||||||
.AddQueryParam("torrent_pass", _settings.PassKey);
|
|
||||||
|
|
||||||
return url.FullUri;
|
return url.FullUri;
|
||||||
}
|
}
|
||||||
|
@@ -20,7 +20,6 @@ namespace NzbDrone.Core.Indexers.Gazelle
|
|||||||
public IndexerCapabilities Capabilities { get; set; }
|
public IndexerCapabilities Capabilities { get; set; }
|
||||||
public Logger Logger { get; set; }
|
public Logger Logger { get; set; }
|
||||||
|
|
||||||
protected virtual string LoginUrl => BaseUrl + "login.php";
|
|
||||||
protected virtual string APIUrl => BaseUrl + "ajax.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 DownloadUrl => BaseUrl + "torrents.php?action=download&usetoken=" + (Settings.UseFreeleechToken ? "1" : "0") + "&id=";
|
||||||
protected virtual string DetailsUrl => BaseUrl + "torrents.php?torrentid=";
|
protected virtual string DetailsUrl => BaseUrl + "torrents.php?torrentid=";
|
||||||
@@ -40,10 +39,6 @@ namespace NzbDrone.Core.Indexers.Gazelle
|
|||||||
|
|
||||||
private IEnumerable<IndexerRequest> GetRequest(string searchParameters)
|
private IEnumerable<IndexerRequest> GetRequest(string searchParameters)
|
||||||
{
|
{
|
||||||
AuthCookieCache = GetCookies();
|
|
||||||
|
|
||||||
Authenticate();
|
|
||||||
|
|
||||||
var filter = "";
|
var filter = "";
|
||||||
if (searchParameters == null)
|
if (searchParameters == null)
|
||||||
{
|
{
|
||||||
@@ -51,91 +46,17 @@ namespace NzbDrone.Core.Indexers.Gazelle
|
|||||||
|
|
||||||
var request =
|
var request =
|
||||||
new IndexerRequest(
|
new IndexerRequest(
|
||||||
$"{APIUrl}?action=browse{searchParameters}{filter}",
|
$"{APIUrl}?{searchParameters}{filter}",
|
||||||
HttpAccept.Json);
|
HttpAccept.Json);
|
||||||
|
|
||||||
var cookies = AuthCookieCache;
|
|
||||||
foreach (var cookie in cookies)
|
|
||||||
{
|
|
||||||
request.HttpRequest.Cookies[cookie.Key] = cookie.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
yield return request;
|
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)
|
private string GetBasicSearchParameters(string searchTerm, int[] categories)
|
||||||
{
|
{
|
||||||
var searchString = GetSearchTerm(searchTerm);
|
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))
|
if (!string.IsNullOrWhiteSpace(searchString))
|
||||||
{
|
{
|
||||||
|
@@ -22,6 +22,7 @@ namespace NzbDrone.Core.Indexers
|
|||||||
protected const int MaxNumResultsPerQuery = 1000;
|
protected const int MaxNumResultsPerQuery = 1000;
|
||||||
|
|
||||||
protected readonly IHttpClient _httpClient;
|
protected readonly IHttpClient _httpClient;
|
||||||
|
public IDictionary<string, string> Cookies { get; set; }
|
||||||
|
|
||||||
public override bool SupportsRss => true;
|
public override bool SupportsRss => true;
|
||||||
public override bool SupportsSearch => true;
|
public override bool SupportsSearch => true;
|
||||||
@@ -111,6 +112,23 @@ namespace NzbDrone.Core.Indexers
|
|||||||
return generator;
|
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)
|
protected virtual IndexerPageableQueryResult FetchReleases(Func<IIndexerRequestGenerator, IndexerPageableRequestChain> pageableRequestChainSelector, bool isRecent = false)
|
||||||
{
|
{
|
||||||
var releases = new List<ReleaseInfo>();
|
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)
|
protected virtual IndexerResponse FetchIndexerResponse(IndexerRequest request)
|
||||||
{
|
{
|
||||||
_logger.Debug("Downloading Feed " + request.HttpRequest.ToString(false));
|
_logger.Debug("Downloading Feed " + request.HttpRequest.ToString(false));
|
||||||
@@ -342,7 +369,17 @@ namespace NzbDrone.Core.Indexers
|
|||||||
request.HttpRequest.RateLimit = RateLimit;
|
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();
|
var stopWatch = Stopwatch.StartNew();
|
||||||
|
|
||||||
@@ -350,6 +387,23 @@ namespace NzbDrone.Core.Indexers
|
|||||||
|
|
||||||
stopWatch.Stop();
|
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);
|
return new IndexerResponse(request, response, stopWatch.ElapsedMilliseconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user