diff --git a/src/Jackett.Common/Indexers/Abstract/GazelleTracker.cs b/src/Jackett.Common/Indexers/Abstract/GazelleTracker.cs
index eac06866d..f0b245827 100644
--- a/src/Jackett.Common/Indexers/Abstract/GazelleTracker.cs
+++ b/src/Jackett.Common/Indexers/Abstract/GazelleTracker.cs
@@ -9,7 +9,7 @@ using System.Text;
using System.Threading.Tasks;
using AngleSharp.Html.Parser;
using Jackett.Common.Models;
-using Jackett.Common.Models.IndexerConfig.Bespoke;
+using Jackett.Common.Models.IndexerConfig;
using Jackett.Common.Services.Interfaces;
using Jackett.Common.Utils;
using Jackett.Common.Utils.Clients;
@@ -22,24 +22,26 @@ namespace Jackett.Common.Indexers.Abstract
[ExcludeFromCodeCoverage]
public abstract class GazelleTracker : BaseWebIndexer
{
- protected virtual string LoginUrl => SiteLink + "login.php";
- protected virtual string APIUrl => SiteLink + "ajax.php";
- protected virtual string DownloadUrl => SiteLink + "torrents.php?action=download&usetoken=" + (useTokens ? "1" : "0") + "&id=";
- protected virtual string DetailsUrl => SiteLink + "torrents.php?torrentid=";
-
- protected bool useTokens;
+ protected string LoginUrl => SiteLink + "login.php";
+ protected string APIUrl => SiteLink + "ajax.php";
+ protected string DownloadUrl => SiteLink + "torrents.php?action=download&usetoken=" + (useTokens ? "1" : "0") + "&id=";
+ protected string DetailsUrl => SiteLink + "torrents.php?torrentid=";
+ protected bool supportsFreeleechTokens;
+ protected bool imdbInTags;
+ protected bool supportsCategories = true; // set to false if the tracker doesn't include the categories in the API search results
+ protected bool useTokens = false;
protected string cookie = "";
- private readonly bool imdbInTags;
- private readonly bool useApiKey;
-
- private new ConfigurationDataGazelleTracker configData => (ConfigurationDataGazelleTracker)base.configData;
+ private new ConfigurationDataBasicLogin configData
+ {
+ get => (ConfigurationDataBasicLogin)base.configData;
+ set => base.configData = value;
+ }
protected GazelleTracker(string link, string id, string name, string description,
IIndexerConfigurationService configService, WebClient client, Logger logger,
IProtectionService p, TorznabCapabilities caps, bool supportsFreeleechTokens,
- bool imdbInTags = false, bool has2Fa = false, bool useApiKey = false,
- string instructionMessageOptional = null)
+ bool imdbInTags = false, bool has2Fa = false)
: base(id: id,
name: name,
description: description,
@@ -49,57 +51,55 @@ namespace Jackett.Common.Indexers.Abstract
client: client,
logger: logger,
p: p,
- configData: new ConfigurationDataGazelleTracker(
- has2Fa, supportsFreeleechTokens, useApiKey, instructionMessageOptional))
+ configData: new ConfigurationDataBasicLogin())
{
Encoding = Encoding.UTF8;
-
+ this.supportsFreeleechTokens = supportsFreeleechTokens;
this.imdbInTags = imdbInTags;
- this.useApiKey = useApiKey;
+
+ if (has2Fa)
+ {
+ var cookieHint = new ConfigurationData.DisplayItem(
+ "
- (use this only if 2FA is enabled for your account)
- Login to this tracker with your browser
- Open the DevTools panel by pressing F12
- Select the Network tab
- Click on the Doc button
- Refresh the page by pressing F5
- Select the Headers tab
- Find 'cookie:' in the Request Headers section
- Copy & paste the whole cookie string to here.
")
+ {
+ Name = "CookieHint"
+ };
+ configData.AddDynamic("cookieHint", cookieHint);
+ var cookieItem = new ConfigurationData.StringItem { Value = "" };
+ cookieItem.Name = "Cookie";
+ configData.AddDynamic("cookie", cookieItem);
+ }
+
+ if (supportsFreeleechTokens)
+ {
+ var useTokenItem = new ConfigurationData.BoolItem { Value = false };
+ useTokenItem.Name = "Use Freeleech Tokens when available";
+ configData.AddDynamic("usetoken", useTokenItem);
+ }
}
public override void LoadValuesFromJson(JToken jsonConfig, bool useProtectionService = false)
{
base.LoadValuesFromJson(jsonConfig, useProtectionService);
- var cookieItem = configData.CookieItem;
+ var cookieItem = (ConfigurationData.StringItem)configData.GetDynamic("cookie");
if (cookieItem != null)
+ {
cookie = cookieItem.Value;
+ }
- var useTokenItem = configData.UseTokenItem;
+ var useTokenItem = (ConfigurationData.BoolItem)configData.GetDynamic("usetoken");
if (useTokenItem != null)
+ {
useTokens = useTokenItem.Value;
+ }
+
}
public override async Task ApplyConfiguration(JToken configJson)
{
LoadValuesFromJson(configJson);
- if (useApiKey)
- {
- var apiKey = configData.ApiKey;
- if (apiKey?.Value == null)
- throw new Exception("Invalid API Key configured");
- if (apiKey.Value.Length != 41)
- throw new Exception($"Invalid API Key configured: expected length: 41, got {apiKey.Value.Length}");
-
- try
- {
- var results = await PerformQuery(new TorznabQuery());
- if (!results.Any())
- throw new Exception("Found 0 results in the tracker");
-
- IsConfigured = true;
- SaveConfig();
- return IndexerConfigurationStatus.Completed;
- }
- catch (Exception e)
- {
- IsConfigured = false;
- throw new Exception($"Your API Key did not work: {e.Message}");
- }
- }
-
var pairs = new Dictionary {
{ "username", configData.Username.Value },
{ "password", configData.Password.Value },
@@ -114,7 +114,9 @@ namespace Jackett.Common.Indexers.Abstract
{
var results = await PerformQuery(new TorznabQuery());
if (!results.Any())
+ {
throw new Exception("Found 0 results in the tracker");
+ }
IsConfigured = true;
SaveConfig();
@@ -123,7 +125,7 @@ namespace Jackett.Common.Indexers.Abstract
catch (Exception e)
{
IsConfigured = false;
- throw new Exception($"Your cookie did not work: {e.Message}");
+ throw new Exception("Your cookie did not work: " + e.Message);
}
}
@@ -160,6 +162,7 @@ namespace Jackett.Common.Indexers.Abstract
{ "order_way", "desc" }
};
+
if (!string.IsNullOrWhiteSpace(query.ImdbID))
{
if (imdbInTags)
@@ -168,7 +171,9 @@ namespace Jackett.Common.Indexers.Abstract
queryCollection.Add("cataloguenumber", query.ImdbID);
}
else if (!string.IsNullOrWhiteSpace(searchString))
+ {
queryCollection.Add("searchstr", searchString);
+ }
if (query.Artist != null)
queryCollection.Add("artistname", query.Artist);
@@ -182,17 +187,18 @@ namespace Jackett.Common.Indexers.Abstract
if (query.Album != null)
queryCollection.Add("groupname", query.Album);
- foreach (var cat in MapTorznabCapsToTrackers(query))
- queryCollection.Add("filter_cat[" + cat + "]", "1");
+ if (supportsCategories)
+ {
+ foreach (var cat in MapTorznabCapsToTrackers(query))
+ {
+ queryCollection.Add("filter_cat[" + cat + "]", "1");
+ }
+ }
searchUrl += "?" + queryCollection.GetQueryString();
- var apiKey = configData.ApiKey;
- var headers = apiKey != null ? new Dictionary { ["Authorization"] = apiKey.Value } : null;
-
- var response = await RequestWithCookiesAndRetryAsync(searchUrl, headers: headers);
- // we get a redirect in html pages and an error message in json response (api)
- if (response.IsRedirect || (response.ContentString != null && response.ContentString.Contains("\"bad credentials\"")))
+ var response = await RequestWithCookiesAndRetryAsync(searchUrl);
+ if (response.IsRedirect)
{
// re-login
await ApplyConfiguration(null);
@@ -235,11 +241,14 @@ namespace Jackett.Common.Indexers.Abstract
if (imdbInTags)
+ {
release.Imdb = tags
.Select(tag => ParseUtil.GetImdbID((string)tag))
.Where(tag => tag != null).FirstIfSingleOrDefault();
+ }
if (r["torrents"] is JArray)
+ {
foreach (JObject torrent in r["torrents"])
{
var release2 = (ReleaseInfo)release.Clone();
@@ -247,6 +256,7 @@ namespace Jackett.Common.Indexers.Abstract
if (ReleaseInfoPostParse(release2, torrent, r))
releases.Add(release2);
}
+ }
else
{
FillReleaseInfoFromJson(release, r);
@@ -272,7 +282,9 @@ namespace Jackett.Common.Indexers.Abstract
var time = (string)torrent["time"];
if (!string.IsNullOrEmpty(time))
+ {
release.PublishDate = DateTime.ParseExact(time + " +0000", "yyyy-MM-dd HH:mm:ss zzz", CultureInfo.InvariantCulture);
+ }
var flags = new List();
@@ -353,10 +365,14 @@ namespace Jackett.Common.Indexers.Abstract
release.DownloadVolumeFactor = 1;
release.UploadVolumeFactor = 1;
if ((bool)torrent["isFreeleech"])
+ {
release.DownloadVolumeFactor = 0;
+ }
var isPersonalFreeleech = (bool?)torrent["isPersonalFreeleech"];
if (isPersonalFreeleech != null && isPersonalFreeleech == true)
+ {
release.DownloadVolumeFactor = 0;
+ }
if ((bool)torrent["isNeutralLeech"])
{
release.DownloadVolumeFactor = 0;
@@ -366,10 +382,7 @@ namespace Jackett.Common.Indexers.Abstract
public override async Task Download(Uri link)
{
- var apiKey = configData.ApiKey;
- var headers = apiKey != null ? new Dictionary { ["Authorization"] = apiKey.Value } : null;
-
- var content = await base.Download(link, RequestType.GET, headers: headers);
+ var content = await base.Download(link);
// Check if we're out of FL tokens/torrent is to large
// most gazelle trackers will simply return the torrent anyway but e.g. redacted will return an error
@@ -385,7 +398,7 @@ namespace Jackett.Common.Indexers.Abstract
{
// download again with usetoken=0
var requestLinkNew = requestLink.Replace("usetoken=1", "usetoken=0");
- content = await base.Download(new Uri(requestLinkNew), RequestType.GET, headers: headers);
+ content = await base.Download(new Uri(requestLinkNew));
}
}
diff --git a/src/Jackett.Common/Indexers/BaseIndexer.cs b/src/Jackett.Common/Indexers/BaseIndexer.cs
index bbeafcdba..f39932254 100644
--- a/src/Jackett.Common/Indexers/BaseIndexer.cs
+++ b/src/Jackett.Common/Indexers/BaseIndexer.cs
@@ -381,7 +381,7 @@ namespace Jackett.Common.Indexers
return await Download(uncleanLink, RequestType.GET);
}
- protected async Task Download(Uri link, RequestType method, string refererlink = null, Dictionaryheaders = null)
+ protected async Task Download(Uri link, RequestType method, string refererlink = null)
{
// return magnet link
if (link.Scheme == "magnet")
@@ -392,8 +392,11 @@ namespace Jackett.Common.Indexers
.Replace("(", "%28")
.Replace(")", "%29")
.Replace("'", "%27");
- var response = await RequestWithCookiesAndRetryAsync(requestLink, null, method, refererlink, null, headers);
+ var response = await RequestWithCookiesAndRetryAsync(requestLink, null, method, requestLink);
+ // if referer link is provied it will be used
+ if (refererlink != null)
+ response = await RequestWithCookiesAndRetryAsync(requestLink, null, method, refererlink);
if (response.IsRedirect)
{
await FollowIfRedirect(response);
diff --git a/src/Jackett.Common/Indexers/Redacted.cs b/src/Jackett.Common/Indexers/Redacted.cs
index 824ba4aa6..b5f0b2ed0 100644
--- a/src/Jackett.Common/Indexers/Redacted.cs
+++ b/src/Jackett.Common/Indexers/Redacted.cs
@@ -5,16 +5,14 @@ using System.Threading.Tasks;
using Jackett.Common.Indexers.Abstract;
using Jackett.Common.Models;
using Jackett.Common.Services.Interfaces;
+using Jackett.Common.Utils.Clients;
using NLog;
-using WebClient = Jackett.Common.Utils.Clients.WebClient;
namespace Jackett.Common.Indexers
{
[ExcludeFromCodeCoverage]
public class Redacted : GazelleTracker
{
- protected override string DownloadUrl => SiteLink + "ajax.php?action=download&usetoken=" + (useTokens ? "1" : "0") + "&id=";
-
public Redacted(IIndexerConfigurationService configService, WebClient wc, Logger l, IProtectionService ps)
: base(id: "redacted",
name: "Redacted",
@@ -29,10 +27,7 @@ namespace Jackett.Common.Indexers
logger: l,
p: ps,
supportsFreeleechTokens: true,
- has2Fa: false,
- useApiKey: true,
- instructionMessageOptional: "- Go to Redacted's site and open your account settings.
- Go to Access Settings tab and copy the API Key.
- Ensure that you've checked Confirm API Key.
- Finally, click Save Profile.
"
- )
+ has2Fa: true)
{
Language = "en-us";
Type = "private";
@@ -53,6 +48,5 @@ namespace Jackett.Common.Indexers
results = results.Where(release => query.MatchQueryStringAND(release.Title));
return results;
}
-
}
}
diff --git a/src/Jackett.Common/Models/IndexerConfig/Bespoke/ConfigurationDataGazelleTracker.cs b/src/Jackett.Common/Models/IndexerConfig/Bespoke/ConfigurationDataGazelleTracker.cs
deleted file mode 100644
index 99e7b8cba..000000000
--- a/src/Jackett.Common/Models/IndexerConfig/Bespoke/ConfigurationDataGazelleTracker.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-namespace Jackett.Common.Models.IndexerConfig.Bespoke
-{
- public class ConfigurationDataGazelleTracker : ConfigurationData
- {
- public StringItem Username { get; private set; }
- public StringItem Password { get; private set; }
- public StringItem ApiKey { get; private set; }
- public DisplayItem CookieHint { get; private set; }
- public StringItem CookieItem { get; private set; }
- public BoolItem UseTokenItem { get; private set; }
- public DisplayItem Instructions { get; private set; }
-
- public ConfigurationDataGazelleTracker(bool has2Fa = false, bool supportsFreeleechToken = false,
- bool useApiKey = false, string instructionMessageOptional = null)
- {
- if (useApiKey)
- ApiKey = new StringItem { Name = "APIKey" };
- else
- {
- Username = new StringItem { Name = "Username" };
- Password = new StringItem { Name = "Password" };
- }
-
- if (has2Fa)
- {
- CookieHint = new DisplayItem(
- @"Use the Cookie field only if 2FA is enabled for your account, let it empty otherwise.
-- Login to this tracker with your browser
-
- Open the DevTools panel by pressing F12
-
- Select the Network tab
-
- Click on the Doc button
-
- Refresh the page by pressing F5
-
- Select the Headers tab
-
- Find 'cookie:' in the Request Headers section
-
- Copy & paste the whole cookie string to here.
")
- {
- Name = "CookieHint"
- };
- CookieItem = new StringItem { Name = "Cookie", Value = "" };
- }
-
- if (supportsFreeleechToken)
- UseTokenItem = new BoolItem { Name = "Use Freeleech Tokens when Available", Value = false };
-
- Instructions = new DisplayItem(instructionMessageOptional) { Name = "" };
- }
-
- }
-}
diff --git a/src/Jackett.Common/Models/IndexerConfig/ConfigurationData.cs b/src/Jackett.Common/Models/IndexerConfig/ConfigurationData.cs
index d999fe30b..db6583c6c 100644
--- a/src/Jackett.Common/Models/IndexerConfig/ConfigurationData.cs
+++ b/src/Jackett.Common/Models/IndexerConfig/ConfigurationData.cs
@@ -169,7 +169,6 @@ namespace Jackett.Common.Models.IndexerConfig
.GetProperties()
.Where(p => p.CanRead)
.Where(p => p.PropertyType.IsSubclassOf(typeof(Item)))
- .Where(p => p.GetValue(this) != null)
.Select(p => (Item)p.GetValue(this)).ToList();
// remove/insert Site Link manualy to make sure it shows up first