Cứu Truyện: Improve search query with multiple tags (#2171)

master
Draken 8 months ago committed by GitHub
parent fe5534b006
commit 3e2515ac6a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -7,7 +7,7 @@ import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Interceptor import okhttp3.Interceptor
import okhttp3.Response import okhttp3.Response
import okio.IOException import okio.IOException
import org.jsoup.HttpStatusException import org.koitharu.kotatsu.parsers.ErrorMessages
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.bitmap.Bitmap import org.koitharu.kotatsu.parsers.bitmap.Bitmap
@ -18,7 +18,6 @@ import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.network.UserAgents import org.koitharu.kotatsu.parsers.network.UserAgents
import org.koitharu.kotatsu.parsers.util.* import org.koitharu.kotatsu.parsers.util.*
import org.koitharu.kotatsu.parsers.util.json.* import org.koitharu.kotatsu.parsers.util.json.*
import java.net.HttpURLConnection
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
@ -26,6 +25,7 @@ import java.util.*
internal class CuuTruyenParser(context: MangaLoaderContext) : internal class CuuTruyenParser(context: MangaLoaderContext) :
PagedMangaParser(context, MangaParserSource.CUUTRUYEN, 20) { PagedMangaParser(context, MangaParserSource.CUUTRUYEN, 20) {
private val apiSuffix = "/api/v2"
override val userAgentKey = ConfigKey.UserAgent(UserAgents.KOTATSU) override val userAgentKey = ConfigKey.UserAgent(UserAgents.KOTATSU)
override val configKeyDomain = ConfigKey.Domain( override val configKeyDomain = ConfigKey.Domain(
@ -52,6 +52,8 @@ internal class CuuTruyenParser(context: MangaLoaderContext) :
override val filterCapabilities: MangaListFilterCapabilities override val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities( get() = MangaListFilterCapabilities(
isSearchSupported = true, isSearchSupported = true,
isSearchWithFiltersSupported = true,
isMultipleTagsSupported = true,
) )
override suspend fun getFilterOptions(): MangaListFilterOptions { override suspend fun getFilterOptions(): MangaListFilterOptions {
@ -63,42 +65,55 @@ internal class CuuTruyenParser(context: MangaLoaderContext) :
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilter): List<Manga> { override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilter): List<Manga> {
val url = buildString { val url = buildString {
append("https://") if (!filter.query.isNullOrEmpty() || filter.tags.isNotEmpty() || filter.states.isNotEmpty()) {
append(domain) append("/mangas/search?q=")
when { if (!filter.query.isNullOrEmpty()) {
!filter.query.isNullOrEmpty() -> {
append("/api/v2/mangas/search?q=")
append(filter.query.urlEncoded()) append(filter.query.urlEncoded())
append("&page=")
append(page.toString())
} }
else -> { // Bug from API: Select both ONGOING + FINISHED will return empty list for all case
val tag = filter.tags.oneOrThrowIfMany() val state = listOf(MangaState.ONGOING, MangaState.FINISHED)
if (tag != null) { if (filter.states.containsAll(state)) {
append("/api/v2/tags/") // oneOrThrowIfMany
append(tag.key) throw IllegalArgumentException(
} else if (filter.states.isNotEmpty()) { ErrorMessages.FILTER_MULTIPLE_STATES_NOT_SUPPORTED
filter.states.oneOrThrowIfMany()?.let { )
append( }
append("&tags=")
val tags = buildList {
addAll(filter.tags.map { "\"${space2plus(it.title.lowercase())}\"" })
// trying to do this special case
addAll(
filter.states.map {
when (it) { when (it) {
MangaState.ONGOING -> "/api/v2/tags/dang-tien-hanh" MangaState.ONGOING -> "\"đang+tiến+hành\""
MangaState.FINISHED -> "/api/v2/tags/da-hoan-thanh" MangaState.FINISHED -> "\"đã+hoàn+thành\""
else -> "/api/v2/mangas/recently_updated" // if not (default page) // return empty list if null / empty
else -> "\"đang+tiến+hành\"+AND+\"đã+hoàn+thành\""
} }
)
} }
)
}.filter { it.isNotEmpty() }
append(tags.joinToString(separator = "+AND+"))
append("&page=")
append(page.toString())
} else { } else {
append("/api/v2/mangas") append("/mangas")
when (order) { when (order) {
SortOrder.UPDATED -> append("/recently_updated") SortOrder.UPDATED -> append("/recently_updated")
SortOrder.POPULARITY -> append("/top?duration=all") SortOrder.POPULARITY -> append("/top?duration=all")
SortOrder.POPULARITY_WEEK -> append("/top?duration=week") SortOrder.POPULARITY_WEEK -> append("/top?duration=week")
SortOrder.POPULARITY_MONTH -> append("/top?duration=month") SortOrder.POPULARITY_MONTH -> append("/top?duration=month")
SortOrder.NEWEST -> append("/recently_updated") SortOrder.NEWEST -> {
else -> append("/recently_updated") // clear old buildString
clear()
append("/home_a")
} }
else -> append("/recently_updated")
} }
when (order) { when (order) {
SortOrder.POPULARITY, SortOrder.POPULARITY_WEEK, SortOrder.POPULARITY_MONTH -> { SortOrder.POPULARITY, SortOrder.POPULARITY_WEEK, SortOrder.POPULARITY_MONTH -> {
append("&page=") append("&page=")
@ -110,28 +125,25 @@ internal class CuuTruyenParser(context: MangaLoaderContext) :
} }
} }
} }
}
append("&per_page=") append("&per_page=")
append(pageSize) append(pageSize)
} }
val json = try { // prevent throw e in app
webClient.httpGet(url).parseJson() val json = runCatching {
} catch (e: HttpStatusException) { webClient.httpGet("https://$domain$apiSuffix$url").parseJson()
if (e.statusCode == HttpURLConnection.HTTP_INTERNAL_ERROR) { }.getOrNull() ?: return emptyList()
return emptyList()
} else { val data = json.optJSONArray("data")
throw e ?: json.getJSONObject("data").getJSONArray("new_chapter_mangas")
} ?: json.getJSONObject("data").getJSONArray("mangas")
}
val data = json.optJSONArray("data") ?: json.getJSONObject("data").getJSONArray("mangas")
return data.mapJSON { jo -> return data.mapJSON { jo ->
val author = jo.getStringOrNull("author_name") val author = jo.getStringOrNull("author_name")
Manga( Manga(
id = generateUid(jo.getLong("id")), id = generateUid(jo.getLong("id")),
url = "/api/v2/mangas/${jo.getLong("id")}", url = "$apiSuffix/mangas/${jo.getLong("id")}",
publicUrl = "https://truycapcuutruyen.pages.dev/mangas/${jo.getLong("id")}", publicUrl = "https://truycapcuutruyen.pages.dev/mangas/${jo.getLong("id")}",
title = jo.getString("name"), title = jo.getString("name"),
altTitles = emptySet(), altTitles = emptySet(),
@ -195,7 +207,7 @@ internal class CuuTruyenParser(context: MangaLoaderContext) :
title = jo.getStringOrNull("name"), title = jo.getStringOrNull("name"),
number = number, number = number,
volume = 0, volume = 0,
url = "/api/v2/chapters/$chapterId", url = "$apiSuffix/chapters/$chapterId",
scanlator = team, scanlator = team,
uploadDate = chapterDateFormat.parseSafe(jo.getStringOrNull("created_at")), uploadDate = chapterDateFormat.parseSafe(jo.getStringOrNull("created_at")),
branch = null, branch = null,
@ -270,6 +282,8 @@ internal class CuuTruyenParser(context: MangaLoaderContext) :
}.toByteArray() }.toByteArray()
} }
private fun space2plus(input: String): String = input.replace(' ', '+')
private fun availableTags() = arraySetOf( // big thanks to beer-psi private fun availableTags() = arraySetOf( // big thanks to beer-psi
MangaTag("School life", "school-life", source), MangaTag("School life", "school-life", source),
MangaTag("Nsfw", "nsfw", source), MangaTag("Nsfw", "nsfw", source),

Loading…
Cancel
Save