using MangaReader.Core.HttpService; using System.Text; using System.Text.Json; namespace MangaReader.Core.Sources.MangaDex.Api { public class MangaDexClient(IHttpService httpService) : IMangaDexClient { private static readonly JsonSerializerOptions _jsonSerializerOptions; static MangaDexClient() { _jsonSerializerOptions = new() { PropertyNameCaseInsensitive = true }; _jsonSerializerOptions.Converters.Add(new MangaDexResponseConverter()); _jsonSerializerOptions.Converters.Add(new MangaDexEntityConverter()); } private async Task GetAsync(string url, CancellationToken cancellationToken) { string response = await httpService.GetStringAsync(url, cancellationToken); return JsonSerializer.Deserialize(response, _jsonSerializerOptions); } public async Task SearchMangaByTitleAsync(string title, CancellationToken cancellationToken) { string normalizedKeyword = GetNormalizedKeyword(title); return await GetAsync($"https://api.mangadex.org/manga?title={normalizedKeyword}&limit=5", cancellationToken); } public async Task SearchMangaByAuthorAsync(string author, CancellationToken cancellationToken) { string normalizedKeyword = GetNormalizedKeyword(author); return await GetAsync($"https://api.mangadex.org/manga?author={normalizedKeyword}&limit=5", cancellationToken); } public async Task SearchMangaByGroupAsync(string group, CancellationToken cancellationToken) { string normalizedKeyword = GetNormalizedKeyword(group); return await GetAsync($"https://api.mangadex.org/manga?group={normalizedKeyword}&limit=5", cancellationToken); } protected static string GetNormalizedKeyword(string keyword) { return keyword.ToLowerInvariant().Normalize(NormalizationForm.FormD); } public async Task GetMangaAsync(Guid mangaGuid, CancellationToken cancellationToken) { return await GetAsync($"https://api.mangadex.org/manga/{mangaGuid}?includes[]=artist&includes[]=author&includes[]=cover_art", cancellationToken); } public async Task GetFeedAsync(Guid mangaGuid, CancellationToken cancellationToken) { return await GetAsync($"https://api.mangadex.org/manga/{mangaGuid}/feed?translatedLanguage[]=en&limit=96&includes[]=scanlation_group&includes[]=user&order[volume]=desc&order[chapter]=desc&offset=0&contentRating[]=safe&contentRating[]=suggestive&contentRating[]=erotica&contentRating[]=pornographic", cancellationToken); } public async Task GetChapterAsync(Guid chapterGuid, CancellationToken cancellationToken) { string url = $"https://api.mangadex.org/at-home/server/{chapterGuid}?forcePort443=false"; string response = await httpService.GetStringAsync(url, cancellationToken); return JsonSerializer.Deserialize(response, _jsonSerializerOptions); } } }