Merge pull request #155 from VietAnh14/source/truyentranhlh
[TruyentranhLH]: New sourcepull/168/head
commit
f4c47b5b84
@ -0,0 +1,154 @@
|
||||
package org.koitharu.kotatsu.parsers.site
|
||||
|
||||
import androidx.collection.ArrayMap
|
||||
import androidx.collection.ArraySet
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.MangaSourceParser
|
||||
import org.koitharu.kotatsu.parsers.PagedMangaParser
|
||||
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
||||
import org.koitharu.kotatsu.parsers.model.*
|
||||
import org.koitharu.kotatsu.parsers.util.*
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
@MangaSourceParser("TRUYENTRANHLH", "TruyentranhLH", "vi")
|
||||
class TruyentranhLHParser(context: MangaLoaderContext) :
|
||||
PagedMangaParser(context, source = MangaSource.TRUYENTRANHLH, pageSize = 18) {
|
||||
|
||||
override val configKeyDomain: ConfigKey.Domain = ConfigKey.Domain("truyentranhlh.net", null)
|
||||
override val sortOrders: Set<SortOrder> = EnumSet.allOf(SortOrder::class.java)
|
||||
|
||||
private val mutex = Mutex()
|
||||
private var tagCache: Map<String, MangaTag>? = null
|
||||
|
||||
override suspend fun getDetails(manga: Manga): Manga {
|
||||
val docs = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml()
|
||||
val infoHeaderEl = docs.selectFirst("main.section-body")
|
||||
val infoEl = docs.selectFirst("main.section-body .series-information")
|
||||
val tags = infoEl?.select(".info-item:contains(Thể loại) > .info-value > a")?.mapNotNullToSet {
|
||||
getOrCreateTagMap()[it.text().trim()]
|
||||
}
|
||||
val state = when (infoEl?.selectFirst(".info-item:contains(Tình trạng) > .info-value")?.text()) {
|
||||
"Đang tiến hành" -> MangaState.ONGOING
|
||||
"Đã hoàn thành" -> MangaState.FINISHED
|
||||
else -> null
|
||||
}
|
||||
val rating = infoHeaderEl?.let {
|
||||
val like = it.selectFirst("#like .block.feature-name")?.text()?.toIntOrNull()
|
||||
val disLike = it.selectFirst("#dislike .block.feature-name")?.text()?.toIntOrNull()
|
||||
when {
|
||||
like == null || disLike == null -> RATING_UNKNOWN
|
||||
like == 0 && disLike == 0 -> RATING_UNKNOWN
|
||||
else -> like.toFloat() / (like + disLike)
|
||||
}
|
||||
}
|
||||
val chapterDateFormat = SimpleDateFormat("dd/MM/yyyy", Locale.US)
|
||||
|
||||
return manga.copy(
|
||||
altTitle = infoEl?.selectFirst(".info-item:contains(Tên khác) > .info-value")?.text(),
|
||||
author = infoEl?.select(".info-item:contains(Tác giả) > .info-value")?.joinToString { it.text() },
|
||||
tags = tags ?: emptySet(),
|
||||
state = state,
|
||||
rating = rating ?: RATING_UNKNOWN,
|
||||
description = infoHeaderEl?.selectFirst(".series-summary .summary-content")?.html(),
|
||||
chapters = docs.select("ul.list-chapters.at-series > a").reversed().mapChapters { index, element ->
|
||||
MangaChapter(
|
||||
id = generateUid(element.attrAsRelativeUrl("href")),
|
||||
name = element.selectFirst(".chapter-name")?.text()?.trim().orEmpty(),
|
||||
number = index + 1,
|
||||
url = element.attrAsRelativeUrl("href"),
|
||||
scanlator = null,
|
||||
uploadDate = chapterDateFormat.tryParse(element.selectFirst(".chapter-time")?.text()),
|
||||
branch = null,
|
||||
source = source,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun getListPage(
|
||||
page: Int,
|
||||
query: String?,
|
||||
tags: Set<MangaTag>?,
|
||||
sortOrder: SortOrder,
|
||||
): List<Manga> {
|
||||
val sortQuery = when (sortOrder) {
|
||||
SortOrder.UPDATED -> "update"
|
||||
SortOrder.NEWEST -> "new"
|
||||
SortOrder.RATING -> "like"
|
||||
SortOrder.POPULARITY -> "top"
|
||||
SortOrder.ALPHABETICAL -> "az"
|
||||
}
|
||||
val url = urlBuilder().apply {
|
||||
addPathSegment("tim-kiem")
|
||||
addQueryParameter("sort", sortQuery)
|
||||
addQueryParameter("page", page.toString())
|
||||
if (!query.isNullOrEmpty()) {
|
||||
addQueryParameter("q", query)
|
||||
}
|
||||
if (!tags.isNullOrEmpty()) {
|
||||
val tagsQuery = tags.joinToString(separator = ",") { it.key }
|
||||
addEncodedQueryParameter("accept_genres", tagsQuery)
|
||||
}
|
||||
}.build()
|
||||
|
||||
return webClient.httpGet(url).parseHtml()
|
||||
.select(".container .card.card-dark .row > .thumb-item-flow")
|
||||
.mapNotNull {
|
||||
val a = it.selectFirstOrThrow(".thumb-wrapper a")
|
||||
Manga(
|
||||
id = generateUid(a.attrAsRelativeUrl("href")),
|
||||
url = a.attrAsRelativeUrl("href"),
|
||||
publicUrl = a.attrAsAbsoluteUrl("href"),
|
||||
title = it.select(".thumb_attr.series-title").text(),
|
||||
altTitle = null,
|
||||
rating = RATING_UNKNOWN,
|
||||
isNsfw = false,
|
||||
coverUrl = a.selectFirst("div[data-bg]")?.attrAsAbsoluteUrl("data-bg").orEmpty(),
|
||||
tags = emptySet(),
|
||||
state = null,
|
||||
author = null,
|
||||
source = source,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
|
||||
val url = chapter.url.toAbsoluteUrl(domain)
|
||||
return webClient.httpGet(url).parseHtml().select("#chapter-content > img").mapNotNull {
|
||||
val imageUrl = it.attrAsRelativeUrlOrNull("data-src")
|
||||
?: it.attrAsRelativeUrlOrNull("src")
|
||||
?: return@mapNotNull null
|
||||
MangaPage(
|
||||
id = generateUid(imageUrl),
|
||||
url = imageUrl,
|
||||
referer = url,
|
||||
preview = null,
|
||||
source = source,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getTags(): Set<MangaTag> {
|
||||
return ArraySet(getOrCreateTagMap().values)
|
||||
}
|
||||
|
||||
private suspend fun getOrCreateTagMap(): Map<String, MangaTag> = mutex.withLock {
|
||||
tagCache?.let { return it }
|
||||
val docs = webClient.httpGet("/tim-kiem".toAbsoluteUrl(domain)).parseHtml()
|
||||
val tags = docs.select(".search-border-left .row > .search-gerne_item").mapNotNull {
|
||||
MangaTag(
|
||||
title = it.text().trim(),
|
||||
key = it.selectFirst("label[data-genre-id]")
|
||||
?.attr("data-genre-id")
|
||||
?.trim() ?: return@mapNotNull null,
|
||||
source = source,
|
||||
)
|
||||
}
|
||||
val tagMap = tags.associateByTo(ArrayMap(tags.size)) { it.title }
|
||||
tagCache = tagMap
|
||||
return tagMap
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue