Fix issues with namespaces in xpath

This commit is contained in:
2025-09-21 01:32:55 +02:00
parent 6576d06bc9
commit 94c220fafc
3 changed files with 51 additions and 31 deletions

View File

@@ -1,4 +1,5 @@
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Web;
using API.MangaDownloadClients; using API.MangaDownloadClients;
using API.Schema.MangaContext; using API.Schema.MangaContext;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
@@ -29,7 +30,7 @@ public class MangaDex : MangaConnector
while(offset < total) while(offset < total)
{ {
string requestUrl = string requestUrl =
$"https://api.mangadex.org/manga?limit={Limit}&offset={offset}&title={mangaSearchName}" + $"https://api.mangadex.org/manga?limit={Limit}&offset={offset}&title={HttpUtility.UrlEncode(mangaSearchName)}" +
$"&contentRating%5B%5D=safe&contentRating%5B%5D=suggestive&contentRating%5B%5D=erotica" + $"&contentRating%5B%5D=safe&contentRating%5B%5D=suggestive&contentRating%5B%5D=erotica" +
$"&includes%5B%5D=manga&includes%5B%5D=cover_art&includes%5B%5D=author&includes%5B%5D=artist&includes%5B%5D=tag'"; $"&includes%5B%5D=manga&includes%5B%5D=cover_art&includes%5B%5D=author&includes%5B%5D=artist&includes%5B%5D=tag'";
offset += Limit; offset += Limit;

View File

@@ -1,5 +1,6 @@
using System.Net; using System.Net;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Web;
using API.MangaDownloadClients; using API.MangaDownloadClients;
using API.Schema.MangaContext; using API.Schema.MangaContext;
using HtmlAgilityPack; using HtmlAgilityPack;
@@ -27,23 +28,20 @@ public class MangaPark : MangaConnector
private (Manga, MangaConnectorId<Manga>)[]? SearchMangaWithDomain(string mangaSearchName, string domain) private (Manga, MangaConnectorId<Manga>)[]? SearchMangaWithDomain(string mangaSearchName, string domain)
{ {
Uri baseUri = new($"https://{domain}/"); Uri baseUri = new($"https://{domain}/");
Uri search = new(baseUri, $"search?word={mangaSearchName}&lang={Tranga.Settings.DownloadLanguage}");
HtmlDocument document = new();
List<(Manga, MangaConnectorId<Manga>)> ret = []; List<(Manga, MangaConnectorId<Manga>)> ret = [];
for (int page = 1;; page++) // break; in loop for (int page = 1;; page++) // break; in loop
{ {
Uri pageSearch = new(search, $"&page={page}"); Uri searchUri = new(baseUri, $"search?word={HttpUtility.UrlEncode(mangaSearchName)}&lang={Tranga.Settings.DownloadLanguage}&page={page}");
if (downloadClient.MakeRequest(pageSearch.ToString(), RequestType.Default) is { statusCode: >= HttpStatusCode.OK and < HttpStatusCode.Ambiguous } result) if (downloadClient.MakeRequest(searchUri.ToString(), RequestType.Default) is { statusCode: >= HttpStatusCode.OK and < HttpStatusCode.Ambiguous } result)
{ {
document.Load(result.result); HtmlDocument document= result.CreateDocument();
// ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract HAP sucks with nullable types // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract HAP sucks with nullable types
if (document.DocumentNode.SelectSingleNode("//button[contains(text(),\"No Data\")]") is not null) // No results found if (document.DocumentNode.SelectSingleNode("//button[contains(text(),\"No Data\")]") is not null) // No results found
break; break;
HtmlNode resultsListNode = document.GetNodeWith("jp_1"); ret.AddRange(document.GetNodesWith("q4_9").Select(n => ParseSingleMangaFromSearchResultsList(baseUri, n)));
ret.AddRange(resultsListNode.ChildNodes.Select(n => ParseSingleMangaFromSearchResultsList(baseUri, n)));
}else }else
return null; return null;
} }
@@ -78,16 +76,23 @@ public class MangaPark : MangaConnector
if (downloadClient.MakeRequest(url, RequestType.Default) is if (downloadClient.MakeRequest(url, RequestType.Default) is
{ statusCode: >= HttpStatusCode.OK and < HttpStatusCode.Ambiguous } result) { statusCode: >= HttpStatusCode.OK and < HttpStatusCode.Ambiguous } result)
{ {
HtmlDocument document = new(); HtmlDocument document= result.CreateDocument();
document.Load(result.result);
string name = document.GetNodeWith("2x", "q:id").InnerText; if (document.GetNodeWith("q1_1")?.GetAttributeValue("title", string.Empty) is not { Length: >0 } name)
string description = document.GetNodeWith("0a_9").InnerText; {
Log.Error("Name not found.");
return null;
}
string description = document.GetNodeWith("0a_9")?.InnerText ?? string.Empty;
string coverRelative = document.GetNodeWith("q1_1").GetAttributeValue("src", ""); if (document.GetNodeWith("q1_1")?.GetAttributeValue("src", string.Empty) is not { Length: >0 } coverRelative)
string coverUrl = $"{url.Substring(0, url.IndexOf('/', 9))}{coverRelative}"; {
Log.Error("Cover not found.");
return null;
}
string coverUrl = $"{url[..url.IndexOf('/', 9)]}{coverRelative}";
MangaReleaseStatus releaseStatus = document.GetNodeWith("Yn_5").InnerText.ToLower() switch MangaReleaseStatus releaseStatus = document.GetNodeWith("Yn_5")?.InnerText.ToLower() switch
{ {
"pending" => MangaReleaseStatus.Unreleased, "pending" => MangaReleaseStatus.Unreleased,
"ongoing" => MangaReleaseStatus.Continuing, "ongoing" => MangaReleaseStatus.Continuing,
@@ -97,21 +102,24 @@ public class MangaPark : MangaConnector
_ => MangaReleaseStatus.Unreleased _ => MangaReleaseStatus.Unreleased
}; };
ICollection<Author> authors = document.GetNodeWith("tz_4") ICollection<Author> authors = document.GetNodeWith("tz_4")?
.ChildNodes.Where(n => n.Name == "a") .ChildNodes.Where(n => n.Name == "a")
.Select(n => n.InnerText) .Select(n => n.InnerText)
.Select(t => new Author(t)).ToList(); .Select(t => new Author(t))
.ToList()??[];
ICollection<MangaTag> mangaTags = document.GetNodesWith("kd_0") ICollection<MangaTag> mangaTags = document.GetNodesWith("kd_0")?
.Select(n => n.InnerText) .Select(n => n.InnerText)
.Select(t => new MangaTag(t)).ToList(); .Select(t => new MangaTag(t))
.ToList()??[];
ICollection<Link> links = []; ICollection<Link> links = [];
ICollection<AltTitle> altTitles = document.GetNodeWith("tz_2") ICollection<AltTitle> altTitles = document.GetNodeWith("tz_2")?
.ChildNodes.Where(n => n.InnerText.Length > 1) .ChildNodes.Where(n => n.InnerText.Length > 1)
.Select(n => n.InnerText) .Select(n => n.InnerText)
.Select(t => new AltTitle(string.Empty, t)).ToList(); .Select(t => new AltTitle(string.Empty, t))
.ToList()??[];
Manga m = new (name, description, coverUrl, releaseStatus, authors, mangaTags, links, altTitles); Manga m = new (name, description, coverUrl, releaseStatus, authors, mangaTags, links, altTitles);
MangaConnectorId<Manga> mcId = new(m, this, url.Split('/').Last(), url); MangaConnectorId<Manga> mcId = new(m, this, url.Split('/').Last(), url);
@@ -136,8 +144,7 @@ public class MangaPark : MangaConnector
if (downloadClient.MakeRequest(requestUri.ToString(), RequestType.Default) is if (downloadClient.MakeRequest(requestUri.ToString(), RequestType.Default) is
{ statusCode: >= HttpStatusCode.OK and < HttpStatusCode.Ambiguous } result) { statusCode: >= HttpStatusCode.OK and < HttpStatusCode.Ambiguous } result)
{ {
HtmlDocument document = new(); HtmlDocument document= result.CreateDocument();
document.Load(result.result);
HtmlNodeCollection chapterNodes = document.GetNodesWith("8t_8"); HtmlNodeCollection chapterNodes = document.GetNodesWith("8t_8");
@@ -189,8 +196,7 @@ public class MangaPark : MangaConnector
if (downloadClient.MakeRequest(requestUri.ToString(), RequestType.Default) is if (downloadClient.MakeRequest(requestUri.ToString(), RequestType.Default) is
{ statusCode: >= HttpStatusCode.OK and < HttpStatusCode.Ambiguous } result) { statusCode: >= HttpStatusCode.OK and < HttpStatusCode.Ambiguous } result)
{ {
HtmlDocument document = new(); HtmlDocument document= result.CreateDocument();
document.Load(result.result);
HtmlNodeCollection imageNodes = document.GetNodesWith("8X_2"); HtmlNodeCollection imageNodes = document.GetNodesWith("8X_2");
@@ -200,8 +206,20 @@ public class MangaPark : MangaConnector
} }
} }
internal static class Helper internal static class MangaParkHelper
{ {
internal static HtmlNode GetNodeWith(this HtmlDocument document, string search, string selector = "q:key") => document.DocumentNode.SelectSingleNode($"//*[@${selector}=${search}]"); internal static HtmlDocument CreateDocument(this RequestResult result)
internal static HtmlNodeCollection GetNodesWith(this HtmlDocument document, string search, string selector = "q:key") => document.DocumentNode.SelectNodes($"//*[@${selector}=${search}]"); {
HtmlDocument document = new();
StreamReader sr = new (result.result);
string htmlStr = sr.ReadToEnd().Replace("q:key", "qkey");
document.LoadHtml(htmlStr);
return document;
}
internal static HtmlNode? GetNodeWith(this HtmlDocument document, string search) => document.DocumentNode.SelectSingleNode("/html").GetNodeWith(search);
internal static HtmlNode? GetNodeWith(this HtmlNode node, string search) => node.SelectNodes($"{node.XPath}//*[@qkey='{search}']").FirstOrDefault();
internal static HtmlNodeCollection GetNodesWith(this HtmlDocument document, string search) => document.DocumentNode.SelectSingleNode("/html ").GetNodesWith(search);
internal static HtmlNodeCollection GetNodesWith(this HtmlNode node, string search) => node.SelectNodes($"{node.XPath}//*[@qkey='{search}']");
} }

View File

@@ -1,4 +1,5 @@
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Web;
using API.MangaDownloadClients; using API.MangaDownloadClients;
using API.Schema.MangaContext; using API.Schema.MangaContext;
using HtmlAgilityPack; using HtmlAgilityPack;
@@ -27,7 +28,7 @@ public sealed class Mangaworld : MangaConnector
public override (Manga, MangaConnectorId<Manga>)[] SearchManga(string mangaSearchName) public override (Manga, MangaConnectorId<Manga>)[] SearchManga(string mangaSearchName)
{ {
Uri baseUri = new ("https://www.mangaworld.cx/"); Uri baseUri = new ("https://www.mangaworld.cx/");
Uri searchUrl = new (baseUri, "archive?keyword=" + Uri.EscapeDataString(mangaSearchName)); Uri searchUrl = new (baseUri, "archive?keyword=" + HttpUtility.UrlEncode(mangaSearchName));
RequestResult res = downloadClient.MakeRequest(searchUrl.ToString(), RequestType.Default); RequestResult res = downloadClient.MakeRequest(searchUrl.ToString(), RequestType.Default);
if ((int)res.statusCode < 200 || (int)res.statusCode >= 300) if ((int)res.statusCode < 200 || (int)res.statusCode >= 300)