From 7fae845d1c09374b28ce1b5e2f60bb61a49b7595 Mon Sep 17 00:00:00 2001 From: Bogdan Date: Wed, 29 Nov 2023 07:42:03 +0200 Subject: [PATCH] redacted: add freeload only option (#14867) --- .../Indexers/Abstract/GazelleTracker.cs | 55 +++++++++++++------ src/Jackett.Common/Indexers/Redacted.cs | 14 +++++ .../ConfigurationDataGazelleTracker.cs | 20 ++++++- 3 files changed, 71 insertions(+), 18 deletions(-) diff --git a/src/Jackett.Common/Indexers/Abstract/GazelleTracker.cs b/src/Jackett.Common/Indexers/Abstract/GazelleTracker.cs index ed509f1b4..cd5953ffa 100644 --- a/src/Jackett.Common/Indexers/Abstract/GazelleTracker.cs +++ b/src/Jackett.Common/Indexers/Abstract/GazelleTracker.cs @@ -44,7 +44,7 @@ namespace Jackett.Common.Indexers.Abstract protected readonly bool usePassKey; protected readonly bool useAuthKey; - private new ConfigurationDataGazelleTracker configData + protected new ConfigurationDataGazelleTracker configData { get => (ConfigurationDataGazelleTracker)base.configData; set => base.configData = value; @@ -52,7 +52,7 @@ namespace Jackett.Common.Indexers.Abstract protected GazelleTracker(IIndexerConfigurationService configService, WebClient client, Logger logger, IProtectionService p, ICacheService cs, - bool supportsFreeleechTokens = false, bool supportsFreeleechOnly = false, + bool supportsFreeleechTokens = false, bool supportsFreeleechOnly = false, bool supportsFreeloadOnly = false, bool imdbInTags = false, bool has2Fa = false, bool useApiKey = false, bool usePassKey = false, bool useAuthKey = false, string instructionMessageOptional = null) : base(configService: configService, @@ -60,7 +60,7 @@ namespace Jackett.Common.Indexers.Abstract logger: logger, p: p, cacheService: cs, - configData: new ConfigurationDataGazelleTracker(has2Fa, supportsFreeleechTokens, supportsFreeleechOnly, useApiKey, usePassKey, useAuthKey, instructionMessageOptional)) + configData: new ConfigurationDataGazelleTracker(has2Fa, supportsFreeleechTokens, supportsFreeleechOnly, supportsFreeloadOnly, useApiKey, usePassKey, useAuthKey, instructionMessageOptional)) { this.imdbInTags = imdbInTags; this.useApiKey = useApiKey; @@ -192,60 +192,64 @@ namespace Jackett.Common.Indexers.Abstract if (!string.IsNullOrWhiteSpace(query.Genre)) { - queryCollection.Add("taglist", query.Genre); + queryCollection.Set("taglist", query.Genre); } if (!string.IsNullOrWhiteSpace(query.ImdbID)) { if (imdbInTags) { - queryCollection.Add("taglist", query.ImdbID); + queryCollection.Set("taglist", query.ImdbID); } else { - queryCollection.Add("cataloguenumber", query.ImdbID); + queryCollection.Set("cataloguenumber", query.ImdbID); } } else if (!string.IsNullOrWhiteSpace(searchString)) { - queryCollection.Add("searchstr", searchString); + queryCollection.Set("searchstr", searchString); } if (query.Artist.IsNotNullOrWhiteSpace() && query.Artist != "VA") { - queryCollection.Add("artistname", query.Artist); + queryCollection.Set("artistname", query.Artist); } if (query.Label.IsNotNullOrWhiteSpace()) { - queryCollection.Add("recordlabel", query.Label); + queryCollection.Set("recordlabel", query.Label); } if (query.Year.HasValue) { - queryCollection.Add("year", query.Year.ToString()); + queryCollection.Set("year", query.Year.ToString()); } if (query.Album.IsNotNullOrWhiteSpace()) { - queryCollection.Add("groupname", query.Album); + queryCollection.Set("groupname", query.Album); } foreach (var cat in MapTorznabCapsToTrackers(query)) { - queryCollection.Add("filter_cat[" + cat + "]", "1"); + queryCollection.Set("filter_cat[" + cat + "]", "1"); } if (configData.FreeleechOnly != null && configData.FreeleechOnly.Value) { - queryCollection.Add("freetorrent", "1"); + queryCollection.Set("freetorrent", "1"); + } + else if (configData.FreeloadOnly != null && configData.FreeloadOnly.Value) + { + queryCollection.Set("freetorrent", "4"); } // remove . as not used in titles searchUrl += "?" + queryCollection.GetQueryString().Replace(".", " "); var apiKey = configData.ApiKey; - var headers = apiKey != null ? new Dictionary { [AuthorizationName] = String.Format(AuthorizationFormat, apiKey.Value) } : null; + var headers = apiKey != null ? new Dictionary { [AuthorizationName] = string.Format(AuthorizationFormat, 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) @@ -344,6 +348,11 @@ namespace Jackett.Common.Indexers.Abstract { foreach (JObject torrent in r["torrents"]) { + if (ShouldSkipRelease(torrent)) + { + continue; + } + var release2 = (ReleaseInfo)release.Clone(); FillReleaseInfoFromJson(release2, torrent); if (ReleaseInfoPostParse(release2, torrent, r)) @@ -354,6 +363,11 @@ namespace Jackett.Common.Indexers.Abstract } else { + if (ShouldSkipRelease(r)) + { + continue; + } + FillReleaseInfoFromJson(release, r); if (ReleaseInfoPostParse(release, r, r)) { @@ -373,6 +387,14 @@ namespace Jackett.Common.Indexers.Abstract // hook to add/modify the parsed information, return false to exclude the torrent from the results protected virtual bool ReleaseInfoPostParse(ReleaseInfo release, JObject torrent, JObject result) => true; + protected virtual bool ShouldSkipRelease(JObject torrent) + { + var isFreeleech = bool.TryParse((string)torrent["isFreeleech"], out var freeleech) && freeleech; + + // skip non-freeload results when freeload only is set + return configData.FreeleechOnly != null && configData.FreeleechOnly.Value && !isFreeleech; + } + protected void FillReleaseInfoFromJson(ReleaseInfo release, JObject torrent) { var torrentId = torrent["torrentId"]; @@ -499,8 +521,9 @@ namespace Jackett.Common.Indexers.Abstract release.DownloadVolumeFactor = 0; } - var isFreeload = (bool?)torrent["isFreeload"]; - if ((bool)torrent["isNeutralLeech"] || (isFreeload != null && isFreeload == true)) + var isFreeload = bool.TryParse((string)torrent["isFreeload"], out var freeload) && freeload; + + if ((bool)torrent["isNeutralLeech"] || isFreeload) { release.DownloadVolumeFactor = 0; release.UploadVolumeFactor = 0; diff --git a/src/Jackett.Common/Indexers/Redacted.cs b/src/Jackett.Common/Indexers/Redacted.cs index 168b28055..914e96b1b 100644 --- a/src/Jackett.Common/Indexers/Redacted.cs +++ b/src/Jackett.Common/Indexers/Redacted.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using Jackett.Common.Indexers.Abstract; using Jackett.Common.Models; using Jackett.Common.Services.Interfaces; +using Newtonsoft.Json.Linq; using NLog; using WebClient = Jackett.Common.Utils.Clients.WebClient; @@ -31,6 +32,7 @@ namespace Jackett.Common.Indexers p: ps, cs: cs, supportsFreeleechTokens: true, + supportsFreeloadOnly: true, has2Fa: false, useApiKey: true, instructionMessageOptional: "
  1. Go to Redacted's site and open your account settings.
  2. Go to Access Settings tab and copy the API Key.
  3. Ensure that you've checked Confirm API Key.
  4. Finally, click Save Profile.
" @@ -82,5 +84,17 @@ namespace Jackett.Common.Indexers return releases; } + + protected override bool ShouldSkipRelease(JObject torrent) + { + var isFreeload = bool.TryParse((string)torrent["isFreeload"], out var freeload) && freeload; + + if (configData.FreeloadOnly != null && configData.FreeloadOnly.Value && !isFreeload) + { + return true; + } + + return base.ShouldSkipRelease(torrent); + } } } diff --git a/src/Jackett.Common/Models/IndexerConfig/Bespoke/ConfigurationDataGazelleTracker.cs b/src/Jackett.Common/Models/IndexerConfig/Bespoke/ConfigurationDataGazelleTracker.cs index 042f3dd0d..bbe74b122 100644 --- a/src/Jackett.Common/Models/IndexerConfig/Bespoke/ConfigurationDataGazelleTracker.cs +++ b/src/Jackett.Common/Models/IndexerConfig/Bespoke/ConfigurationDataGazelleTracker.cs @@ -3,7 +3,7 @@ using System.Diagnostics.CodeAnalysis; namespace Jackett.Common.Models.IndexerConfig.Bespoke { [ExcludeFromCodeCoverage] - internal class ConfigurationDataGazelleTracker : ConfigurationData + public class ConfigurationDataGazelleTracker : ConfigurationData { public StringConfigurationItem Username { get; private set; } public PasswordConfigurationItem Password { get; private set; } @@ -14,14 +14,17 @@ namespace Jackett.Common.Models.IndexerConfig.Bespoke public StringConfigurationItem CookieItem { get; private set; } public BoolConfigurationItem UseTokenItem { get; private set; } public BoolConfigurationItem FreeleechOnly { get; private set; } + public BoolConfigurationItem FreeloadOnly { get; private set; } public DisplayInfoConfigurationItem Instructions { get; private set; } - public ConfigurationDataGazelleTracker(bool has2Fa = false, bool supportsFreeleechToken = false, bool supportsFreeleechOnly = false, + public ConfigurationDataGazelleTracker(bool has2Fa = false, bool supportsFreeleechToken = false, bool supportsFreeleechOnly = false, bool supportsFreeloadOnly = false, bool useApiKey = false, bool usePassKey = false, bool useAuthKey = false, string instructionMessageOptional = null) { if (useApiKey) + { ApiKey = new StringConfigurationItem("APIKey"); + } else { Username = new StringConfigurationItem("Username"); @@ -44,16 +47,29 @@ namespace Jackett.Common.Models.IndexerConfig.Bespoke } if (usePassKey) + { PassKey = new StringConfigurationItem("Passkey"); + } if (useAuthKey) + { AuthKey = new StringConfigurationItem("Authkey"); + } if (supportsFreeleechToken) + { UseTokenItem = new BoolConfigurationItem("Use Freeleech Tokens when Available") { Value = false }; + } if (supportsFreeleechOnly) + { FreeleechOnly = new BoolConfigurationItem("Search freeleech only") { Value = false }; + } + + if (supportsFreeloadOnly) + { + FreeloadOnly = new BoolConfigurationItem("Search freeload only") { Value = false }; + } Instructions = new DisplayInfoConfigurationItem("", instructionMessageOptional); }