MyReadingManga: Improve search query with more filters
This commit is contained in:
2
.github/workflows/test-branch.yml
vendored
2
.github/workflows/test-branch.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
- name: Set up enviroment 🔧
|
||||
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
|
||||
with:
|
||||
java-version: '17'
|
||||
java-version: '21'
|
||||
distribution: 'temurin'
|
||||
|
||||
- name: Set up Gradle 📦
|
||||
|
||||
2
.github/workflows/test-parsers.yml
vendored
2
.github/workflows/test-parsers.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
||||
- name: Set up enviroment 🔧
|
||||
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
|
||||
with:
|
||||
java-version: '17'
|
||||
java-version: '21'
|
||||
distribution: 'temurin'
|
||||
|
||||
- name: Set up Gradle 📦
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package org.koitharu.kotatsu.parsers.site.all
|
||||
|
||||
import okhttp3.Headers
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import org.koitharu.kotatsu.parsers.Broken
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.MangaSourceParser
|
||||
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
||||
@@ -23,34 +23,39 @@ import org.koitharu.kotatsu.parsers.model.SortOrder
|
||||
import org.koitharu.kotatsu.parsers.util.attrAsRelativeUrl
|
||||
import org.koitharu.kotatsu.parsers.util.generateUid
|
||||
import org.koitharu.kotatsu.parsers.util.mapToSet
|
||||
import org.koitharu.kotatsu.parsers.util.oneOrThrowIfMany
|
||||
import org.koitharu.kotatsu.parsers.util.parseHtml
|
||||
import org.koitharu.kotatsu.parsers.util.splitByWhitespace
|
||||
import org.koitharu.kotatsu.parsers.util.toAbsoluteUrl
|
||||
import org.koitharu.kotatsu.parsers.util.urlEncoded
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.EnumSet
|
||||
import java.util.Locale
|
||||
import java.util.regex.Pattern
|
||||
import kotlin.collections.joinToString
|
||||
|
||||
@Broken("Need to rewrite getListPage")
|
||||
@MangaSourceParser("MYREADINGMANGA", "MyReadingManga", type = ContentType.HENTAI)
|
||||
internal class MyReadingManga(context: MangaLoaderContext) :
|
||||
PagedMangaParser(context, MangaParserSource.MYREADINGMANGA, 18) {
|
||||
|
||||
override val configKeyDomain = ConfigKey.Domain("myreadingmanga.info")
|
||||
|
||||
override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
|
||||
super.onCreateConfig(keys)
|
||||
keys.add(userAgentKey)
|
||||
}
|
||||
override fun getRequestHeaders(): Headers = Headers.Builder()
|
||||
.add("User-Agent", "Mozilla/5.0 (Linux; Android 13) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Mobile Safari/537.36")
|
||||
.add("X-Requested-With", randomString((1..20).random()))
|
||||
.build()
|
||||
|
||||
override val filterCapabilities: MangaListFilterCapabilities
|
||||
get() = MangaListFilterCapabilities(
|
||||
isSearchSupported = true,
|
||||
isSearchWithFiltersSupported = true,
|
||||
isMultipleTagsSupported = true,
|
||||
isOriginalLocaleSupported = true,
|
||||
)
|
||||
|
||||
override val availableSortOrders: Set<SortOrder> = EnumSet.of(
|
||||
SortOrder.UPDATED,
|
||||
SortOrder.RELEVANCE,
|
||||
SortOrder.NEWEST,
|
||||
SortOrder.NEWEST_ASC,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
@@ -58,6 +63,8 @@ internal class MyReadingManga(context: MangaLoaderContext) :
|
||||
availableStates = EnumSet.of(
|
||||
MangaState.ONGOING,
|
||||
MangaState.FINISHED,
|
||||
MangaState.PAUSED,
|
||||
MangaState.ABANDONED,
|
||||
),
|
||||
availableContentRating = EnumSet.of(ContentRating.ADULT),
|
||||
availableLocales = setOf(
|
||||
@@ -102,6 +109,8 @@ internal class MyReadingManga(context: MangaLoaderContext) :
|
||||
|
||||
private fun getLanguageSlug(locale: Locale?): String? {
|
||||
return when {
|
||||
locale?.language == "en" -> "english"
|
||||
locale?.language == "ja" -> "japanese"
|
||||
locale?.language == "fr" -> "french"
|
||||
locale?.language == "ja" -> "jp"
|
||||
locale?.language == "zh" && locale.country == "TW" -> "traditional-chinese"
|
||||
@@ -141,75 +150,53 @@ internal class MyReadingManga(context: MangaLoaderContext) :
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilter): List<Manga> {
|
||||
val url = buildString {
|
||||
append("https://")
|
||||
append(domain)
|
||||
|
||||
// Add language path if specified, need to fix
|
||||
val langSlug = getLanguageSlug(filter.locale)
|
||||
if (langSlug != null) {
|
||||
append("/lang/")
|
||||
append(langSlug)
|
||||
}
|
||||
if (page > 1) {
|
||||
append("/page/")
|
||||
append(page)
|
||||
}
|
||||
|
||||
when {
|
||||
!filter.query.isNullOrEmpty() -> {
|
||||
// Search with language: /lang/french/page/2/?s=example
|
||||
if (page > 1) {
|
||||
append("/page/")
|
||||
append(page)
|
||||
}
|
||||
append("/?s=")
|
||||
append(filter.query.urlEncoded())
|
||||
}
|
||||
append("/?ep_sort=")
|
||||
when (order) {
|
||||
SortOrder.NEWEST -> append("date")
|
||||
SortOrder.NEWEST_ASC -> append("date_asc")
|
||||
else -> append("")
|
||||
}
|
||||
|
||||
filter.tags.isNotEmpty() -> {
|
||||
// Genre filtering doesn't work with language, so we ignore language for genre
|
||||
if (langSlug == null) {
|
||||
append("/genre/")
|
||||
append(filter.tags.first().key)
|
||||
append("/page/")
|
||||
append(page)
|
||||
append("/")
|
||||
} else {
|
||||
// If both language and genre are selected, just use language
|
||||
append("/page/")
|
||||
append(page)
|
||||
append("/")
|
||||
}
|
||||
}
|
||||
if (!filter.query.isNullOrEmpty()) {
|
||||
append("&s=")
|
||||
append(filter.query.splitByWhitespace().joinToString(separator = "+"))
|
||||
}
|
||||
|
||||
filter.states.isNotEmpty() -> {
|
||||
// Status filtering doesn't work with language either
|
||||
if (langSlug == null) {
|
||||
append("/status/")
|
||||
append(
|
||||
when (filter.states.first()) {
|
||||
MangaState.ONGOING -> "ongoing"
|
||||
MangaState.FINISHED -> "completed"
|
||||
else -> "ongoing"
|
||||
},
|
||||
)
|
||||
append("/page/")
|
||||
append(page)
|
||||
append("/")
|
||||
} else {
|
||||
// If both language and status are selected, just use language
|
||||
append("/page/")
|
||||
append(page)
|
||||
append("/")
|
||||
}
|
||||
}
|
||||
val langSlug = getLanguageSlug(filter.locale)
|
||||
if (langSlug != null) {
|
||||
append("&ep_filter_lang=")
|
||||
append(langSlug)
|
||||
}
|
||||
|
||||
else -> {
|
||||
// Regular browsing with or without language
|
||||
append("/page/")
|
||||
append(page)
|
||||
append("/")
|
||||
}
|
||||
}
|
||||
if (filter.states.isNotEmpty()) {
|
||||
append("&ep_filter_status=")
|
||||
filter.states.oneOrThrowIfMany()?.let {
|
||||
append(
|
||||
when (it) {
|
||||
MangaState.ONGOING -> "ongoing"
|
||||
MangaState.FINISHED -> "completed"
|
||||
MangaState.PAUSED -> "hiatus"
|
||||
MangaState.ABANDONED -> "dropped"
|
||||
else -> ""
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (filter.tags.isNotEmpty()) {
|
||||
append("&ep_filter_genre=")
|
||||
append(filter.tags.joinToString(",") { it.key })
|
||||
}
|
||||
}
|
||||
|
||||
val doc = webClient.httpGet(url).parseHtml()
|
||||
@@ -302,6 +289,8 @@ internal class MyReadingManga(context: MangaLoaderContext) :
|
||||
val state = when (doc.select("a[href*=status]").firstOrNull()?.text()) {
|
||||
"Ongoing" -> MangaState.ONGOING
|
||||
"Completed" -> MangaState.FINISHED
|
||||
"Hiatus" -> MangaState.PAUSED
|
||||
"Dropped" -> MangaState.ABANDONED
|
||||
else -> null
|
||||
}
|
||||
|
||||
@@ -449,5 +438,10 @@ internal class MyReadingManga(context: MangaLoaderContext) :
|
||||
0L
|
||||
}
|
||||
}
|
||||
|
||||
private fun randomString(length: Int): String {
|
||||
val charPool = ('a'..'z') + ('A'..'Z')
|
||||
return List(length) { charPool.random() }.joinToString("")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user