From cb623b7e852cb08e6a563a0a5de39aa32bd952a2 Mon Sep 17 00:00:00 2001 From: gtament Date: Thu, 21 Nov 2024 03:22:25 +0200 Subject: [PATCH] Review fixes for KunMangaTo. Also refactored filters a bit --- .../extension/en/kunmangato/KunMangaTo.kt | 126 +++++------------- ...o.kt => KunMangaToChapterResourcesDtos.kt} | 4 +- .../en/kunmangato/KunMangaToFilters.kt | 13 ++ .../extension/en/kunmangato/UriPartFilter.kt | 9 +- 4 files changed, 56 insertions(+), 96 deletions(-) rename src/en/kunmangato/src/eu/kanade/tachiyomi/extension/en/kunmangato/{KunMangaToChapterResourcesDto.kt => KunMangaToChapterResourcesDtos.kt} (82%) create mode 100644 src/en/kunmangato/src/eu/kanade/tachiyomi/extension/en/kunmangato/KunMangaToFilters.kt diff --git a/src/en/kunmangato/src/eu/kanade/tachiyomi/extension/en/kunmangato/KunMangaTo.kt b/src/en/kunmangato/src/eu/kanade/tachiyomi/extension/en/kunmangato/KunMangaTo.kt index cf986e0b6..c8f78c55c 100644 --- a/src/en/kunmangato/src/eu/kanade/tachiyomi/extension/en/kunmangato/KunMangaTo.kt +++ b/src/en/kunmangato/src/eu/kanade/tachiyomi/extension/en/kunmangato/KunMangaTo.kt @@ -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().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 { val document = response.asJsoup() val chaptersDocument = - Jsoup.parse("
" + document.getElementById("chapterList")!!.attr("value") + "
") + Jsoup.parse("
" + document.selectFirst(chapterListSelector())!!.attr("value") + "
") 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(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, List>>? = null + private var filterValues: Map>? = null private var fetchFilterValuesAttempts: Int = 0 - private fun parseFilters(document: Document): Map, List>> { - return filterNames.associateBy( - { it }, - { - document.select("[name=\"${it.first}\"] option") - .map { option -> Pair(option.attr("value"), option.text()) } - }, - ) + private fun parseFilters(document: Document): Map> { + 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 { throw UnsupportedOperationException() } - - override fun latestUpdatesNextPageSelector(): String? { - throw UnsupportedOperationException() - } - - override fun popularMangaNextPageSelector(): String? { - throw UnsupportedOperationException() - } - - override fun searchMangaNextPageSelector(): String? { - throw UnsupportedOperationException() - } } diff --git a/src/en/kunmangato/src/eu/kanade/tachiyomi/extension/en/kunmangato/KunMangaToChapterResourcesDto.kt b/src/en/kunmangato/src/eu/kanade/tachiyomi/extension/en/kunmangato/KunMangaToChapterResourcesDtos.kt similarity index 82% rename from src/en/kunmangato/src/eu/kanade/tachiyomi/extension/en/kunmangato/KunMangaToChapterResourcesDto.kt rename to src/en/kunmangato/src/eu/kanade/tachiyomi/extension/en/kunmangato/KunMangaToChapterResourcesDtos.kt index e035939ef..7d8c4bfa8 100644 --- a/src/en/kunmangato/src/eu/kanade/tachiyomi/extension/en/kunmangato/KunMangaToChapterResourcesDto.kt +++ b/src/en/kunmangato/src/eu/kanade/tachiyomi/extension/en/kunmangato/KunMangaToChapterResourcesDtos.kt @@ -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, ) diff --git a/src/en/kunmangato/src/eu/kanade/tachiyomi/extension/en/kunmangato/KunMangaToFilters.kt b/src/en/kunmangato/src/eu/kanade/tachiyomi/extension/en/kunmangato/KunMangaToFilters.kt new file mode 100644 index 000000000..6943ec01d --- /dev/null +++ b/src/en/kunmangato/src/eu/kanade/tachiyomi/extension/en/kunmangato/KunMangaToFilters.kt @@ -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 diff --git a/src/en/kunmangato/src/eu/kanade/tachiyomi/extension/en/kunmangato/UriPartFilter.kt b/src/en/kunmangato/src/eu/kanade/tachiyomi/extension/en/kunmangato/UriPartFilter.kt index eb49e9df8..d485efa48 100644 --- a/src/en/kunmangato/src/eu/kanade/tachiyomi/extension/en/kunmangato/UriPartFilter.kt +++ b/src/en/kunmangato/src/eu/kanade/tachiyomi/extension/en/kunmangato/UriPartFilter.kt @@ -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>, -) : Filter.Select(displayName, vals.map { it.second }.toTypedArray()) { + private val filter: KunMangaToFilter, + private val vals: List, +) : Filter.Select(filter.name, vals.map { it.second }.toTypedArray()) { + fun toQueryParam() = filter.queryParam + fun toUriPart() = vals[state].first }