From 99a153304d30848d5677bf86801e85def6c6dc1a Mon Sep 17 00:00:00 2001 From: are-are-are <62763969+dejavui@users.noreply.github.com> Date: Fri, 25 Jul 2025 23:03:26 +0700 Subject: [PATCH] MiMiHentai: Advanced Search (#9773) * Advanced Search * Add if search * Update src/vi/mimihentai/src/eu/kanade/tachiyomi/extension/vi/mimihentai/MiMiHentai.kt Co-authored-by: stevenyomi <95685115+stevenyomi@users.noreply.github.com> * Fix build * Apply suggestion * Complete Advanced Search * Revert "Complete Advanced Search" This reverts commit 25a77c5d9be035f64fe5d9e418686830fb41cde8. * Delete hs_err_pid25072.log * Advanced Search * suggestion * Revert not apply suggestion because Inefficient * Update MiMiHentai.kt * Apply suggestion --------- Co-authored-by: stevenyomi <95685115+stevenyomi@users.noreply.github.com> --- src/vi/mimihentai/build.gradle | 2 +- .../tachiyomi/extension/vi/mimihentai/Dto.kt | 6 ++ .../extension/vi/mimihentai/MiMiHentai.kt | 71 ++++++++++++++++--- 3 files changed, 69 insertions(+), 10 deletions(-) diff --git a/src/vi/mimihentai/build.gradle b/src/vi/mimihentai/build.gradle index 7f7ee97c3..a3737d38e 100644 --- a/src/vi/mimihentai/build.gradle +++ b/src/vi/mimihentai/build.gradle @@ -1,7 +1,7 @@ ext { extName = "MiMiHentai" extClass = ".MiMiHentai" - extVersionCode = 1 + extVersionCode = 2 isNsfw = true } apply from: "$rootDir/common.gradle" diff --git a/src/vi/mimihentai/src/eu/kanade/tachiyomi/extension/vi/mimihentai/Dto.kt b/src/vi/mimihentai/src/eu/kanade/tachiyomi/extension/vi/mimihentai/Dto.kt index bc8d6662b..7a8846146 100644 --- a/src/vi/mimihentai/src/eu/kanade/tachiyomi/extension/vi/mimihentai/Dto.kt +++ b/src/vi/mimihentai/src/eu/kanade/tachiyomi/extension/vi/mimihentai/Dto.kt @@ -62,3 +62,9 @@ private val dateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSS", Locale class PageListDto( val pages: List, ) + +@Serializable +class Genres( + val id: Long, + val name: String, +) diff --git a/src/vi/mimihentai/src/eu/kanade/tachiyomi/extension/vi/mimihentai/MiMiHentai.kt b/src/vi/mimihentai/src/eu/kanade/tachiyomi/extension/vi/mimihentai/MiMiHentai.kt index 809e384d0..128a037b6 100644 --- a/src/vi/mimihentai/src/eu/kanade/tachiyomi/extension/vi/mimihentai/MiMiHentai.kt +++ b/src/vi/mimihentai/src/eu/kanade/tachiyomi/extension/vi/mimihentai/MiMiHentai.kt @@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.extension.vi.mimihentai import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.asObservableSuccess +import eu.kanade.tachiyomi.network.await import eu.kanade.tachiyomi.network.interceptor.rateLimit import eu.kanade.tachiyomi.source.model.Filter import eu.kanade.tachiyomi.source.model.FilterList @@ -11,6 +12,9 @@ import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.online.HttpSource import keiyoushi.utils.parseAs +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.OkHttpClient import okhttp3.Request @@ -38,7 +42,7 @@ class MiMiHentai : HttpSource() { override fun latestUpdatesRequest(page: Int): Request = GET( apiUrl.toHttpUrl().newBuilder().apply { addPathSegments("tatcatruyen") - addQueryParameter("page", page.toString()) + addQueryParameter("page", (page - 1).toString()) addQueryParameter("sort", "updated_at") }.build(), headers, @@ -106,7 +110,7 @@ class MiMiHentai : HttpSource() { override fun popularMangaRequest(page: Int): Request = GET( apiUrl.toHttpUrl().newBuilder().apply { addPathSegments("tatcatruyen") - addQueryParameter("page", page.toString()) + addQueryParameter("page", (page - 1).toString()) addQueryParameter("sort", "views") }.build(), headers, @@ -139,10 +143,12 @@ class MiMiHentai : HttpSource() { override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { val url = apiUrl.toHttpUrl().newBuilder().apply { - addPathSegments("search") - addQueryParameter("page", page.toString()) + addPathSegments("advance-search") + addQueryParameter("author", "") + addQueryParameter("character", "") + addQueryParameter("parody", "") + addQueryParameter("page", (page - 1).toString()) addQueryParameter("name", query) - (if (filters.isEmpty()) getFilterList() else filters).forEach { filters -> when (filters) { is SortByList -> @@ -150,7 +156,10 @@ class MiMiHentai : HttpSource() { val sort = getSortByList()[filters.state] addQueryParameter("sort", sort.id) } - + is GenreList -> { + filters.state.forEach { genre -> if (genre.state) addQueryParameter("genre", genre.id) } + } + is TextField -> setQueryParameter(filters.key, filters.state) else -> {} } } @@ -158,6 +167,38 @@ class MiMiHentai : HttpSource() { return GET(url, headers) } + private fun genresRequest(): Request = GET("$apiUrl/genres", headers) + + private fun parseGenres(response: Response): List> { + return response.parseAs>().map { Pair(it.id, it.name) } + } + + private var fetchGenresAttempts: Int = 0 + private fun fetchGenres() { + if (fetchGenresAttempts >= 3 || genreList.isEmpty()) { + launchIO { + try { + client.newCall(genresRequest()).await() + .use { parseGenres(it) } + .takeIf { it.isNotEmpty() } + ?.also { genreList = it } + } catch (_: Exception) { + } finally { + fetchGenresAttempts++ + } + } + } + } + + private fun launchIO(block: suspend () -> Unit) = GlobalScope.launch(Dispatchers.IO) { block() } + + private var genreList: List> = emptyList() + + private class GenreList(name: String, pairs: List>) : GenresFilter(name, pairs) + private open class GenresFilter(title: String, pairs: List>) : + Filter.Group(title, pairs.map { GenreCheckBox(it.second, it.first.toString()) }) + class GenreCheckBox(name: String, val id: String = name) : Filter.CheckBox(name) + private class SortByList(sort: Array) : Filter.Select("Sắp xếp", sort) private class SortBy(name: String, val id: String) : Filter.CheckBox(name) { override fun toString(): String { @@ -165,9 +206,21 @@ class MiMiHentai : HttpSource() { } } - override fun getFilterList() = FilterList( - SortByList(getSortByList()), - ) + private class TextField(name: String, val key: String) : Filter.Text(name) + override fun getFilterList(): FilterList { + fetchGenres() + return FilterList( + SortByList(getSortByList()), + TextField("Tác giả", "author"), + TextField("Parody", "parody"), + TextField("Nhân vật", "character"), + if (genreList.isEmpty()) { + Filter.Header("Nhấn 'Làm mới' để thử tải thể loại") + } else { + GenreList("Thể loại", genreList) + }, + ) + } private fun getSortByList() = arrayOf( SortBy("Mới", "updated_at"),