|
|
|
|
@ -10,9 +10,7 @@ import org.koitharu.kotatsu.parsers.util.*
|
|
|
|
|
import org.koitharu.kotatsu.parsers.util.json.*
|
|
|
|
|
import java.text.SimpleDateFormat
|
|
|
|
|
import java.util.*
|
|
|
|
|
import org.koitharu.kotatsu.parsers.Broken
|
|
|
|
|
|
|
|
|
|
@Broken("Changed API entities + paths")
|
|
|
|
|
@MangaSourceParser("MIMIHENTAI", "MimiHentai", "vi", type = ContentType.HENTAI)
|
|
|
|
|
internal class MimiHentai(context: MangaLoaderContext) :
|
|
|
|
|
LegacyPagedMangaParser(context, MangaParserSource.MIMIHENTAI, 18) {
|
|
|
|
|
@ -36,7 +34,15 @@ internal class MimiHentai(context: MangaLoaderContext) :
|
|
|
|
|
keys.add(preferredServerKey)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED)
|
|
|
|
|
override val availableSortOrders: Set<SortOrder> = EnumSet.of(
|
|
|
|
|
SortOrder.UPDATED,
|
|
|
|
|
SortOrder.ALPHABETICAL,
|
|
|
|
|
SortOrder.POPULARITY,
|
|
|
|
|
SortOrder.POPULARITY_TODAY,
|
|
|
|
|
SortOrder.POPULARITY_WEEK,
|
|
|
|
|
SortOrder.POPULARITY_MONTH,
|
|
|
|
|
SortOrder.RATING,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
override val filterCapabilities: MangaListFilterCapabilities
|
|
|
|
|
get() = MangaListFilterCapabilities(
|
|
|
|
|
@ -55,10 +61,13 @@ internal class MimiHentai(context: MangaLoaderContext) :
|
|
|
|
|
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilter): List<Manga> {
|
|
|
|
|
val url = buildString {
|
|
|
|
|
append("https://")
|
|
|
|
|
append(domain)
|
|
|
|
|
append("/$apiSuffix/advance-search?page=")
|
|
|
|
|
append(domain + "/" + apiSuffix)
|
|
|
|
|
|
|
|
|
|
if (!filter.query.isNullOrEmpty() || !filter.author.isNullOrEmpty() || filter.tags.isNotEmpty()) {
|
|
|
|
|
append("/advance-search?page=")
|
|
|
|
|
append(page)
|
|
|
|
|
append("&max=18") // page size, avoid rate limit
|
|
|
|
|
|
|
|
|
|
when {
|
|
|
|
|
!filter.query.isNullOrEmpty() -> {
|
|
|
|
|
append("&name=")
|
|
|
|
|
@ -75,6 +84,36 @@ internal class MimiHentai(context: MangaLoaderContext) :
|
|
|
|
|
append(filter.tags.joinToString(",") { it.key })
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
append("&sort=")
|
|
|
|
|
append(
|
|
|
|
|
when (order) {
|
|
|
|
|
SortOrder.UPDATED -> "updated_at"
|
|
|
|
|
SortOrder.ALPHABETICAL -> "title"
|
|
|
|
|
SortOrder.POPULARITY,
|
|
|
|
|
SortOrder.POPULARITY_TODAY,
|
|
|
|
|
SortOrder.POPULARITY_WEEK,
|
|
|
|
|
SortOrder.POPULARITY_MONTH -> "views"
|
|
|
|
|
SortOrder.RATING -> "likes"
|
|
|
|
|
else -> ""
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else {
|
|
|
|
|
append(
|
|
|
|
|
when (order) {
|
|
|
|
|
SortOrder.UPDATED -> "/tatcatruyen?page=$page&sort=updated_at"
|
|
|
|
|
SortOrder.ALPHABETICAL -> "/tatcatruyen?page=$page&sort=title"
|
|
|
|
|
SortOrder.POPULARITY -> "/tatcatruyen?page=$page&sort=views"
|
|
|
|
|
SortOrder.POPULARITY_TODAY -> "/top-manga?page=$page&timeType=1&limit=18"
|
|
|
|
|
SortOrder.POPULARITY_WEEK -> "/top-manga?page=$page&timeType=2&limit=18"
|
|
|
|
|
SortOrder.POPULARITY_MONTH -> "/top-manga?page=$page&timeType=3&limit=18"
|
|
|
|
|
SortOrder.RATING -> "/tatcatruyen?page=$page&sort=likes"
|
|
|
|
|
else -> "/tatcatruyen?page=$page&sort=updated_at" // default
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
val json = webClient.httpGet(url).parseJson()
|
|
|
|
|
@ -85,16 +124,37 @@ internal class MimiHentai(context: MangaLoaderContext) :
|
|
|
|
|
private fun parseMangaList(data: JSONArray): List<Manga> {
|
|
|
|
|
return data.mapJSON { jo ->
|
|
|
|
|
val id = jo.getLong("id")
|
|
|
|
|
val title = jo.getString("title")
|
|
|
|
|
val title = jo.getString("title").takeIf { it.isNotEmpty() } ?: "Web chưa đặt tên"
|
|
|
|
|
val description = jo.getStringOrNull("description")
|
|
|
|
|
val authors = jo.getJSONArray("authors").asTypedList<String>().toSet()
|
|
|
|
|
val differentNames = jo.getJSONArray("differentNames").asTypedList<String>().toSet()
|
|
|
|
|
|
|
|
|
|
val differentNames = mutableSetOf<String>().apply {
|
|
|
|
|
jo.optJSONArray("differentNames")?.let { namesArray ->
|
|
|
|
|
for (i in 0 until namesArray.length()) {
|
|
|
|
|
namesArray.optString(i)?.takeIf { it.isNotEmpty() }?.let { name ->
|
|
|
|
|
add(name)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
val state = when (description) {
|
|
|
|
|
"Đang Tiến Hành" -> MangaState.ONGOING
|
|
|
|
|
"Hoàn Thành" -> MangaState.FINISHED
|
|
|
|
|
else -> null
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
val authors = jo.getJSONArray("authors").mapJSON {
|
|
|
|
|
it.getString("name")
|
|
|
|
|
}.toSet()
|
|
|
|
|
|
|
|
|
|
val tags = jo.getJSONArray("genres").mapJSON { genre ->
|
|
|
|
|
MangaTag(
|
|
|
|
|
key = genre.getLong("id").toString(),
|
|
|
|
|
title = genre.getString("name"),
|
|
|
|
|
source = source
|
|
|
|
|
)
|
|
|
|
|
}.toSet()
|
|
|
|
|
|
|
|
|
|
Manga(
|
|
|
|
|
id = generateUid(id),
|
|
|
|
|
title = title,
|
|
|
|
|
@ -104,7 +164,7 @@ internal class MimiHentai(context: MangaLoaderContext) :
|
|
|
|
|
rating = RATING_UNKNOWN,
|
|
|
|
|
contentRating = ContentRating.ADULT,
|
|
|
|
|
coverUrl = jo.getString("coverUrl"),
|
|
|
|
|
tags = emptySet(),
|
|
|
|
|
tags = tags,
|
|
|
|
|
state = state,
|
|
|
|
|
authors = authors,
|
|
|
|
|
source = source,
|
|
|
|
|
@ -115,9 +175,11 @@ internal class MimiHentai(context: MangaLoaderContext) :
|
|
|
|
|
override suspend fun getDetails(manga: Manga): Manga {
|
|
|
|
|
val url = manga.url.toAbsoluteUrl(domain)
|
|
|
|
|
val json = webClient.httpGet(url).parseJson()
|
|
|
|
|
val id = json.getLong("id")
|
|
|
|
|
val description = json.getStringOrNull("description")
|
|
|
|
|
val uploaderName = json.getJSONObject("uploader").getString("displayName")
|
|
|
|
|
|
|
|
|
|
val relationInfo = json.getJSONObject("relationInfo")
|
|
|
|
|
val tags = relationInfo.getJSONArray("genres").mapJSONToSet { jo ->
|
|
|
|
|
val tags = json.getJSONArray("genres").mapJSONToSet { jo ->
|
|
|
|
|
MangaTag(
|
|
|
|
|
title = jo.getString("name").toTitleCase(sourceLocale),
|
|
|
|
|
key = jo.getLong("id").toString(),
|
|
|
|
|
@ -125,10 +187,6 @@ internal class MimiHentai(context: MangaLoaderContext) :
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
val basicInfo = json.getJSONObject("basicInfo")
|
|
|
|
|
val id = basicInfo.getLong("id")
|
|
|
|
|
val description = basicInfo.getStringOrNull("description")
|
|
|
|
|
val uploaderName = json.getStringOrNull("uploaderName")
|
|
|
|
|
val urlChaps = "https://$domain/$apiSuffix/gallery/$id"
|
|
|
|
|
val parsedChapters = webClient.httpGet(urlChaps).parseJsonArray()
|
|
|
|
|
val dateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSS", Locale.US)
|
|
|
|
|
|