fix ul.direlist
Build Futon with Niadd patch / Build Futon Niadd debug APK (push) Successful in 12m49s
Build Futon with Niadd patch / Build Futon Niadd debug APK (push) Successful in 12m49s
This commit is contained in:
1 file changed
+192
-2
@@ -17,7 +17,10 @@ parser_file = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
if not parser_file.is_file():
|
if not parser_file.is_file():
|
||||||
print(f"ERROR: parser file not found: {parser_file}", file=sys.stderr)
|
print(
|
||||||
|
f"ERROR: parser file not found: {parser_file}",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
@@ -44,6 +47,40 @@ def replace_exact(name: str, old: str, new: str) -> None:
|
|||||||
print(f"[OK] {name}")
|
print(f"[OK] {name}")
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Niadd search pagination:
|
||||||
|
#
|
||||||
|
# NineManga:
|
||||||
|
# ?page=2
|
||||||
|
#
|
||||||
|
# Niadd:
|
||||||
|
# ?page=2.html
|
||||||
|
#
|
||||||
|
replace_exact(
|
||||||
|
"Niadd search pagination",
|
||||||
|
''' append("/search/")
|
||||||
|
append("?page=")
|
||||||
|
append(page.toString())
|
||||||
|
''',
|
||||||
|
''' append("/search/")
|
||||||
|
append("?page=")
|
||||||
|
append(page.toString())
|
||||||
|
if (domain.endsWith("niadd.com")) {
|
||||||
|
append(".html")
|
||||||
|
}
|
||||||
|
''',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Niadd category pagination:
|
||||||
|
#
|
||||||
|
# Page 1:
|
||||||
|
# /category/
|
||||||
|
#
|
||||||
|
# Page 2+:
|
||||||
|
# /category/index_2.html
|
||||||
|
#
|
||||||
replace_exact(
|
replace_exact(
|
||||||
"Niadd category pagination",
|
"Niadd category pagination",
|
||||||
''' } else {
|
''' } else {
|
||||||
@@ -67,6 +104,142 @@ replace_exact(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# NineManga used:
|
||||||
|
#
|
||||||
|
# ul.direlist > li
|
||||||
|
#
|
||||||
|
# Niadd no longer has ul.direlist.
|
||||||
|
#
|
||||||
|
# Instead, discover manga cards through their canonical /manga/ links.
|
||||||
|
#
|
||||||
|
# The same manga can have several links:
|
||||||
|
# - cover
|
||||||
|
# - title
|
||||||
|
# - description
|
||||||
|
#
|
||||||
|
# Therefore links are grouped by absolute manga URL.
|
||||||
|
#
|
||||||
|
replace_exact(
|
||||||
|
"Niadd manga list parser",
|
||||||
|
''' val doc = webClient.httpGet(url).parseHtml()
|
||||||
|
val root = doc.body().selectFirstOrThrow("ul.direlist")
|
||||||
|
val baseHost = root.baseUri().toHttpUrl().host
|
||||||
|
return root.select("li").map { node ->
|
||||||
|
val href = node.selectFirstOrThrow("a").attrAsAbsoluteUrl("href")
|
||||||
|
val relUrl = href.toRelativeUrl(baseHost)
|
||||||
|
val dd = node.selectFirst("dd")
|
||||||
|
Manga(
|
||||||
|
id = generateUid(relUrl),
|
||||||
|
url = relUrl,
|
||||||
|
publicUrl = href,
|
||||||
|
title = dd?.selectFirst("a.bookname")?.text()?.toCamelCase().orEmpty(),
|
||||||
|
altTitles = emptySet(),
|
||||||
|
coverUrl = node.selectFirst("img")?.src(),
|
||||||
|
rating = RATING_UNKNOWN,
|
||||||
|
authors = emptySet(),
|
||||||
|
contentRating = null,
|
||||||
|
tags = emptySet(),
|
||||||
|
state = null,
|
||||||
|
source = source,
|
||||||
|
description = dd?.selectFirst("p")?.html(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
''',
|
||||||
|
''' val doc = webClient.httpGet(url).parseHtml()
|
||||||
|
|
||||||
|
if (domain.endsWith("niadd.com")) {
|
||||||
|
val mangaLinks = doc.select("a[href]").filter { link ->
|
||||||
|
val href = link.attr("href")
|
||||||
|
href.startsWith("/manga/") ||
|
||||||
|
href.startsWith("https://${domain}/manga/")
|
||||||
|
}
|
||||||
|
|
||||||
|
val linksByUrl = mangaLinks.groupBy { link ->
|
||||||
|
link.attrAsAbsoluteUrl("href")
|
||||||
|
}
|
||||||
|
|
||||||
|
return linksByUrl.mapNotNull { (href, links) ->
|
||||||
|
val relUrl = href.toRelativeUrl(domain)
|
||||||
|
|
||||||
|
val texts = links
|
||||||
|
.map { it.text().trim() }
|
||||||
|
.filter { it.isNotEmpty() }
|
||||||
|
.distinct()
|
||||||
|
|
||||||
|
val rawTitle = texts.minByOrNull { it.length }
|
||||||
|
?: return@mapNotNull null
|
||||||
|
|
||||||
|
val description = texts
|
||||||
|
.asSequence()
|
||||||
|
.filter { it != rawTitle }
|
||||||
|
.filter { it.length > rawTitle.length }
|
||||||
|
.maxByOrNull { it.length }
|
||||||
|
?.removePrefix(rawTitle)
|
||||||
|
?.trim()
|
||||||
|
?.takeIf { it.isNotEmpty() }
|
||||||
|
|
||||||
|
val coverUrl = links
|
||||||
|
.asSequence()
|
||||||
|
.mapNotNull { link ->
|
||||||
|
link.selectFirst("img")?.src()
|
||||||
|
?: link.parent()?.selectFirst("img")?.src()
|
||||||
|
?: link.parent()?.parent()?.selectFirst("img")?.src()
|
||||||
|
}
|
||||||
|
.firstOrNull()
|
||||||
|
|
||||||
|
Manga(
|
||||||
|
id = generateUid(relUrl),
|
||||||
|
url = relUrl,
|
||||||
|
publicUrl = href,
|
||||||
|
title = rawTitle.toCamelCase(),
|
||||||
|
altTitles = emptySet(),
|
||||||
|
coverUrl = coverUrl,
|
||||||
|
rating = RATING_UNKNOWN,
|
||||||
|
authors = emptySet(),
|
||||||
|
contentRating = null,
|
||||||
|
tags = emptySet(),
|
||||||
|
state = null,
|
||||||
|
source = source,
|
||||||
|
description = description,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val root = doc.body().selectFirstOrThrow("ul.direlist")
|
||||||
|
val baseHost = root.baseUri().toHttpUrl().host
|
||||||
|
|
||||||
|
return root.select("li").map { node ->
|
||||||
|
val href = node.selectFirstOrThrow("a").attrAsAbsoluteUrl("href")
|
||||||
|
val relUrl = href.toRelativeUrl(baseHost)
|
||||||
|
val dd = node.selectFirst("dd")
|
||||||
|
|
||||||
|
Manga(
|
||||||
|
id = generateUid(relUrl),
|
||||||
|
url = relUrl,
|
||||||
|
publicUrl = href,
|
||||||
|
title = dd?.selectFirst("a.bookname")?.text()?.toCamelCase().orEmpty(),
|
||||||
|
altTitles = emptySet(),
|
||||||
|
coverUrl = node.selectFirst("img")?.src(),
|
||||||
|
rating = RATING_UNKNOWN,
|
||||||
|
authors = emptySet(),
|
||||||
|
contentRating = null,
|
||||||
|
tags = emptySet(),
|
||||||
|
state = null,
|
||||||
|
source = source,
|
||||||
|
description = dd?.selectFirst("p")?.html(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
''',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Russian statuses on Niadd are not consistently cased:
|
||||||
|
#
|
||||||
|
# постоянный
|
||||||
|
# Завершенный
|
||||||
|
#
|
||||||
replace_exact(
|
replace_exact(
|
||||||
"Russian status parsing",
|
"Russian status parsing",
|
||||||
''' //ru
|
''' //ru
|
||||||
@@ -80,6 +253,12 @@ replace_exact(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Activate Russian source and migrate it to Niadd.
|
||||||
|
#
|
||||||
|
# Keep NINEMANGA_RU intentionally unchanged so existing Futon
|
||||||
|
# database/source references remain compatible.
|
||||||
|
#
|
||||||
replace_exact(
|
replace_exact(
|
||||||
"NineManga RU to Niadd RU",
|
"NineManga RU to Niadd RU",
|
||||||
''' @Broken
|
''' @Broken
|
||||||
@@ -100,7 +279,18 @@ replace_exact(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
parser_file.write_text(text, encoding="utf-8")
|
parser_file.write_text(
|
||||||
|
text,
|
||||||
|
encoding="utf-8",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
print()
|
print()
|
||||||
print(f"[OK] Patched: {parser_file}")
|
print(f"[OK] Patched: {parser_file}")
|
||||||
|
print()
|
||||||
|
print("[OK] Niadd domain")
|
||||||
|
print("[OK] Niadd category pagination")
|
||||||
|
print("[OK] Niadd search pagination")
|
||||||
|
print("[OK] Niadd manga list parser")
|
||||||
|
print("[OK] Russian statuses")
|
||||||
|
print("[OK] Russian source enabled")
|
||||||
Reference in new issue
Block a user