mirror of
https://github.com/Jackett/Jackett.git
synced 2025-09-17 17:34:09 +02:00
animebytes: add search by year and rate limit 1req/10s (#14224)
This commit is contained in:
@@ -8,6 +8,7 @@ using System.Linq;
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Jackett.Common.Extensions;
|
||||||
using Jackett.Common.Models;
|
using Jackett.Common.Models;
|
||||||
using Jackett.Common.Models.IndexerConfig.Bespoke;
|
using Jackett.Common.Models.IndexerConfig.Bespoke;
|
||||||
using Jackett.Common.Services.Interfaces;
|
using Jackett.Common.Services.Interfaces;
|
||||||
@@ -40,6 +41,8 @@ namespace Jackett.Common.Indexers
|
|||||||
private bool AddFileNameTitles => ConfigData.AddFileNameTitles.Value;
|
private bool AddFileNameTitles => ConfigData.AddFileNameTitles.Value;
|
||||||
private bool FilterSeasonEpisode => ConfigData.FilterSeasonEpisode.Value;
|
private bool FilterSeasonEpisode => ConfigData.FilterSeasonEpisode.Value;
|
||||||
|
|
||||||
|
private static Regex YearRegex => new Regex(@"\b((?:19|20)\d{2})$", RegexOptions.Compiled);
|
||||||
|
|
||||||
private ConfigurationDataAnimeBytes ConfigData => (ConfigurationDataAnimeBytes)configData;
|
private ConfigurationDataAnimeBytes ConfigData => (ConfigurationDataAnimeBytes)configData;
|
||||||
|
|
||||||
public AnimeBytes(IIndexerConfigurationService configService, WebClient client, Logger l,
|
public AnimeBytes(IIndexerConfigurationService configService, WebClient client, Logger l,
|
||||||
@@ -51,7 +54,10 @@ namespace Jackett.Common.Indexers
|
|||||||
cacheService: cs,
|
cacheService: cs,
|
||||||
configData: new ConfigurationDataAnimeBytes("Note: Go to AnimeBytes site and open your account settings. Go to 'Account' tab, move cursor over black part near 'Passkey' and copy its value. Your username is case sensitive."))
|
configData: new ConfigurationDataAnimeBytes("Note: Go to AnimeBytes site and open your account settings. Go to 'Account' tab, move cursor over black part near 'Passkey' and copy its value. Your username is case sensitive."))
|
||||||
{
|
{
|
||||||
webclient.EmulateBrowser = false; // Animebytes doesn't like fake user agents (issue #1535)
|
// Animebytes doesn't like fake user agents (issue #1535)
|
||||||
|
webclient.EmulateBrowser = false;
|
||||||
|
// requestDelay for API Limit (1 request per 10 seconds)
|
||||||
|
webclient.requestDelay = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
private TorznabCapabilities SetCapabilities()
|
private TorznabCapabilities SetCapabilities()
|
||||||
@@ -113,27 +119,45 @@ namespace Jackett.Common.Indexers
|
|||||||
return IndexerConfigurationStatus.Completed;
|
return IndexerConfigurationStatus.Completed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
|
||||||
|
{
|
||||||
|
var releases = new List<ReleaseInfo>();
|
||||||
|
|
||||||
|
releases.AddRange(await GetResults(query, "anime", StripEpisodeNumber(query.SanitizedSearchTerm.Trim())));
|
||||||
|
|
||||||
|
if (ContainsMusicCategories(query.Categories))
|
||||||
|
releases.AddRange(await GetResults(query, "music", query.SanitizedSearchTerm.Trim()));
|
||||||
|
|
||||||
|
return releases
|
||||||
|
.OrderByDescending(o => o.PublishDate)
|
||||||
|
.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
private string StripEpisodeNumber(string term)
|
private string StripEpisodeNumber(string term)
|
||||||
{
|
{
|
||||||
// Tracer does not support searching with episode number so strip it if we have one
|
// Tracer does not support searching with episode number so strip it if we have one
|
||||||
term = Regex.Replace(term, @"\W(\dx)?\d?\d$", string.Empty);
|
term = Regex.Replace(term, @"\W(\dx)?\d?\d$", string.Empty);
|
||||||
term = Regex.Replace(term, @"\W(S\d\d?E)?\d?\d$", string.Empty);
|
term = Regex.Replace(term, @"\W(S\d\d?E)?\d?\d$", string.Empty);
|
||||||
term = Regex.Replace(term, @"\W\d+$", string.Empty);
|
term = Regex.Replace(term, @"\W\d+$", string.Empty);
|
||||||
return term;
|
|
||||||
|
return term.Trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
|
private static int? ParseYearFromSearchTerm(string term)
|
||||||
{
|
{
|
||||||
var releases = new List<ReleaseInfo>();
|
if (term.IsNullOrWhiteSpace())
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (ContainsMusicCategories(query.Categories))
|
var yearMatch = YearRegex.Match(term);
|
||||||
releases.AddRange(await GetResults(query, "music", query.SanitizedSearchTerm));
|
|
||||||
|
|
||||||
releases.AddRange(
|
if (!yearMatch.Success)
|
||||||
await GetResults(query, "anime", StripEpisodeNumber(query.SanitizedSearchTerm))
|
{
|
||||||
);
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return releases.ToArray();
|
return ParseUtil.CoerceInt(yearMatch.Groups[1].Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool ContainsMusicCategories(int[] categories)
|
private bool ContainsMusicCategories(int[] categories)
|
||||||
@@ -154,20 +178,35 @@ namespace Jackett.Common.Indexers
|
|||||||
{
|
{
|
||||||
var releases = new List<ReleaseInfo>();
|
var releases = new List<ReleaseInfo>();
|
||||||
|
|
||||||
var queryCollection = new NameValueCollection
|
var parameters = new NameValueCollection
|
||||||
{
|
{
|
||||||
{ "username", ConfigData.Username.Value },
|
{ "username", ConfigData.Username.Value },
|
||||||
{ "torrent_pass", ConfigData.Passkey.Value },
|
{ "torrent_pass", ConfigData.Passkey.Value },
|
||||||
|
{ "sort", "grouptime" },
|
||||||
|
{ "way", "desc" },
|
||||||
{ "type", searchType },
|
{ "type", searchType },
|
||||||
|
{ "limit", searchTerm.IsNotNullOrWhiteSpace() ? "50" : "15" },
|
||||||
{ "searchstr", searchTerm }
|
{ "searchstr", searchTerm }
|
||||||
};
|
};
|
||||||
|
|
||||||
var queryCats = MapTorznabCapsToTrackers(query);
|
if (ConfigData.SearchByYear.Value)
|
||||||
if (queryCats.Count > 0)
|
{
|
||||||
foreach (var cat in queryCats)
|
var searchYear = ParseYearFromSearchTerm(query.SanitizedSearchTerm.Trim());
|
||||||
queryCollection.Add(cat, "1");
|
|
||||||
|
|
||||||
var queryUrl = ScrapeUrl + "?" + queryCollection.GetQueryString();
|
if (searchYear > 0)
|
||||||
|
{
|
||||||
|
parameters.Set("year", searchYear.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var queryCats = MapTorznabCapsToTrackers(query);
|
||||||
|
|
||||||
|
if (queryCats.Any())
|
||||||
|
{
|
||||||
|
queryCats.ForEach(cat => parameters.Set(cat, "1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
var searchUrl = ScrapeUrl + "?" + parameters.GetQueryString();
|
||||||
|
|
||||||
// Check cache first so we don't query the server for each episode when searching for each episode in a series.
|
// Check cache first so we don't query the server for each episode when searching for each episode in a series.
|
||||||
lock (cache)
|
lock (cache)
|
||||||
@@ -175,15 +214,19 @@ namespace Jackett.Common.Indexers
|
|||||||
// Remove old cache items
|
// Remove old cache items
|
||||||
CleanCache();
|
CleanCache();
|
||||||
|
|
||||||
var cachedResult = cache.Where(i => i.Query == queryUrl).FirstOrDefault();
|
var cachedResult = cache.FirstOrDefault(i => i.Query == searchUrl);
|
||||||
|
|
||||||
if (cachedResult != null)
|
if (cachedResult != null)
|
||||||
return cachedResult.Results.Select(s => (ReleaseInfo)s.Clone()).ToArray();
|
{
|
||||||
|
return cachedResult.Results.Select(r => (ReleaseInfo)r.Clone()).ToArray();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the content from the tracker
|
// Get the content from the tracker
|
||||||
var response = await RequestWithCookiesAndRetryAsync(queryUrl);
|
var response = await RequestWithCookiesAndRetryAsync(searchUrl);
|
||||||
if (!response.ContentString.StartsWith("{")) // not JSON => error
|
if (!response.ContentString.StartsWith("{")) // not JSON => error
|
||||||
throw new ExceptionWithConfigData("Unexpected response (not JSON)", ConfigData);
|
throw new ExceptionWithConfigData("Unexpected response (not JSON)", ConfigData);
|
||||||
|
|
||||||
var json = JsonConvert.DeserializeObject<dynamic>(response.ContentString);
|
var json = JsonConvert.DeserializeObject<dynamic>(response.ContentString);
|
||||||
|
|
||||||
// Parse
|
// Parse
|
||||||
@@ -194,8 +237,11 @@ namespace Jackett.Common.Indexers
|
|||||||
|
|
||||||
var matches = (long)json["Matches"];
|
var matches = (long)json["Matches"];
|
||||||
|
|
||||||
if (matches > 0)
|
if (matches == 0)
|
||||||
{
|
{
|
||||||
|
return releases;
|
||||||
|
}
|
||||||
|
|
||||||
var groups = (JArray)json.Groups;
|
var groups = (JArray)json.Groups;
|
||||||
|
|
||||||
foreach (var group in groups)
|
foreach (var group in groups)
|
||||||
@@ -207,7 +253,8 @@ namespace Jackett.Common.Indexers
|
|||||||
var groupName = (string)group["GroupName"];
|
var groupName = (string)group["GroupName"];
|
||||||
var seriesName = (string)group["SeriesName"];
|
var seriesName = (string)group["SeriesName"];
|
||||||
var mainTitle = WebUtility.HtmlDecode((string)group["FullName"]);
|
var mainTitle = WebUtility.HtmlDecode((string)group["FullName"]);
|
||||||
if (seriesName != null)
|
|
||||||
|
if (seriesName.IsNotNullOrWhiteSpace())
|
||||||
mainTitle = seriesName;
|
mainTitle = seriesName;
|
||||||
|
|
||||||
synonyms.Add(mainTitle);
|
synonyms.Add(mainTitle);
|
||||||
@@ -319,9 +366,7 @@ namespace Jackett.Common.Indexers
|
|||||||
{
|
{
|
||||||
if (property.Contains(" PSP "))
|
if (property.Contains(" PSP "))
|
||||||
category = new List<int> { TorznabCatType.ConsolePSP.ID };
|
category = new List<int> { TorznabCatType.ConsolePSP.ID };
|
||||||
if (property.Contains("PSX"))
|
if (property.Contains("PSX") || property.Contains(" NES ") || property.Contains(" Switch "))
|
||||||
category = new List<int> { TorznabCatType.ConsoleOther.ID };
|
|
||||||
if (property.Contains(" NES "))
|
|
||||||
category = new List<int> { TorznabCatType.ConsoleOther.ID };
|
category = new List<int> { TorznabCatType.ConsoleOther.ID };
|
||||||
if (property.Contains(" PC "))
|
if (property.Contains(" PC "))
|
||||||
category = new List<int> { TorznabCatType.PCGames.ID };
|
category = new List<int> { TorznabCatType.PCGames.ID };
|
||||||
@@ -380,6 +425,7 @@ namespace Jackett.Common.Indexers
|
|||||||
$"{releaseGroup}{title} {releaseInfo} {infoString}";
|
$"{releaseGroup}{title} {releaseInfo} {infoString}";
|
||||||
|
|
||||||
var guid = new Uri(details + "&nh=" + StringUtil.Hash(title));
|
var guid = new Uri(details + "&nh=" + StringUtil.Hash(title));
|
||||||
|
|
||||||
var release = new ReleaseInfo
|
var release = new ReleaseInfo
|
||||||
{
|
{
|
||||||
MinimumRatio = 1,
|
MinimumRatio = 1,
|
||||||
@@ -436,7 +482,6 @@ namespace Jackett.Common.Indexers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
OnParseError(response.ContentString, ex);
|
OnParseError(response.ContentString, ex);
|
||||||
@@ -445,10 +490,10 @@ namespace Jackett.Common.Indexers
|
|||||||
// Add to the cache
|
// Add to the cache
|
||||||
lock (cache)
|
lock (cache)
|
||||||
{
|
{
|
||||||
cache.Add(new CachedQueryResult(queryUrl, releases));
|
cache.Add(new CachedQueryResult(searchUrl, releases));
|
||||||
}
|
}
|
||||||
|
|
||||||
return releases.Select(s => (ReleaseInfo)s.Clone());
|
return releases.Select(r => (ReleaseInfo)r.Clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -5,6 +5,7 @@ namespace Jackett.Common.Models.IndexerConfig.Bespoke
|
|||||||
[ExcludeFromCodeCoverage]
|
[ExcludeFromCodeCoverage]
|
||||||
internal class ConfigurationDataAnimeBytes : ConfigurationDataUserPasskey
|
internal class ConfigurationDataAnimeBytes : ConfigurationDataUserPasskey
|
||||||
{
|
{
|
||||||
|
public BoolConfigurationItem SearchByYear { get; private set; }
|
||||||
public BoolConfigurationItem IncludeRaw { get; private set; }
|
public BoolConfigurationItem IncludeRaw { get; private set; }
|
||||||
//public DisplayItem DateWarning { get; private set; }
|
//public DisplayItem DateWarning { get; private set; }
|
||||||
public BoolConfigurationItem PadEpisode { get; private set; }
|
public BoolConfigurationItem PadEpisode { get; private set; }
|
||||||
@@ -15,8 +16,9 @@ namespace Jackett.Common.Models.IndexerConfig.Bespoke
|
|||||||
public BoolConfigurationItem FilterSeasonEpisode { get; private set; }
|
public BoolConfigurationItem FilterSeasonEpisode { get; private set; }
|
||||||
|
|
||||||
public ConfigurationDataAnimeBytes(string instructionMessageOptional = null)
|
public ConfigurationDataAnimeBytes(string instructionMessageOptional = null)
|
||||||
: base()
|
: base(instructionMessageOptional)
|
||||||
{
|
{
|
||||||
|
SearchByYear = new BoolConfigurationItem("Search by year as a different argument in the request") { Value = false };
|
||||||
IncludeRaw = new BoolConfigurationItem("IncludeRaw") { Value = false };
|
IncludeRaw = new BoolConfigurationItem("IncludeRaw") { Value = false };
|
||||||
//DateWarning = new DisplayItem("This tracker does not supply upload dates so they are based off year of release.") { Name = "DateWarning" };
|
//DateWarning = new DisplayItem("This tracker does not supply upload dates so they are based off year of release.") { Name = "DateWarning" };
|
||||||
PadEpisode = new BoolConfigurationItem("Pad episode number for Sonarr compatability") { Value = false };
|
PadEpisode = new BoolConfigurationItem("Pad episode number for Sonarr compatability") { Value = false };
|
||||||
@@ -25,7 +27,6 @@ namespace Jackett.Common.Models.IndexerConfig.Bespoke
|
|||||||
AddAlternativeTitles = new BoolConfigurationItem("Add releases for Alternative Title(s)") { Value = false };
|
AddAlternativeTitles = new BoolConfigurationItem("Add releases for Alternative Title(s)") { Value = false };
|
||||||
AddFileNameTitles = new BoolConfigurationItem("Add releases based on single filename") { Value = false };
|
AddFileNameTitles = new BoolConfigurationItem("Add releases based on single filename") { Value = false };
|
||||||
FilterSeasonEpisode = new BoolConfigurationItem("Filter results by season/episode") { Value = false };
|
FilterSeasonEpisode = new BoolConfigurationItem("Filter results by season/episode") { Value = false };
|
||||||
Instructions = new DisplayInfoConfigurationItem("", instructionMessageOptional);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user