Adjust nullability in parsers
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package org.koitharu.kotatsu.core.parser
|
||||
|
||||
import org.koitharu.kotatsu.base.domain.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.core.exceptions.ParseException
|
||||
import org.koitharu.kotatsu.core.model.MangaPage
|
||||
import org.koitharu.kotatsu.core.model.MangaSource
|
||||
import org.koitharu.kotatsu.core.model.MangaTag
|
||||
@@ -75,4 +76,8 @@ abstract class RemoteMangaRepository(
|
||||
h = 31 * h + id
|
||||
return h
|
||||
}
|
||||
|
||||
protected fun parseFailed(message: String? = null): Nothing {
|
||||
throw ParseException(message)
|
||||
}
|
||||
}
|
||||
@@ -32,30 +32,33 @@ class AnibelRepository(loaderContext: MangaLoaderContext) : RemoteMangaRepositor
|
||||
else -> "/manga?page=$page".withDomain()
|
||||
}
|
||||
val doc = loaderContext.httpGet(link).parseHtml()
|
||||
val root = doc.body().select("div.manga-block") ?: throw ParseException("Cannot find root")
|
||||
val root = doc.body().select("div.manga-block") ?: parseFailed("Cannot find root")
|
||||
val items = root.select("div.anime-card")
|
||||
return items.mapNotNull { card ->
|
||||
val href = card.selectFirst("a").attr("href")
|
||||
val href = card.selectFirst("a")?.attr("href") ?: return@mapNotNull null
|
||||
val status = card.select("tr")[2].text()
|
||||
val fullTitle = card.selectFirst("h1.anime-card-title").text()
|
||||
.substringBeforeLast('[')
|
||||
val fullTitle = card.selectFirst("h1.anime-card-title")?.text()
|
||||
?.substringBeforeLast('[') ?: return@mapNotNull null
|
||||
val titleParts = fullTitle.splitTwoParts('/')
|
||||
Manga(
|
||||
id = generateUid(href),
|
||||
title = titleParts?.first?.trim() ?: fullTitle,
|
||||
coverUrl = card.selectFirst("img").attr("data-src").withDomain(),
|
||||
coverUrl = card.selectFirst("img")?.attr("data-src")
|
||||
?.withDomain().orEmpty(),
|
||||
altTitle = titleParts?.second?.trim(),
|
||||
author = null,
|
||||
rating = Manga.NO_RATING,
|
||||
url = href,
|
||||
publicUrl = href.withDomain(),
|
||||
tags = card.select("p.tupe.tag")?.select("a")?.mapNotNullToSet tags@{ x ->
|
||||
tags = card.select("p.tupe.tag").select("a").mapNotNullToSet tags@{ x ->
|
||||
MangaTag(
|
||||
title = x.text(),
|
||||
key = x.attr("href")?.substringAfterLast("=") ?: return@tags null,
|
||||
key = x.attr("href").ifEmpty {
|
||||
return@mapNotNull null
|
||||
}.substringAfterLast("="),
|
||||
source = source
|
||||
)
|
||||
}.orEmpty(),
|
||||
},
|
||||
state = when (status) {
|
||||
"выпускаецца" -> MangaState.ONGOING
|
||||
"завершанае" -> MangaState.FINISHED
|
||||
@@ -68,16 +71,17 @@ class AnibelRepository(loaderContext: MangaLoaderContext) : RemoteMangaRepositor
|
||||
|
||||
override suspend fun getDetails(manga: Manga): Manga {
|
||||
val doc = loaderContext.httpGet(manga.publicUrl).parseHtml()
|
||||
val root = doc.body().select("div.container") ?: throw ParseException("Cannot find root")
|
||||
val root = doc.body().select("div.container") ?: parseFailed("Cannot find root")
|
||||
return manga.copy(
|
||||
description = root.select("div.manga-block.grid-12")[2].select("p").text(),
|
||||
chapters = root.select("ul.series").flatMap { table ->
|
||||
table.select("li")
|
||||
}.map { it.selectFirst("a") }.mapIndexedNotNull { i, a ->
|
||||
val href = a.select("a").first().attr("href").toRelativeUrl(getDomain())
|
||||
val href = a?.select("a")?.first()?.attr("href")
|
||||
?.toRelativeUrl(getDomain()) ?: return@mapIndexedNotNull null
|
||||
MangaChapter(
|
||||
id = generateUid(href),
|
||||
name = a.select("a").first().text(),
|
||||
name = a.selectFirst("a")?.text().orEmpty(),
|
||||
number = i + 1,
|
||||
url = href,
|
||||
source = source
|
||||
@@ -112,16 +116,17 @@ class AnibelRepository(loaderContext: MangaLoaderContext) : RemoteMangaRepositor
|
||||
)
|
||||
}
|
||||
}
|
||||
throw ParseException("Pages list not found at ${chapter.url.withDomain()}")
|
||||
parseFailed("Pages list not found at ${chapter.url.withDomain()}")
|
||||
}
|
||||
|
||||
override suspend fun getTags(): Set<MangaTag> {
|
||||
val doc = loaderContext.httpGet("https://${getDomain()}/manga").parseHtml()
|
||||
val root = doc.body().select("div#tabs-genres").select("ul#list.ul-three-colums")
|
||||
return root.select("p.menu-tags.tupe").mapToSet { a ->
|
||||
return root.select("p.menu-tags.tupe").mapToSet { p ->
|
||||
val a = p.selectFirst("a") ?: parseFailed("a is null")
|
||||
MangaTag(
|
||||
title = a.select("a").text().capitalize(Locale.ROOT),
|
||||
key = a.select("a").attr("data-name"),
|
||||
title = a.text().toCamelCase(),
|
||||
key = a.attr("data-name"),
|
||||
source = source
|
||||
)
|
||||
}
|
||||
@@ -130,30 +135,33 @@ class AnibelRepository(loaderContext: MangaLoaderContext) : RemoteMangaRepositor
|
||||
private suspend fun search(query: String): List<Manga> {
|
||||
val domain = getDomain()
|
||||
val doc = loaderContext.httpGet("https://$domain/search?q=$query").parseHtml()
|
||||
val root = doc.body().select("div.manga-block").select("article.tab-2") ?: throw ParseException("Cannot find root")
|
||||
val root = doc.body().select("div.manga-block").select("article.tab-2") ?: parseFailed("Cannot find root")
|
||||
val items = root.select("div.anime-card")
|
||||
return items.mapNotNull { card ->
|
||||
val href = card.select("a").attr("href")
|
||||
val status = card.select("tr")[2].text()
|
||||
val fullTitle = card.selectFirst("h1.anime-card-title").text()
|
||||
.substringBeforeLast('[')
|
||||
val fullTitle = card.selectFirst("h1.anime-card-title")?.text()
|
||||
?.substringBeforeLast('[') ?: return@mapNotNull null
|
||||
val titleParts = fullTitle.splitTwoParts('/')
|
||||
Manga(
|
||||
id = generateUid(href),
|
||||
title = titleParts?.first?.trim() ?: fullTitle,
|
||||
coverUrl = card.selectFirst("img").attr("src").withDomain(),
|
||||
coverUrl = card.selectFirst("img")?.attr("src")
|
||||
?.withDomain().orEmpty(),
|
||||
altTitle = titleParts?.second?.trim(),
|
||||
author = null,
|
||||
rating = Manga.NO_RATING,
|
||||
url = href,
|
||||
publicUrl = href.withDomain(),
|
||||
tags = card.select("p.tupe.tag")?.select("a")?.mapNotNullToSet tags@{ x ->
|
||||
tags = card.select("p.tupe.tag").select("a").mapNotNullToSet tags@{ x ->
|
||||
MangaTag(
|
||||
title = x.text(),
|
||||
key = x.attr("href")?.substringAfterLast("=") ?: return@tags null,
|
||||
key = x.attr("href").ifEmpty {
|
||||
return@mapNotNull null
|
||||
}.substringAfterLast("="),
|
||||
source = source
|
||||
)
|
||||
}.orEmpty(),
|
||||
},
|
||||
state = when (status) {
|
||||
"выпускаецца" -> MangaState.ONGOING
|
||||
"завершанае" -> MangaState.FINISHED
|
||||
|
||||
@@ -35,7 +35,7 @@ abstract class ChanRepository(loaderContext: MangaLoaderContext) : RemoteMangaRe
|
||||
else -> "https://$domain/${getSortKey(sortOrder)}?offset=$offset"
|
||||
}
|
||||
val doc = loaderContext.httpGet(url).parseHtml()
|
||||
val root = doc.body().selectFirst("div.main_fon").getElementById("content")
|
||||
val root = doc.body().selectFirst("div.main_fon")?.getElementById("content")
|
||||
?: throw ParseException("Cannot find root")
|
||||
return root.select("div.content_row").mapNotNull { row ->
|
||||
val a = row.selectFirst("div.manga_row1")?.selectFirst("h2")?.selectFirst("a")
|
||||
@@ -78,7 +78,7 @@ abstract class ChanRepository(loaderContext: MangaLoaderContext) : RemoteMangaRe
|
||||
chapters = root.select("table.table_cha").flatMap { table ->
|
||||
table.select("div.manga2")
|
||||
}.map { it.selectFirst("a") }.reversed().mapIndexedNotNull { i, a ->
|
||||
val href = a.relUrl("href")
|
||||
val href = a?.relUrl("href") ?: return@mapIndexedNotNull null
|
||||
MangaChapter(
|
||||
id = generateUid(href),
|
||||
name = a.text().trim(),
|
||||
@@ -123,12 +123,12 @@ abstract class ChanRepository(loaderContext: MangaLoaderContext) : RemoteMangaRe
|
||||
override suspend fun getTags(): Set<MangaTag> {
|
||||
val domain = getDomain()
|
||||
val doc = loaderContext.httpGet("https://$domain/catalog").parseHtml()
|
||||
val root = doc.body().selectFirst("div.main_fon").getElementById("side")
|
||||
.select("ul").last()
|
||||
val root = doc.body().selectFirst("div.main_fon")?.getElementById("side")
|
||||
?.select("ul")?.last() ?: throw ParseException("Cannot find root")
|
||||
return root.select("li.sidetag").mapToSet { li ->
|
||||
val a = li.children().last()
|
||||
val a = li.children().last() ?: throw ParseException("a is null")
|
||||
MangaTag(
|
||||
title = a.text().capitalize(),
|
||||
title = a.text().toCamelCase(),
|
||||
key = a.attr("href").substringAfterLast('/'),
|
||||
source = source
|
||||
)
|
||||
|
||||
@@ -6,7 +6,6 @@ import org.koitharu.kotatsu.core.model.*
|
||||
import org.koitharu.kotatsu.core.parser.RemoteMangaRepository
|
||||
import org.koitharu.kotatsu.utils.ext.*
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
class DesuMeRepository(loaderContext: MangaLoaderContext) : RemoteMangaRepository(loaderContext) {
|
||||
|
||||
@@ -122,12 +121,13 @@ class DesuMeRepository(loaderContext: MangaLoaderContext) : RemoteMangaRepositor
|
||||
|
||||
override suspend fun getTags(): Set<MangaTag> {
|
||||
val doc = loaderContext.httpGet("https://${getDomain()}/manga/").parseHtml()
|
||||
val root = doc.body().getElementById("animeFilter").selectFirst(".catalog-genres")
|
||||
val root = doc.body().getElementById("animeFilter")
|
||||
?.selectFirst(".catalog-genres") ?: throw ParseException("Root not found")
|
||||
return root.select("li").mapToSet {
|
||||
MangaTag(
|
||||
source = source,
|
||||
key = it.selectFirst("input").attr("data-genre"),
|
||||
title = it.selectFirst("label").text()
|
||||
key = it.selectFirst("input")?.attr("data-genre") ?: parseFailed(),
|
||||
title = it.selectFirst("label")?.text() ?: parseFailed()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ abstract class GroupleRepository(loaderContext: MangaLoaderContext) :
|
||||
if (descDiv.selectFirst("i.fa-user") != null) {
|
||||
return@mapNotNull null //skip author
|
||||
}
|
||||
val href = imgDiv.selectFirst("a").attr("href")?.inContextOf(node)
|
||||
val href = imgDiv.selectFirst("a")?.attr("href")?.inContextOf(node)
|
||||
if (href == null || href.toHttpUrl().host != baseHost) {
|
||||
return@mapNotNull null // skip external links
|
||||
}
|
||||
@@ -161,11 +161,11 @@ abstract class GroupleRepository(loaderContext: MangaLoaderContext) :
|
||||
|
||||
override suspend fun getTags(): Set<MangaTag> {
|
||||
val doc = loaderContext.httpGet("https://${getDomain()}/list/genres/sort_name").parseHtml()
|
||||
val root = doc.body().getElementById("mangaBox").selectFirst("div.leftContent")
|
||||
.selectFirst("table.table")
|
||||
val root = doc.body().getElementById("mangaBox")?.selectFirst("div.leftContent")
|
||||
?.selectFirst("table.table") ?: parseFailed("Cannot find root")
|
||||
return root.select("a.element-link").mapToSet { a ->
|
||||
MangaTag(
|
||||
title = a.text().capitalize(),
|
||||
title = a.text().toCamelCase(),
|
||||
key = a.attr("href").substringAfterLast('/'),
|
||||
source = source
|
||||
)
|
||||
|
||||
@@ -36,7 +36,7 @@ class HenChanRepository(loaderContext: MangaLoaderContext) : ChanRepository(load
|
||||
description = root.getElementById("description")?.html()?.substringBeforeLast("<div"),
|
||||
largeCoverUrl = root.getElementById("cover")?.absUrl("src"),
|
||||
tags = root.selectFirst("div.sidetags")?.select("li.sidetag")?.mapToSet {
|
||||
val a = it.children().last()
|
||||
val a = it.children().last() ?: parseFailed("Invalid tag")
|
||||
MangaTag(
|
||||
title = a.text(),
|
||||
key = a.attr("href").substringAfterLast('/'),
|
||||
|
||||
@@ -10,7 +10,6 @@ import org.koitharu.kotatsu.core.model.*
|
||||
import org.koitharu.kotatsu.core.parser.RemoteMangaRepository
|
||||
import org.koitharu.kotatsu.utils.ext.*
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
open class MangaLibRepository(loaderContext: MangaLoaderContext) :
|
||||
RemoteMangaRepository(loaderContext) {
|
||||
@@ -51,13 +50,14 @@ open class MangaLibRepository(loaderContext: MangaLoaderContext) :
|
||||
}
|
||||
val doc = loaderContext.httpGet(url).parseHtml()
|
||||
val root = doc.body().getElementById("manga-list") ?: throw ParseException("Root not found")
|
||||
val items = root.selectFirst("div.media-cards-grid").select("div.media-card-wrap")
|
||||
val items = root.selectFirst("div.media-cards-grid")?.select("div.media-card-wrap")
|
||||
?: return emptyList()
|
||||
return items.mapNotNull { card ->
|
||||
val a = card.selectFirst("a.media-card") ?: return@mapNotNull null
|
||||
val href = a.relUrl("href")
|
||||
Manga(
|
||||
id = generateUid(href),
|
||||
title = card.selectFirst("h3").text(),
|
||||
title = card.selectFirst("h3")?.text().orEmpty(),
|
||||
coverUrl = a.absUrl("data-src"),
|
||||
altTitle = null,
|
||||
author = null,
|
||||
@@ -98,10 +98,11 @@ open class MangaLibRepository(loaderContext: MangaLoaderContext) :
|
||||
append(item.getInt("chapter_volume"))
|
||||
append("/c")
|
||||
append(item.getString("chapter_number"))
|
||||
@Suppress("BlockingMethodInNonBlockingContext") // lint issue
|
||||
append('/')
|
||||
append(item.optString("chapter_string"))
|
||||
}
|
||||
var name = item.getString("chapter_name")
|
||||
var name = item.getStringOrNull("chapter_name")
|
||||
if (name.isNullOrBlank() || name == "null") {
|
||||
name = "Том " + item.getInt("chapter_volume") +
|
||||
" Глава " + item.getString("chapter_number")
|
||||
@@ -128,17 +129,17 @@ open class MangaLibRepository(loaderContext: MangaLoaderContext) :
|
||||
rating = root.selectFirst("div.media-stats-item__score")
|
||||
?.selectFirst("span")
|
||||
?.text()?.toFloatOrNull()?.div(5f) ?: manga.rating,
|
||||
author = info.getElementsMatchingOwnText("Автор").firstOrNull()
|
||||
author = info?.getElementsMatchingOwnText("Автор")?.firstOrNull()
|
||||
?.nextElementSibling()?.text() ?: manga.author,
|
||||
tags = info.selectFirst("div.media-tags")
|
||||
tags = info?.selectFirst("div.media-tags")
|
||||
?.select("a.media-tag-item")?.mapToSet { a ->
|
||||
MangaTag(
|
||||
title = a.text().capitalize(),
|
||||
title = a.text().toCamelCase(),
|
||||
key = a.attr("href").substringAfterLast('='),
|
||||
source = source
|
||||
)
|
||||
} ?: manga.tags,
|
||||
description = info.selectFirst("div.media-description__text")?.html(),
|
||||
description = info?.selectFirst("div.media-description__text")?.html(),
|
||||
chapters = chapters
|
||||
)
|
||||
}
|
||||
@@ -146,11 +147,11 @@ open class MangaLibRepository(loaderContext: MangaLoaderContext) :
|
||||
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
|
||||
val fullUrl = chapter.url.withDomain()
|
||||
val doc = loaderContext.httpGet(fullUrl).parseHtml()
|
||||
if (doc.location()?.endsWith("/register") == true) {
|
||||
if (doc.location().endsWith("/register")) {
|
||||
throw AuthRequiredException("/login".inContextOf(doc))
|
||||
}
|
||||
val scripts = doc.head().select("script")
|
||||
val pg = doc.body().getElementById("pg").html()
|
||||
val pg = (doc.body().getElementById("pg")?.html() ?: parseFailed("Element #pg not found"))
|
||||
.substringAfter('=')
|
||||
.substringBeforeLast(';')
|
||||
val pages = JSONArray(pg)
|
||||
@@ -196,7 +197,7 @@ open class MangaLibRepository(loaderContext: MangaLoaderContext) :
|
||||
result += MangaTag(
|
||||
source = source,
|
||||
key = x.getInt("id").toString(),
|
||||
title = x.getString("name").capitalize()
|
||||
title = x.getString("name").toCamelCase()
|
||||
)
|
||||
}
|
||||
return result
|
||||
|
||||
@@ -51,14 +51,15 @@ class MangaTownRepository(loaderContext: MangaLoaderContext) :
|
||||
?: throw ParseException("Root not found")
|
||||
return root.select("li").mapNotNull { li ->
|
||||
val a = li.selectFirst("a.manga_cover")
|
||||
val href = a.relUrl("href")
|
||||
val href = a?.relUrl("href")
|
||||
?: return@mapNotNull null
|
||||
val views = li.select("p.view")
|
||||
val status = views.findOwnText { x -> x.startsWith("Status:") }
|
||||
?.substringAfter(':')?.trim()?.toLowerCase(Locale.ROOT)
|
||||
?.substringAfter(':')?.trim()?.lowercase(Locale.ROOT)
|
||||
Manga(
|
||||
id = generateUid(href),
|
||||
title = a.attr("title"),
|
||||
coverUrl = a.selectFirst("img").absUrl("src"),
|
||||
coverUrl = a.selectFirst("img")?.absUrl("src").orEmpty(),
|
||||
source = MangaSource.MANGATOWN,
|
||||
altTitle = null,
|
||||
rating = li.selectFirst("p.score")?.selectFirst("b")
|
||||
@@ -87,11 +88,11 @@ class MangaTownRepository(loaderContext: MangaLoaderContext) :
|
||||
val doc = loaderContext.httpGet(manga.url.withDomain()).parseHtml()
|
||||
val root = doc.body().selectFirst("section.main")
|
||||
?.selectFirst("div.article_content") ?: throw ParseException("Cannot find root")
|
||||
val info = root.selectFirst("div.detail_info").selectFirst("ul")
|
||||
val info = root.selectFirst("div.detail_info")?.selectFirst("ul")
|
||||
val chaptersList = root.selectFirst("div.chapter_content")
|
||||
?.selectFirst("ul.chapter_list")?.select("li")?.asReversed()
|
||||
return manga.copy(
|
||||
tags = manga.tags + info.select("li").find { x ->
|
||||
tags = manga.tags + info?.select("li")?.find { x ->
|
||||
x.selectFirst("b")?.ownText() == "Genre(s):"
|
||||
}?.select("a")?.mapNotNull { a ->
|
||||
MangaTag(
|
||||
@@ -100,9 +101,10 @@ class MangaTownRepository(loaderContext: MangaLoaderContext) :
|
||||
source = MangaSource.MANGATOWN
|
||||
)
|
||||
}.orEmpty(),
|
||||
description = info.getElementById("show")?.ownText(),
|
||||
description = info?.getElementById("show")?.ownText(),
|
||||
chapters = chaptersList?.mapIndexedNotNull { i, li ->
|
||||
val href = li.selectFirst("a").relUrl("href")
|
||||
val href = li.selectFirst("a")?.relUrl("href")
|
||||
?: return@mapIndexedNotNull null
|
||||
val name = li.select("span").filter { it.className().isEmpty() }
|
||||
.joinToString(" - ") { it.text() }.trim()
|
||||
MangaChapter(
|
||||
@@ -110,7 +112,7 @@ class MangaTownRepository(loaderContext: MangaLoaderContext) :
|
||||
url = href,
|
||||
source = MangaSource.MANGATOWN,
|
||||
number = i + 1,
|
||||
name = if (name.isEmpty()) "${manga.title} - ${i + 1}" else name
|
||||
name = name.ifEmpty { "${manga.title} - ${i + 1}" }
|
||||
)
|
||||
}
|
||||
)
|
||||
@@ -121,7 +123,7 @@ class MangaTownRepository(loaderContext: MangaLoaderContext) :
|
||||
val doc = loaderContext.httpGet(fullUrl).parseHtml()
|
||||
val root = doc.body().selectFirst("div.page_select")
|
||||
?: throw ParseException("Cannot find root")
|
||||
return root.selectFirst("select").select("option").mapNotNull {
|
||||
return root.selectFirst("select")?.select("option")?.mapNotNull {
|
||||
val href = it.relUrl("value")
|
||||
if (href.endsWith("featured.html")) {
|
||||
return@mapNotNull null
|
||||
@@ -132,20 +134,20 @@ class MangaTownRepository(loaderContext: MangaLoaderContext) :
|
||||
referer = fullUrl,
|
||||
source = MangaSource.MANGATOWN
|
||||
)
|
||||
}
|
||||
} ?: parseFailed("Pages list not found")
|
||||
}
|
||||
|
||||
override suspend fun getPageUrl(page: MangaPage): String {
|
||||
val doc = loaderContext.httpGet(page.url.withDomain()).parseHtml()
|
||||
return doc.getElementById("image").absUrl("src")
|
||||
return doc.getElementById("image")?.absUrl("src") ?: parseFailed("Image not found")
|
||||
}
|
||||
|
||||
override suspend fun getTags(): Set<MangaTag> {
|
||||
val doc = loaderContext.httpGet("/directory/".withDomain()).parseHtml()
|
||||
val root = doc.body().selectFirst("aside.right")
|
||||
.getElementsContainingOwnText("Genres")
|
||||
.first()
|
||||
.nextElementSibling()
|
||||
?.getElementsContainingOwnText("Genres")
|
||||
?.first()
|
||||
?.nextElementSibling() ?: parseFailed("Root not found")
|
||||
return root.select("li").mapNotNullToSet { li ->
|
||||
val a = li.selectFirst("a") ?: return@mapNotNullToSet null
|
||||
val key = a.attr("href").parseTagKey()
|
||||
|
||||
@@ -43,25 +43,26 @@ class MangareadRepository(
|
||||
payload
|
||||
).parseHtml()
|
||||
return doc.select("div.row.c-tabs-item__content").map { div ->
|
||||
val href = div.selectFirst("a").relUrl("href")
|
||||
val href = div.selectFirst("a")?.relUrl("href")
|
||||
?: parseFailed("Link not found")
|
||||
val summary = div.selectFirst(".tab-summary")
|
||||
Manga(
|
||||
id = generateUid(href),
|
||||
url = href,
|
||||
publicUrl = href.inContextOf(div),
|
||||
coverUrl = div.selectFirst("img").absUrl("src"),
|
||||
title = summary.selectFirst("h3").text(),
|
||||
coverUrl = div.selectFirst("img")?.absUrl("src").orEmpty(),
|
||||
title = summary?.selectFirst("h3")?.text().orEmpty(),
|
||||
rating = div.selectFirst("span.total_votes")?.ownText()
|
||||
?.toFloatOrNull()?.div(5f) ?: -1f,
|
||||
tags = summary.selectFirst(".mg_genres")?.select("a")?.mapToSet { a ->
|
||||
tags = summary?.selectFirst(".mg_genres")?.select("a")?.mapToSet { a ->
|
||||
MangaTag(
|
||||
key = a.attr("href").removeSuffix("/").substringAfterLast('/'),
|
||||
title = a.text(),
|
||||
source = MangaSource.MANGAREAD
|
||||
)
|
||||
}.orEmpty(),
|
||||
author = summary.selectFirst(".mg_author")?.selectFirst("a")?.ownText(),
|
||||
state = when (summary.selectFirst(".mg_status")?.selectFirst(".summary-content")
|
||||
author = summary?.selectFirst(".mg_author")?.selectFirst("a")?.ownText(),
|
||||
state = when (summary?.selectFirst(".mg_status")?.selectFirst(".summary-content")
|
||||
?.ownText()?.trim()) {
|
||||
"OnGoing" -> MangaState.ONGOING
|
||||
"Completed" -> MangaState.FINISHED
|
||||
@@ -75,9 +76,9 @@ class MangareadRepository(
|
||||
override suspend fun getTags(): Set<MangaTag> {
|
||||
val doc = loaderContext.httpGet("https://${getDomain()}/manga/").parseHtml()
|
||||
val root = doc.body().selectFirst("header")
|
||||
.selectFirst("ul.second-menu")
|
||||
?.selectFirst("ul.second-menu") ?: parseFailed("Root not found")
|
||||
return root.select("li").mapNotNullToSet { li ->
|
||||
val a = li.selectFirst("a")
|
||||
val a = li.selectFirst("a") ?: return@mapNotNullToSet null
|
||||
val href = a.attr("href").removeSuffix("/")
|
||||
.substringAfterLast("genres/", "")
|
||||
if (href.isEmpty()) {
|
||||
@@ -127,10 +128,12 @@ class MangareadRepository(
|
||||
?.joinToString { it.html() },
|
||||
chapters = doc2.select("li").asReversed().mapIndexed { i, li ->
|
||||
val a = li.selectFirst("a")
|
||||
val href = a.relUrl("href")
|
||||
val href = a?.relUrl("href").orEmpty().ifEmpty {
|
||||
parseFailed("Link is missing")
|
||||
}
|
||||
MangaChapter(
|
||||
id = generateUid(href),
|
||||
name = a.ownText(),
|
||||
name = a!!.ownText(),
|
||||
number = i + 1,
|
||||
url = href,
|
||||
source = MangaSource.MANGAREAD
|
||||
@@ -147,7 +150,7 @@ class MangareadRepository(
|
||||
?: throw ParseException("Root not found")
|
||||
return root.select("div.page-break").map { div ->
|
||||
val img = div.selectFirst("img")
|
||||
val url = img.relUrl("src")
|
||||
val url = img?.relUrl("src") ?: parseFailed("Page image not found")
|
||||
MangaPage(
|
||||
id = generateUid(url),
|
||||
url = url,
|
||||
|
||||
@@ -56,22 +56,23 @@ abstract class NineMangaRepository(
|
||||
?: throw ParseException("Cannot find root")
|
||||
val baseHost = root.baseUri().toHttpUrl().host
|
||||
return root.select("li").map { node ->
|
||||
val href = node.selectFirst("a").absUrl("href")
|
||||
val href = node.selectFirst("a")?.absUrl("href")
|
||||
?: parseFailed("Link not found")
|
||||
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(),
|
||||
title = dd?.selectFirst("a.bookname")?.text()?.toCamelCase().orEmpty(),
|
||||
altTitle = null,
|
||||
coverUrl = node.selectFirst("img").absUrl("src"),
|
||||
coverUrl = node.selectFirst("img")?.absUrl("src").orEmpty(),
|
||||
rating = Manga.NO_RATING,
|
||||
author = null,
|
||||
tags = emptySet(),
|
||||
state = null,
|
||||
source = source,
|
||||
description = dd.selectFirst("p").html(),
|
||||
description = dd?.selectFirst("p")?.html(),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -86,7 +87,7 @@ abstract class NineMangaRepository(
|
||||
val infoRoot = root.selectFirst("div.bookintro")
|
||||
?: throw ParseException("Cannot find info")
|
||||
return manga.copy(
|
||||
tags = infoRoot.getElementsByAttributeValue("itemprop", "genre")?.first()
|
||||
tags = infoRoot.getElementsByAttributeValue("itemprop", "genre").first()
|
||||
?.select("a")?.mapToSet { a ->
|
||||
MangaTag(
|
||||
title = a.text(),
|
||||
@@ -94,13 +95,13 @@ abstract class NineMangaRepository(
|
||||
source = source,
|
||||
)
|
||||
}.orEmpty(),
|
||||
author = infoRoot.getElementsByAttributeValue("itemprop", "author")?.first()?.text(),
|
||||
description = infoRoot.getElementsByAttributeValue("itemprop", "description")?.first()
|
||||
author = infoRoot.getElementsByAttributeValue("itemprop", "author").first()?.text(),
|
||||
description = infoRoot.getElementsByAttributeValue("itemprop", "description").first()
|
||||
?.html()?.substringAfter("</b>"),
|
||||
chapters = root.selectFirst("div.chapterbox")?.selectFirst("ul")
|
||||
?.select("li")?.asReversed()?.mapIndexed { i, li ->
|
||||
val a = li.selectFirst("a")
|
||||
val href = a.relUrl("href")
|
||||
val href = a?.relUrl("href") ?: parseFailed("Link not found")
|
||||
MangaChapter(
|
||||
id = generateUid(href),
|
||||
name = a.text(),
|
||||
@@ -138,14 +139,14 @@ abstract class NineMangaRepository(
|
||||
val doc = loaderContext.httpGet("https://${getDomain()}/category/", PREDEFINED_HEADERS)
|
||||
.parseHtml()
|
||||
val root = doc.body().selectFirst("ul.genreidex")
|
||||
return root.select("li").mapToSet { li ->
|
||||
val a = li.selectFirst("a")
|
||||
return root?.select("li")?.mapToSet { li ->
|
||||
val a = li.selectFirst("a") ?: parseFailed("Link not found")
|
||||
MangaTag(
|
||||
title = a.text(),
|
||||
key = a.attr("href").substringBetweenLast("/", "."),
|
||||
source = source
|
||||
)
|
||||
}
|
||||
} ?: parseFailed("Root not found")
|
||||
}
|
||||
|
||||
class English(loaderContext: MangaLoaderContext) : NineMangaRepository(
|
||||
|
||||
@@ -6,6 +6,7 @@ import java.math.BigInteger
|
||||
import java.net.URLEncoder
|
||||
import java.security.MessageDigest
|
||||
import java.util.*
|
||||
import kotlin.contracts.contract
|
||||
import kotlin.math.min
|
||||
|
||||
fun String.longHashCode(): Long {
|
||||
|
||||
Reference in New Issue
Block a user