|
|
|
@ -18,12 +18,12 @@ import org.koitharu.kotatsu.parsers.Broken
|
|
|
|
@Broken
|
|
|
|
@Broken
|
|
|
|
@MangaSourceParser("TRUYENHENTAI18", "TruyenHentai18", "vi", ContentType.HENTAI)
|
|
|
|
@MangaSourceParser("TRUYENHENTAI18", "TruyenHentai18", "vi", ContentType.HENTAI)
|
|
|
|
internal class TruyenHentai18(context: MangaLoaderContext):
|
|
|
|
internal class TruyenHentai18(context: MangaLoaderContext):
|
|
|
|
PagedMangaParser(context, MangaParserSource.TRUYENHENTAI18, 18) {
|
|
|
|
PagedMangaParser(context, MangaParserSource.TRUYENHENTAI18, 18) {
|
|
|
|
|
|
|
|
|
|
|
|
override val configKeyDomain = ConfigKey.Domain("truyenhentai18.app")
|
|
|
|
override val configKeyDomain = ConfigKey.Domain("truyenhentai18.app")
|
|
|
|
|
|
|
|
|
|
|
|
private val apiSuffix = "api.th18.app"
|
|
|
|
private val apiSuffix = "api.th18.app"
|
|
|
|
private val cdnSuffix = "vi-api.th18.app"
|
|
|
|
private val cdnSuffix = "vi-api.th18.app"
|
|
|
|
|
|
|
|
|
|
|
|
override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
|
|
|
|
override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
|
|
|
|
super.onCreateConfig(keys)
|
|
|
|
super.onCreateConfig(keys)
|
|
|
|
@ -32,8 +32,8 @@ internal class TruyenHentai18(context: MangaLoaderContext):
|
|
|
|
|
|
|
|
|
|
|
|
override val availableSortOrders: Set<SortOrder> = EnumSet.of(
|
|
|
|
override val availableSortOrders: Set<SortOrder> = EnumSet.of(
|
|
|
|
SortOrder.UPDATED,
|
|
|
|
SortOrder.UPDATED,
|
|
|
|
SortOrder.NEWEST,
|
|
|
|
SortOrder.NEWEST,
|
|
|
|
SortOrder.NEWEST_ASC,
|
|
|
|
SortOrder.NEWEST_ASC,
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
override val filterCapabilities: MangaListFilterCapabilities
|
|
|
|
override val filterCapabilities: MangaListFilterCapabilities
|
|
|
|
@ -83,11 +83,10 @@ internal class TruyenHentai18(context: MangaLoaderContext):
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
val fullUrl = "https://" + url
|
|
|
|
|
|
|
|
return when {
|
|
|
|
return when {
|
|
|
|
filter.tags.isNotEmpty() -> parseNextList(webClient.httpGet(fullUrl).parseHtml())
|
|
|
|
filter.tags.isNotEmpty() -> parseNextList(webClient.httpGet("https://$url").parseHtml())
|
|
|
|
else -> {
|
|
|
|
else -> {
|
|
|
|
val doc = webClient.httpGet(fullUrl).parseJson()
|
|
|
|
val doc = webClient.httpGet("https://$url").parseJson()
|
|
|
|
parseJSONList(doc)
|
|
|
|
parseJSONList(doc)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@ -231,41 +230,31 @@ internal class TruyenHentai18(context: MangaLoaderContext):
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
|
|
|
|
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
|
|
|
|
val doc = webClient.httpGet(chapter.url.toAbsoluteUrl(domain)).parseHtml()
|
|
|
|
val doc = webClient.httpGet(chapter.url.toAbsoluteUrl(domain)).parseHtml()
|
|
|
|
val scriptContent = doc.select("script")
|
|
|
|
val scriptContent = doc.select("script")
|
|
|
|
.firstOrNull { it.data().startsWith("self.__next_f.push([1,\"\\u003cp\\u003e\\u003c") }
|
|
|
|
.firstOrNull { it.data().contains("img src") }
|
|
|
|
?.data()
|
|
|
|
?.data()
|
|
|
|
|
|
|
|
?: return emptyList()
|
|
|
|
if (scriptContent != null) {
|
|
|
|
|
|
|
|
val regex = Regex("""self\.__next_f\.push\(\[1,\"(.*)\"\]\)""")
|
|
|
|
val decoded = scriptContent
|
|
|
|
val htmlEncoded = regex.find(scriptContent)?.groupValues?.getOrNull(1)
|
|
|
|
.replace("\\u003c", "<")
|
|
|
|
if (!htmlEncoded.isNullOrEmpty()) {
|
|
|
|
.replace("\\u003e", ">")
|
|
|
|
val html = try {
|
|
|
|
.replace("\\\"", "\"")
|
|
|
|
JSONArray("[\"$htmlEncoded\"]").getString(0)
|
|
|
|
.replace("\\/", "/")
|
|
|
|
} catch (e: Exception) {
|
|
|
|
|
|
|
|
htmlEncoded
|
|
|
|
val regex = Regex("""img\s+src=["'](https?://[^"']+)["']""")
|
|
|
|
.replace("\\u003c", "<")
|
|
|
|
val imageUrls = regex.findAll(decoded).map { it.groupValues[1] }.toList()
|
|
|
|
.replace("\\u003e", ">")
|
|
|
|
|
|
|
|
.replace("\\\"", "\"")
|
|
|
|
return imageUrls.map { url ->
|
|
|
|
.replace("\\/", "/")
|
|
|
|
MangaPage(
|
|
|
|
}
|
|
|
|
id = generateUid(url),
|
|
|
|
|
|
|
|
url = url,
|
|
|
|
val imageUrls = Jsoup.parse(html).select("img").mapNotNull { it.attr("src") }
|
|
|
|
preview = null,
|
|
|
|
if (imageUrls.isNotEmpty()) {
|
|
|
|
source = source,
|
|
|
|
return imageUrls.map { url ->
|
|
|
|
)
|
|
|
|
MangaPage(
|
|
|
|
}
|
|
|
|
id = generateUid(url),
|
|
|
|
}
|
|
|
|
url = url,
|
|
|
|
|
|
|
|
preview = null,
|
|
|
|
|
|
|
|
source = source,
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} else return emptyList()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return emptyList()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private fun parseChapterDate(date: String?): Long {
|
|
|
|
private fun parseChapterDate(date: String?): Long {
|
|
|
|
if (date == null) return 0
|
|
|
|
if (date == null) return 0
|
|
|
|
|