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