From 5d52bddd7b1c27d9f889211257ae7453ac3584f0 Mon Sep 17 00:00:00 2001 From: gtament Date: Wed, 20 Nov 2024 23:10:34 +0200 Subject: [PATCH 1/2] Add KunMangaTo source --- src/en/kunmangato/build.gradle | 7 + .../res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 3836 bytes .../res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 1948 bytes .../res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 5910 bytes .../res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 11706 bytes .../res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 18723 bytes .../extension/en/kunmangato/KunMangaTo.kt | 267 ++++++++++++++++++ .../KunMangaToChapterResourcesDto.kt | 21 ++ .../extension/en/kunmangato/UriPartFilter.kt | 11 + 9 files changed, 306 insertions(+) create mode 100644 src/en/kunmangato/build.gradle create mode 100644 src/en/kunmangato/res/mipmap-hdpi/ic_launcher.png create mode 100644 src/en/kunmangato/res/mipmap-mdpi/ic_launcher.png create mode 100644 src/en/kunmangato/res/mipmap-xhdpi/ic_launcher.png create mode 100644 src/en/kunmangato/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 src/en/kunmangato/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 src/en/kunmangato/src/eu/kanade/tachiyomi/extension/en/kunmangato/KunMangaTo.kt create mode 100644 src/en/kunmangato/src/eu/kanade/tachiyomi/extension/en/kunmangato/KunMangaToChapterResourcesDto.kt create mode 100644 src/en/kunmangato/src/eu/kanade/tachiyomi/extension/en/kunmangato/UriPartFilter.kt diff --git a/src/en/kunmangato/build.gradle b/src/en/kunmangato/build.gradle new file mode 100644 index 00000000000..f6ebb4c211c --- /dev/null +++ b/src/en/kunmangato/build.gradle @@ -0,0 +1,7 @@ +ext { + extName = 'KunMangaTo' + extClass = '.KunMangaTo' + extVersionCode = 1 +} + +apply from: "$rootDir/common.gradle" diff --git a/src/en/kunmangato/res/mipmap-hdpi/ic_launcher.png b/src/en/kunmangato/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..5fb609c1b8be5f1b44ec09f0f3067d5f378c3106 GIT binary patch literal 3836 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 literal 0 HcmV?d00001 diff --git a/src/en/kunmangato/res/mipmap-xxhdpi/ic_launcher.png b/src/en/kunmangato/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..77eada0c407dc7e66584e445df4a9752bf6d50e3 GIT binary patch literal 11706 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୏Tg-fz8a4viiy6G% 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 Q9DW2`a`!>hUku9n8*t>FW&i*H literal 0 HcmV?d00001 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 new file mode 100644 index 00000000000..cf986e0b61b --- /dev/null +++ b/src/en/kunmangato/src/eu/kanade/tachiyomi/extension/en/kunmangato/KunMangaTo.kt @@ -0,0 +1,267 @@ +package eu.kanade.tachiyomi.extension.en.kunmangato + +import eu.kanade.tachiyomi.network.GET +import eu.kanade.tachiyomi.network.POST +import eu.kanade.tachiyomi.source.model.Filter +import eu.kanade.tachiyomi.source.model.FilterList +import eu.kanade.tachiyomi.source.model.MangasPage +import eu.kanade.tachiyomi.source.model.Page +import eu.kanade.tachiyomi.source.model.SChapter +import eu.kanade.tachiyomi.source.model.SManga +import eu.kanade.tachiyomi.source.online.ParsedHttpSource +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 +import org.jsoup.Jsoup +import org.jsoup.nodes.Document +import org.jsoup.nodes.Element +import uy.kohesive.injekt.injectLazy +import java.text.ParseException +import java.text.SimpleDateFormat +import java.util.Locale +import kotlin.concurrent.thread + +class KunMangaTo : ParsedHttpSource() { + override val name = "KunMangaTo" + override val baseUrl = "https://kunmanga.to" + override val lang = "en" + override val supportsLatest = true + + private val json: Json by injectLazy() + + private val dateFormat by lazy { + SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH) + } + + override fun popularMangaRequest(page: Int): Request { + return GET(baseUrl) + } + + 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() + return MangasPage(mangas, false) + } + + override fun popularMangaSelector(): String { + return ".sidebar-box-popular article" + } + + override fun popularMangaFromElement(element: Element): SManga { + val a = element.select("a.manga").first()!! + return SManga.create().apply { + title = a.text() + url = a.attr("href").removePrefix(baseUrl) + thumbnail_url = element.select("img").first()!!.attr("src") + } + } + + override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { + val urlBuilder = "$baseUrl/search".toHttpUrl().newBuilder() + .addQueryParameter("term", query.trim()) + .addQueryParameter("page", page.toString()) + + filters.filterIsInstance().forEach { filter -> + urlBuilder.addQueryParameter( + filter.internalName, + filter.toUriPart(), + ) + } + + return GET(urlBuilder.build()) + } + + 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 searchMangaFromElement(element: Element): SManga = popularMangaFromElement(element) + + 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, + ) + } + + override fun latestUpdatesSelector(): String = searchMangaSelector() + + override fun latestUpdatesFromElement(element: Element) = searchMangaFromElement(element) + + 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) + 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") + } + } + + override fun chapterListParse(response: Response): List { + val document = response.asJsoup() + val chaptersDocument = + Jsoup.parse("
" + document.getElementById("chapterList")!!.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() + + 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() + } + } + + private fun String?.parseChapterDate(): Long { + if (this == null) return 0L + return try { + dateFormat.parse(this)!!.time + } catch (_: ParseException) { + 0L + } + } + + override fun pageListParse(response: Response): List { + val document = response.asJsoup() + val form = FormBody.Builder() + .add( + "chapterIdx", + response.request.url.toString().substringBefore(".html").substringAfterLast("-"), + ) + .build() + val chaptersRequest = POST( + "$baseUrl/chapter-resources", + Headers.headersOf( + "X-CSRF-TOKEN", + document.select("head > meta[name=\"csrf-token\"]").first()!!.attr("content"), + "Cookie", + response.headers.values("set-cookie") + .find { value -> value.startsWith("kunmanga_session") }!!, + ), + 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, + ) + } + } + + 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 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 fetchFiltersValues() { + if (fetchFilterValuesAttempts < 3 && filterValues == null) { + thread { + try { + filterValues = parseFilters( + client.newCall(searchMangaRequest(1, "", FilterList())).execute().asJsoup(), + ) + } finally { + fetchFilterValuesAttempts++ + } + } + } + } + + override fun getFilterList(): FilterList { + fetchFiltersValues() + return if (filterValues != null) { + FilterList( + filterValues!!.map { filterValue -> + UriPartFilter( + filterValue.key.second, + filterValue.key.first, + filterValue.value, + ) + }, + ) + } else { + FilterList(Filter.Header("Press 'Reset' to attempt to fetch the filters")) + } + } + + override fun imageUrlParse(document: Document): String { + 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/KunMangaToChapterResourcesDto.kt new file mode 100644 index 00000000000..e035939ef12 --- /dev/null +++ b/src/en/kunmangato/src/eu/kanade/tachiyomi/extension/en/kunmangato/KunMangaToChapterResourcesDto.kt @@ -0,0 +1,21 @@ +package eu.kanade.tachiyomi.extension.en.kunmangato + +import kotlinx.serialization.Serializable + +@Serializable +data class KunMangaToChapterResourcesDto( + val status: Int, + val data: KunMangaToDataDto, +) + +@Serializable +data class KunMangaToDataDto( + val resources: List, +) + +@Serializable +class KunMangaToResourceDto( + val id: Int, + val name: Int, + val thumb: String, +) 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 new file mode 100644 index 00000000000..eb49e9df897 --- /dev/null +++ b/src/en/kunmangato/src/eu/kanade/tachiyomi/extension/en/kunmangato/UriPartFilter.kt @@ -0,0 +1,11 @@ +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()) { + fun toUriPart() = vals[state].first +} From cb623b7e852cb08e6a563a0a5de39aa32bd952a2 Mon Sep 17 00:00:00 2001 From: gtament Date: Thu, 21 Nov 2024 03:22:25 +0200 Subject: [PATCH 2/2] 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 cf986e0b61b..c8f78c55c29 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()) - } - - 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, - ) + return GET(urlBuilder.build(), headers) } - 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 e035939ef12..7d8c4bfa890 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 00000000000..6943ec01d80 --- /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 eb49e9df897..d485efa48a2 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 }