Review fixes for KunMangaTo. Also refactored filters a bit

This commit is contained in:
gtament 2024-11-21 03:22:25 +02:00
parent 5d52bddd7b
commit cb623b7e85
4 changed files with 56 additions and 96 deletions

View File

@ -13,7 +13,6 @@ import eu.kanade.tachiyomi.util.asJsoup
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import okhttp3.FormBody
import okhttp3.Headers
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Request
import okhttp3.Response
@ -38,31 +37,26 @@ class KunMangaTo : ParsedHttpSource() {
SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH)
}
override fun popularMangaRequest(page: Int): Request {
return GET(baseUrl)
}
override fun popularMangaRequest(page: Int): Request = GET(baseUrl, headers)
override fun popularMangaParse(response: Response): MangasPage {
val document = response.asJsoup()
val mangas = document.select(popularMangaSelector()).map { element ->
popularMangaFromElement(element)
}.associateBy({ it.url }, { it }).values.toList()
val mangas = super.popularMangaParse(response).mangas.distinctBy { it.url }
return MangasPage(mangas, false)
}
override fun popularMangaSelector(): String {
return ".sidebar-box-popular article"
}
override fun popularMangaSelector(): String = ".sidebar-box-popular article"
override fun popularMangaFromElement(element: Element): SManga {
val a = element.select("a.manga").first()!!
val a = element.selectFirst("a.manga")!!
return SManga.create().apply {
title = a.text()
url = a.attr("href").removePrefix(baseUrl)
thumbnail_url = element.select("img").first()!!.attr("src")
thumbnail_url = element.selectFirst("img")!!.attr("src")
}
}
override fun popularMangaNextPageSelector(): String? = null
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
val urlBuilder = "$baseUrl/search".toHttpUrl().newBuilder()
.addQueryParameter("term", query.trim())
@ -70,86 +64,63 @@ class KunMangaTo : ParsedHttpSource() {
filters.filterIsInstance<UriPartFilter>().forEach { filter ->
urlBuilder.addQueryParameter(
filter.internalName,
filter.toQueryParam(),
filter.toUriPart(),
)
}
return GET(urlBuilder.build())
return GET(urlBuilder.build(), headers)
}
override fun searchMangaParse(response: Response): MangasPage {
val document = response.asJsoup()
val mangas = document.select(searchMangaSelector()).map { element ->
searchMangaFromElement(element)
}
val nextPageElement = document.select(".pagination .page-item").last()
return MangasPage(
mangas,
nextPageElement?.hasClass("disabled")?.not() ?: false,
)
}
override fun searchMangaSelector(): String {
return "article .card-manga"
}
override fun searchMangaSelector(): String = "article .card-manga"
override fun searchMangaFromElement(element: Element): SManga = popularMangaFromElement(element)
override fun searchMangaNextPageSelector(): String = "ul.pagination-primary a[rel=next]"
override fun latestUpdatesRequest(page: Int): Request {
val urlBuilder = "$baseUrl/latest".toHttpUrl().newBuilder()
.addQueryParameter("page", page.toString())
return GET(urlBuilder.build())
}
override fun latestUpdatesParse(response: Response): MangasPage {
val document = response.asJsoup()
val mangas = document.select(latestUpdatesSelector()).map { element ->
latestUpdatesFromElement(element)
}
val nextPageElement = document.select(".pagination .page-item").last()
return MangasPage(
mangas,
nextPageElement?.hasClass("disabled")?.not() ?: false,
)
return GET(urlBuilder.build(), headers)
}
override fun latestUpdatesSelector(): String = searchMangaSelector()
override fun latestUpdatesFromElement(element: Element) = searchMangaFromElement(element)
override fun latestUpdatesNextPageSelector(): String = searchMangaNextPageSelector()
override fun mangaDetailsParse(document: Document): SManga {
return SManga.create().apply {
title = document.select(".page-heading").first()!!.text()
author = document.select("p.mb-1:nth-child(1)").first()!!.text().drop(9)
title = document.selectFirst(".page-heading")!!.text()
author = document.selectFirst("p.mb-1:nth-child(1)")!!.text().drop(9)
description = document.getElementById("manga-description")!!.text()
genre =
document.select("a.manga-genre").joinToString(", ") { element -> element.text() }
status =
if (document.select(".text-success").size > 0) SManga.COMPLETED else SManga.ONGOING
thumbnail_url = document.select("img.text-end").first()!!.attr("src")
thumbnail_url = document.selectFirst("img.text-end")!!.attr("src")
}
}
override fun chapterListParse(response: Response): List<SChapter> {
val document = response.asJsoup()
val chaptersDocument =
Jsoup.parse("<div>" + document.getElementById("chapterList")!!.attr("value") + "</div>")
Jsoup.parse("<div>" + document.selectFirst(chapterListSelector())!!.attr("value") + "</div>")
val chapterItems = chaptersDocument.select(".chapter-item")
return chapterItems.map { element ->
chapterFromElement(element)
}
}
override fun chapterFromElement(element: Element): SChapter {
val chapterName = element.getElementsByTag("h3").first()!!.text()
override fun chapterListSelector(): String = "#chapterList"
override fun chapterFromElement(element: Element): SChapter {
return SChapter.create().apply {
url = element.getElementsByTag("a").first()!!.attr("href").removePrefix(baseUrl)
name = chapterName
date_upload = element.select(".text-muted").first()!!.text().parseChapterDate()
chapter_number = chapterName.removePrefix("Chapter ").toFloat()
name = element.getElementsByTag("h3").first()!!.text()
date_upload = element.selectFirst(".text-muted")!!.text().parseChapterDate()
}
}
@ -170,44 +141,36 @@ class KunMangaTo : ParsedHttpSource() {
response.request.url.toString().substringBefore(".html").substringAfterLast("-"),
)
.build()
val chaptersRequest = POST(
"$baseUrl/chapter-resources",
Headers.headersOf(
headers.newBuilder().add(
"X-CSRF-TOKEN",
document.select("head > meta[name=\"csrf-token\"]").first()!!.attr("content"),
document.selectFirst("head > meta[name=\"csrf-token\"]")!!.attr("content"),
).add(
"Cookie",
response.headers.values("set-cookie")
.find { value -> value.startsWith("kunmanga_session") }!!,
),
).build(),
form,
)
val chaptersResponse = client.newCall(chaptersRequest).execute()
val chapterResources =
json.decodeFromString<KunMangaToChapterResourcesDto>(chaptersResponse.body.string())
return chapterResources.data.resources.map { resource ->
Page(
resource.id,
"",
resource.thumb,
)
Page(resource.id, imageUrl = resource.thumb)
}
}
private val filterNames =
arrayOf("manga_genre_id" to "Genre", "manga_type_id" to "Type", "status" to "Status")
private var filterValues: Map<Pair<String, String>, List<Pair<String, String>>>? = null
private var filterValues: Map<KunMangaToFilter, List<OptionValueOptionNamePair>>? = null
private var fetchFilterValuesAttempts: Int = 0
private fun parseFilters(document: Document): Map<Pair<String, String>, List<Pair<String, String>>> {
return filterNames.associateBy(
{ it },
{
document.select("[name=\"${it.first}\"] option")
.map { option -> Pair(option.attr("value"), option.text()) }
},
)
private fun parseFilters(document: Document): Map<KunMangaToFilter, List<OptionValueOptionNamePair>> {
return KunMangaToFilter.values().associateWith {
document.select("[name=\"${it.queryParam}\"] option")
.map { option -> option.attr("value") to option.text() }
}
}
private fun fetchFiltersValues() {
@ -230,8 +193,7 @@ class KunMangaTo : ParsedHttpSource() {
FilterList(
filterValues!!.map { filterValue ->
UriPartFilter(
filterValue.key.second,
filterValue.key.first,
filterValue.key,
filterValue.value,
)
},
@ -245,23 +207,7 @@ class KunMangaTo : ParsedHttpSource() {
throw UnsupportedOperationException()
}
override fun chapterListSelector(): String {
throw UnsupportedOperationException()
}
override fun pageListParse(document: Document): List<Page> {
throw UnsupportedOperationException()
}
override fun latestUpdatesNextPageSelector(): String? {
throw UnsupportedOperationException()
}
override fun popularMangaNextPageSelector(): String? {
throw UnsupportedOperationException()
}
override fun searchMangaNextPageSelector(): String? {
throw UnsupportedOperationException()
}
}

View File

@ -3,13 +3,13 @@ package eu.kanade.tachiyomi.extension.en.kunmangato
import kotlinx.serialization.Serializable
@Serializable
data class KunMangaToChapterResourcesDto(
class KunMangaToChapterResourcesDto(
val status: Int,
val data: KunMangaToDataDto,
)
@Serializable
data class KunMangaToDataDto(
class KunMangaToDataDto(
val resources: List<KunMangaToResourceDto>,
)

View File

@ -0,0 +1,13 @@
package eu.kanade.tachiyomi.extension.en.kunmangato
enum class KunMangaToFilter(val queryParam: String) {
Genre("manga_genre_id"),
Type("manga_type_id"),
Status("status"),
}
typealias OptionName = String
typealias OptionValue = String
typealias OptionValueOptionNamePair = Pair<OptionValue, OptionName>

View File

@ -3,9 +3,10 @@ package eu.kanade.tachiyomi.extension.en.kunmangato
import eu.kanade.tachiyomi.source.model.Filter
open class UriPartFilter(
displayName: String,
val internalName: String,
private val vals: List<Pair<String, String>>,
) : Filter.Select<String>(displayName, vals.map { it.second }.toTypedArray()) {
private val filter: KunMangaToFilter,
private val vals: List<OptionValueOptionNamePair>,
) : Filter.Select<String>(filter.name, vals.map { it.second }.toTypedArray()) {
fun toQueryParam() = filter.queryParam
fun toUriPart() = vals[state].first
}