mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-12 10:18:27 -04:00
Abstract away cache. 2 implementations: redis and memory
This commit is contained in:
@@ -1,17 +1,15 @@
|
||||
#nullable disable
|
||||
using AngleSharp;
|
||||
using AngleSharp.Html.Dom;
|
||||
using NadekoBot.Modules.Searches.Common;
|
||||
using Newtonsoft.Json;
|
||||
using System.Net.Http.Json;
|
||||
|
||||
namespace NadekoBot.Modules.Searches.Services;
|
||||
|
||||
public class AnimeSearchService : INService
|
||||
{
|
||||
private readonly IDataCache _cache;
|
||||
private readonly IBotCache _cache;
|
||||
private readonly IHttpClientFactory _httpFactory;
|
||||
|
||||
public AnimeSearchService(IDataCache cache, IHttpClientFactory httpFactory)
|
||||
public AnimeSearchService(IBotCache cache, IHttpClientFactory httpFactory)
|
||||
{
|
||||
_cache = cache;
|
||||
_httpFactory = httpFactory;
|
||||
@@ -21,24 +19,25 @@ public class AnimeSearchService : INService
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(query))
|
||||
throw new ArgumentNullException(nameof(query));
|
||||
|
||||
TypedKey<AnimeResult> GetKey(string link)
|
||||
=> new TypedKey<AnimeResult>($"anime2:{link}");
|
||||
|
||||
try
|
||||
{
|
||||
var link = "https://aniapi.nadeko.bot/anime/"
|
||||
+ Uri.EscapeDataString(query.Replace("/", " ", StringComparison.InvariantCulture));
|
||||
var suffix = Uri.EscapeDataString(query.Replace("/", " ", StringComparison.InvariantCulture));
|
||||
var link = $"https://aniapi.nadeko.bot/anime/{suffix}";
|
||||
link = link.ToLowerInvariant();
|
||||
var (ok, data) = await _cache.TryGetAnimeDataAsync(link);
|
||||
if (!ok)
|
||||
var result = await _cache.GetAsync(GetKey(link));
|
||||
if (!result.TryPickT0(out var data, out _))
|
||||
{
|
||||
using (var http = _httpFactory.CreateClient())
|
||||
{
|
||||
data = await http.GetStringAsync(link);
|
||||
}
|
||||
using var http = _httpFactory.CreateClient();
|
||||
data = await http.GetFromJsonAsync<AnimeResult>(link);
|
||||
|
||||
await _cache.SetAnimeDataAsync(link, data);
|
||||
await _cache.AddAsync(GetKey(link), data, expiry: TimeSpan.FromHours(12));
|
||||
}
|
||||
|
||||
|
||||
return JsonConvert.DeserializeObject<AnimeResult>(data);
|
||||
return data;
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -46,95 +45,31 @@ public class AnimeSearchService : INService
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<NovelResult> GetNovelData(string query)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(query))
|
||||
throw new ArgumentNullException(nameof(query));
|
||||
|
||||
query = query.Replace(" ", "-", StringComparison.InvariantCulture);
|
||||
try
|
||||
{
|
||||
var link = "https://www.novelupdates.com/series/"
|
||||
+ Uri.EscapeDataString(query.Replace(" ", "-").Replace("/", " "));
|
||||
link = link.ToLowerInvariant();
|
||||
var (ok, data) = await _cache.TryGetNovelDataAsync(link);
|
||||
if (!ok)
|
||||
{
|
||||
var config = Configuration.Default.WithDefaultLoader();
|
||||
using var document = await BrowsingContext.New(config).OpenAsync(link);
|
||||
var imageElem = document.QuerySelector("div.seriesimg > img");
|
||||
if (imageElem is null)
|
||||
return null;
|
||||
var imageUrl = ((IHtmlImageElement)imageElem).Source;
|
||||
|
||||
var descElem = document.QuerySelector("div#editdescription > p");
|
||||
var desc = descElem.InnerHtml;
|
||||
|
||||
var genres = document.QuerySelector("div#seriesgenre")
|
||||
.Children.Select(x => x as IHtmlAnchorElement)
|
||||
.Where(x => x is not null)
|
||||
.Select(x => $"[{x.InnerHtml}]({x.Href})")
|
||||
.ToArray();
|
||||
|
||||
var authors = document.QuerySelector("div#showauthors")
|
||||
.Children.Select(x => x as IHtmlAnchorElement)
|
||||
.Where(x => x is not null)
|
||||
.Select(x => $"[{x.InnerHtml}]({x.Href})")
|
||||
.ToArray();
|
||||
|
||||
var score = ((IHtmlSpanElement)document.QuerySelector("h5.seriesother > span.uvotes")).InnerHtml;
|
||||
|
||||
var status = document.QuerySelector("div#editstatus").InnerHtml;
|
||||
var title = document.QuerySelector("div.w-blog-content > div.seriestitlenu").InnerHtml;
|
||||
|
||||
var obj = new NovelResult
|
||||
{
|
||||
Description = desc,
|
||||
Authors = authors,
|
||||
Genres = genres,
|
||||
ImageUrl = imageUrl,
|
||||
Link = link,
|
||||
Score = score,
|
||||
Status = status,
|
||||
Title = title
|
||||
};
|
||||
|
||||
await _cache.SetNovelDataAsync(link, JsonConvert.SerializeObject(obj));
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
return JsonConvert.DeserializeObject<NovelResult>(data);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Error getting novel data");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<MangaResult> GetMangaData(string query)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(query))
|
||||
throw new ArgumentNullException(nameof(query));
|
||||
|
||||
TypedKey<MangaResult> GetKey(string link)
|
||||
=> new TypedKey<MangaResult>($"manga2:{link}");
|
||||
|
||||
try
|
||||
{
|
||||
var link = "https://aniapi.nadeko.bot/manga/"
|
||||
+ Uri.EscapeDataString(query.Replace("/", " ", StringComparison.InvariantCulture));
|
||||
link = link.ToLowerInvariant();
|
||||
var (ok, data) = await _cache.TryGetAnimeDataAsync(link);
|
||||
if (!ok)
|
||||
|
||||
var result = await _cache.GetAsync(GetKey(link));
|
||||
if (!result.TryPickT0(out var data, out _))
|
||||
{
|
||||
using (var http = _httpFactory.CreateClient())
|
||||
{
|
||||
data = await http.GetStringAsync(link);
|
||||
}
|
||||
using var http = _httpFactory.CreateClient();
|
||||
data = await http.GetFromJsonAsync<MangaResult>(link);
|
||||
|
||||
await _cache.SetAnimeDataAsync(link, data);
|
||||
await _cache.AddAsync(GetKey(link), data, expiry: TimeSpan.FromHours(3));
|
||||
}
|
||||
|
||||
|
||||
return JsonConvert.DeserializeObject<MangaResult>(data);
|
||||
return data;
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
Reference in New Issue
Block a user