-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #283 from C9Glax/cuttingedge-merge-candiate
AsuraToon merge
- Loading branch information
Showing
6 changed files
with
217 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,208 @@ | ||
using System.Net; | ||
using System.Text.RegularExpressions; | ||
using HtmlAgilityPack; | ||
using Tranga.Jobs; | ||
|
||
namespace Tranga.MangaConnectors; | ||
|
||
public class AsuraToon : MangaConnector | ||
{ | ||
|
||
public AsuraToon(GlobalBase clone) : base(clone, "AsuraToon", ["en"]) | ||
{ | ||
this.downloadClient = new HttpDownloadClient(clone); | ||
} | ||
|
||
public override Manga[] GetManga(string publicationTitle = "") | ||
{ | ||
Log($"Searching Publications. Term=\"{publicationTitle}\""); | ||
string sanitizedTitle = string.Join(' ', Regex.Matches(publicationTitle, "[A-z]*").Where(m => m.Value.Length > 0)).ToLower(); | ||
string requestUrl = $"https://asuracomic.net/series?name={sanitizedTitle}"; | ||
RequestResult requestResult = | ||
downloadClient.MakeRequest(requestUrl, RequestType.Default); | ||
if ((int)requestResult.statusCode < 200 || (int)requestResult.statusCode >= 300) | ||
return Array.Empty<Manga>(); | ||
|
||
if (requestResult.htmlDocument is null) | ||
{ | ||
Log($"Failed to retrieve site"); | ||
return Array.Empty<Manga>(); | ||
} | ||
|
||
Manga[] publications = ParsePublicationsFromHtml(requestResult.htmlDocument); | ||
Log($"Retrieved {publications.Length} publications. Term=\"{publicationTitle}\""); | ||
return publications; | ||
} | ||
|
||
public override Manga? GetMangaFromId(string publicationId) | ||
{ | ||
return GetMangaFromUrl($"https://asuracomic.net/series/{publicationId}"); | ||
} | ||
|
||
public override Manga? GetMangaFromUrl(string url) | ||
{ | ||
RequestResult requestResult = downloadClient.MakeRequest(url, RequestType.MangaInfo); | ||
if ((int)requestResult.statusCode < 200 || (int)requestResult.statusCode >= 300) | ||
return null; | ||
if (requestResult.htmlDocument is null) | ||
{ | ||
Log($"Failed to retrieve site"); | ||
return null; | ||
} | ||
return ParseSinglePublicationFromHtml(requestResult.htmlDocument, url.Split('/')[^1], url); | ||
} | ||
|
||
private Manga[] ParsePublicationsFromHtml(HtmlDocument document) | ||
{ | ||
HtmlNodeCollection mangaList = document.DocumentNode.SelectNodes("//a[starts-with(@href,'series')]"); | ||
if (mangaList.Count < 1) | ||
return Array.Empty<Manga>(); | ||
|
||
IEnumerable<string> urls = mangaList.Select(a => $"https://asuracomic.net/{a.GetAttributeValue("href", "")}"); | ||
|
||
List<Manga> ret = new(); | ||
foreach (string url in urls) | ||
{ | ||
Manga? manga = GetMangaFromUrl(url); | ||
if (manga is not null) | ||
ret.Add((Manga)manga); | ||
} | ||
|
||
return ret.ToArray(); | ||
} | ||
|
||
private Manga ParseSinglePublicationFromHtml(HtmlDocument document, string publicationId, string websiteUrl) | ||
{ | ||
string? originalLanguage = null; | ||
Dictionary<string, string> altTitles = new(), links = new(); | ||
|
||
HtmlNodeCollection genreNodes = document.DocumentNode.SelectNodes("//h3[text()='Genres']/../div/button"); | ||
string[] tags = genreNodes.Select(b => b.InnerText).ToArray(); | ||
|
||
HtmlNode statusNode = document.DocumentNode.SelectSingleNode("//h3[text()='Status']/../h3[2]"); | ||
Manga.ReleaseStatusByte releaseStatus = statusNode.InnerText.ToLower() switch | ||
{ | ||
"ongoing" => Manga.ReleaseStatusByte.Continuing, | ||
"hiatus" => Manga.ReleaseStatusByte.OnHiatus, | ||
"completed" => Manga.ReleaseStatusByte.Completed, | ||
"dropped" => Manga.ReleaseStatusByte.Cancelled, | ||
"season end" => Manga.ReleaseStatusByte.Continuing, | ||
"coming soon" => Manga.ReleaseStatusByte.Unreleased, | ||
_ => Manga.ReleaseStatusByte.Unreleased | ||
}; | ||
|
||
HtmlNode coverNode = | ||
document.DocumentNode.SelectSingleNode("//img[@alt='poster']"); | ||
string coverUrl = coverNode.GetAttributeValue("src", ""); | ||
string coverFileNameInCache = SaveCoverImageToCache(coverUrl, publicationId, RequestType.MangaCover); | ||
|
||
HtmlNode titleNode = | ||
document.DocumentNode.SelectSingleNode("//title"); | ||
string sortName = Regex.Match(titleNode.InnerText, @"(.*) - Asura Scans").Groups[1].Value; | ||
|
||
HtmlNode descriptionNode = | ||
document.DocumentNode.SelectSingleNode("//h3[starts-with(text(),'Synopsis')]/../span"); | ||
string description = descriptionNode.InnerText; | ||
|
||
HtmlNodeCollection authorNodes = document.DocumentNode.SelectNodes("//h3[text()='Author']/../h3[not(text()='Author' or text()='_')]"); | ||
HtmlNodeCollection artistNodes = document.DocumentNode.SelectNodes("//h3[text()='Artist']/../h3[not(text()='Author' or text()='_')]"); | ||
List<string> authors = authorNodes.Select(a => a.InnerText).Concat(artistNodes.Select(a => a.InnerText)).ToList(); | ||
|
||
HtmlNode? firstChapterNode = document.DocumentNode.SelectSingleNode("//a[contains(@href, 'chapter/1')]/../following-sibling::h3"); | ||
int? year = int.Parse(firstChapterNode?.InnerText.Split(' ')[^1] ?? "2000"); | ||
|
||
Manga manga = new (sortName, authors, description, altTitles, tags, coverUrl, coverFileNameInCache, links, | ||
year, originalLanguage, publicationId, releaseStatus, websiteUrl); | ||
AddMangaToCache(manga); | ||
return manga; | ||
} | ||
|
||
public override Chapter[] GetChapters(Manga manga, string language="en") | ||
{ | ||
Log($"Getting chapters {manga}"); | ||
string requestUrl = $"https://asuracomic.net/series/{manga.publicationId}"; | ||
// Leaving this in for verification if the page exists | ||
RequestResult requestResult = | ||
downloadClient.MakeRequest(requestUrl, RequestType.Default); | ||
if ((int)requestResult.statusCode < 200 || (int)requestResult.statusCode >= 300) | ||
return Array.Empty<Chapter>(); | ||
|
||
//Return Chapters ordered by Chapter-Number | ||
List<Chapter> chapters = ParseChaptersFromHtml(manga, requestUrl); | ||
Log($"Got {chapters.Count} chapters. {manga}"); | ||
return chapters.Order().ToArray(); | ||
} | ||
|
||
private List<Chapter> ParseChaptersFromHtml(Manga manga, string mangaUrl) | ||
{ | ||
RequestResult result = downloadClient.MakeRequest(mangaUrl, RequestType.Default); | ||
if ((int)result.statusCode < 200 || (int)result.statusCode >= 300 || result.htmlDocument is null) | ||
{ | ||
Log("Failed to load site"); | ||
return new List<Chapter>(); | ||
} | ||
|
||
List<Chapter> ret = new(); | ||
|
||
HtmlNodeCollection chapterURLNodes = result.htmlDocument.DocumentNode.SelectNodes("//a[contains(@href, '/chapter/')]"); | ||
Regex infoRex = new(@"Chapter ([0-9]+)(.*)?"); | ||
|
||
foreach (HtmlNode chapterInfo in chapterURLNodes) | ||
{ | ||
string chapterUrl = chapterInfo.GetAttributeValue("href", ""); | ||
|
||
Match match = infoRex.Match(chapterInfo.InnerText); | ||
string chapterNumber = match.Groups[1].Value; | ||
string? chapterName = match.Groups[2].Success && match.Groups[2].Length > 1 ? match.Groups[2].Value : null; | ||
string url = $"https://asuracomic.net/series/{chapterUrl}"; | ||
ret.Add(new Chapter(manga, chapterName, null, chapterNumber, url)); | ||
} | ||
|
||
return ret; | ||
} | ||
|
||
public override HttpStatusCode DownloadChapter(Chapter chapter, ProgressToken? progressToken = null) | ||
{ | ||
if (progressToken?.cancellationRequested ?? false) | ||
{ | ||
progressToken.Cancel(); | ||
return HttpStatusCode.RequestTimeout; | ||
} | ||
|
||
Manga chapterParentManga = chapter.parentManga; | ||
Log($"Retrieving chapter-info {chapter} {chapterParentManga}"); | ||
string requestUrl = chapter.url; | ||
// Leaving this in to check if the page exists | ||
RequestResult requestResult = | ||
downloadClient.MakeRequest(requestUrl, RequestType.Default); | ||
if ((int)requestResult.statusCode < 200 || (int)requestResult.statusCode >= 300) | ||
{ | ||
progressToken?.Cancel(); | ||
return requestResult.statusCode; | ||
} | ||
|
||
string[] imageUrls = ParseImageUrlsFromHtml(requestUrl); | ||
|
||
return DownloadChapterImages(imageUrls, chapter, RequestType.MangaImage, progressToken:progressToken); | ||
} | ||
|
||
private string[] ParseImageUrlsFromHtml(string mangaUrl) | ||
{ | ||
RequestResult requestResult = | ||
downloadClient.MakeRequest(mangaUrl, RequestType.Default); | ||
if ((int)requestResult.statusCode < 200 || (int)requestResult.statusCode >= 300) | ||
{ | ||
return Array.Empty<string>(); | ||
} | ||
if (requestResult.htmlDocument is null) | ||
{ | ||
Log($"Failed to retrieve site"); | ||
return Array.Empty<string>(); | ||
} | ||
|
||
HtmlNodeCollection images = | ||
requestResult.htmlDocument.DocumentNode.SelectNodes("//img[contains(@alt, 'chapter page')]"); | ||
|
||
return images.Select(i => i.GetAttributeValue("src", "")).ToArray(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters