Fix broken search and chapter images at MP. (#7580)

This commit is contained in:
Alessandro Jean 2021-06-09 18:46:25 -03:00 committed by GitHub
parent d6cd87b712
commit ca27731aa8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 186 additions and 206 deletions

View File

@ -6,7 +6,7 @@ ext {
extName = 'MangaPark v3'
pkgNameSuffix = 'all.mangapark'
extClass = '.MangaParkFactory'
extVersionCode = 5
extVersionCode = 6
libVersion = '1.2'
containsNsfw = true
}

View File

@ -14,50 +14,50 @@ import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive
import kotlinx.serialization.json.put
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.Response
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.util.Calendar
import java.util.concurrent.TimeUnit
import okhttp3.Response
import rx.Observable
import uy.kohesive.injekt.injectLazy
import java.util.Calendar
import java.util.concurrent.TimeUnit
open class MangaPark(
override val lang: String,
private val siteLang: String
) : ParsedHttpSource() {
override val name : String = "MangaPark v3"
override val baseUrl : String = "https://mangapark.net"
override val supportsLatest = true
private val json : Json by injectLazy()
override val client : OkHttpClient = network.cloudflareClient.newBuilder()
override val name: String = "MangaPark v3"
override val baseUrl: String = "https://mangapark.net"
override val supportsLatest = true
private val json: Json by injectLazy()
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.build()
override fun latestUpdatesRequest(page: Int): Request {
return GET("$baseUrl/browse?sort=update&page=$page")
}
override fun latestUpdatesSelector(): String {
return "div#subject-list div.col"
}
override fun latestUpdatesFromElement(element: Element): SManga {
return SManga.create().apply {
setUrlWithoutDomain(element.select("a.fw-bold").attr("href"))
@ -65,19 +65,19 @@ open class MangaPark(
thumbnail_url = element.select("a.position-relative img").attr("abs:src")
}
}
override fun latestUpdatesNextPageSelector() = "div#mainer nav.d-none .pagination .page-item:last-of-type:not(.disabled)"
override fun popularMangaRequest(page: Int): Request {
return GET("$baseUrl/browse?sort=d007&page=$page")
}
override fun popularMangaSelector() = latestUpdatesSelector()
override fun popularMangaFromElement(element: Element) = latestUpdatesFromElement(element)
override fun popularMangaNextPageSelector() = latestUpdatesNextPageSelector()
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
return when {
query.startsWith(PREFIX_ID_SEARCH) -> {
@ -87,15 +87,15 @@ open class MangaPark(
mangaFromID(response, id)
}
}
query.isNotBlank() -> {
val url = "$baseUrl/search?word=$query&page=$page"
client.newCall(GET(url, headers)).asObservableSuccess()
.map { response ->
searchParse(response)
searchMangaParse(response)
}
}
else -> {
val sortFilter = filters.findInstance<SortFilter>()!!
val reverseSortFilter = filters.findInstance<ReverseSortFilter>()!!
@ -105,21 +105,22 @@ open class MangaPark(
val maxChapterFilter = filters.findInstance<MaxChapterTextFilter>()!!
val url = "$baseUrl/browse".toHttpUrlOrNull()!!.newBuilder()
url.addQueryParameter("page", page.toString())
with (sortFilter) {
with(sortFilter) {
if (reverseSortFilter.state) {
url.addQueryParameter("sort","${this.selected}.az")
url.addQueryParameter("sort", "${this.selected}.az")
} else {
url.addQueryParameter("sort","${this.selected}.za")
url.addQueryParameter("sort", "${this.selected}.za")
}
}
with (genreFilter) {
url.addQueryParameter("genres", included.joinToString(",") + "|" + excluded.joinToString(",")
with(genreFilter) {
url.addQueryParameter(
"genres", included.joinToString(",") + "|" + excluded.joinToString(",")
)
}
with (statusFilter) {
with(statusFilter) {
url.addQueryParameter("release", this.selected)
}
@ -129,12 +130,12 @@ open class MangaPark(
client.newCall(GET(url.build().toString(), headers)).asObservableSuccess()
.map { response ->
searchParse(response)
searchMangaParse(response)
}
}
}
}
private fun mangaFromID(response: Response, id: String): MangasPage {
val infoElement = response.asJsoup().select("div#mainer div.container-fluid")
val manga = SManga.create().apply {
@ -146,41 +147,30 @@ open class MangaPark(
return MangasPage(listOf(manga), false)
}
private fun searchParse(response: Response): MangasPage {
val mangas = mutableListOf<SManga>()
response.asJsoup().select("div#search-list div.col").forEach { element ->
mangas.add(latestUpdatesFromElement(element))
}
val nextPage = response.asJsoup().select(latestUpdatesNextPageSelector()).first() != null
return MangasPage(mangas, nextPage)
}
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request = throw UnsupportedOperationException("Not used")
override fun searchMangaSelector() = throw UnsupportedOperationException("Not used")
override fun searchMangaFromElement(element: Element) = throw UnsupportedOperationException("Not used")
override fun searchMangaNextPageSelector() = throw UnsupportedOperationException("Not used")
override fun searchMangaSelector() = "div#search-list div.col"
override fun searchMangaFromElement(element: Element) = latestUpdatesFromElement(element)
override fun searchMangaNextPageSelector() = latestUpdatesNextPageSelector()
override fun mangaDetailsParse(document: Document): SManga {
val infoElement = document.select("div#mainer div.container-fluid")
val genreList = mutableListOf<String>()
val statusStr = infoElement.select("div.attr-item:contains(status) span").text()
infoElement.select("div.attr-item:contains(genres) span span").forEach { element ->
genreList.add(element.text())
}
return SManga.create().apply {
title = infoElement.select("h3.item-title").text()
description = infoElement.select("div.limit-height-body").select("h5.text-muted, div.limit-html").joinToString("\n\n") { it.text() }
author = infoElement.select("div.attr-item:contains(author)").text().split("/").joinToString(", ") { it.trim() }
description = infoElement.select("div.limit-height-body")
.select("h5.text-muted, div.limit-html")
.joinToString("\n\n") { it.text() }
author = infoElement.select("div.attr-item:contains(author) a")
.joinToString { it.text().trim() }
status = parseStatus(statusStr)
thumbnail_url = infoElement.select("div.detail-set div.attr-cover img").attr("abs:src")
genre = genreList.joinToString(", ") { it.trim() }
genre = infoElement.select("div.attr-item:contains(genres) span span")
.joinToString { it.text().trim() }
}
}
private fun parseStatus(status: String?) = when {
@ -200,7 +190,7 @@ open class MangaPark(
put("lang", siteLang)
put("sid", sid)
}
val requestBody = jsonPayload.toString().toRequestBody("application/json;charset=UTF-8".toMediaType())
val refererUrl = "$baseUrl/$url".toHttpUrlOrNull()!!.newBuilder()
@ -217,20 +207,20 @@ open class MangaPark(
body = requestBody
)
}
override fun chapterListParse(response: Response): List<SChapter> {
val resToJson = json.parseToJsonElement(response.body!!.string()).jsonObject
val document = Jsoup.parse(resToJson["html"]!!.jsonPrimitive.content)
return document.select(chapterListSelector()).map { chapterFromElement(it) }
}
override fun chapterListSelector() = "div.episode-item"
override fun chapterFromElement(element: Element): SChapter {
val urlElement = element.select("a.chapt")
val time = element.select("div.extra > i.ps-2").text()
return SChapter.create().apply {
name = urlElement.text()
chapter_number = urlElement.attr("href").substringAfterLast("/").toFloat()
@ -238,7 +228,7 @@ open class MangaPark(
setUrlWithoutDomain(urlElement.attr("href"))
}
}
private fun parseChapterDate(date: String): Long {
val value = date.split(' ')[0].toInt()
val timeStr = date.split(' ')[1].removeSuffix("s")
@ -272,32 +262,25 @@ open class MangaPark(
}
override fun pageListParse(document: Document): List<Page> {
val pages = mutableListOf<Page>()
val duktape = Duktape.create()
val script = document.select("script").html()
val imgCdnHost = script.substringAfter("const imgCdnHost = ").substringBefore(";")
val imgCdnHost = script.substringAfter("const imgCdnHost = \"").substringBefore("\";")
val imgPathLisRaw = script.substringAfter("const imgPathLis = ").substringBefore(";")
val imgPathLis = json.parseToJsonElement(imgPathLisRaw).jsonArray
val amPass = duktape.evaluate(script.substringAfter("const amPass = ").substringBefore(";")).toString()
val amPass = script.substringAfter("const amPass = ").substringBefore(";")
val amWord = script.substringAfter("const amWord = ").substringBefore(";")
val decryptScript = cryptoJS + "CryptoJS.AES.decrypt($amWord, \"$amPass\").toString(CryptoJS.enc.Utf8);"
val decryptScript = cryptoJS + "CryptoJS.AES.decrypt($amWord, $amPass).toString(CryptoJS.enc.Utf8);"
val imgWordLisRaw = duktape.evaluate(decryptScript).toString()
val imgWordLis = json.parseToJsonElement(imgWordLisRaw).jsonArray
imgPathLis.mapIndexed { i, imgPathE ->
val imgPath = imgPathE.jsonPrimitive.content
val imgWordE = imgWordLis.elementAt(i)
val imgWord = imgWordE.jsonPrimitive.content
val page = "$imgCdnHost$imgPath?$imgWord"
pages.add(Page(i, "", "$page"))
}
return pages
return imgWordLis.mapIndexed { i, imgWordE ->
val imgPath = imgPathLis[i].jsonPrimitive.content
val imgWord = imgWordE.jsonPrimitive.content
Page(i, "", "$imgCdnHost$imgPath?$imgWord")
}
}
private val cryptoJS by lazy {
@ -311,9 +294,8 @@ open class MangaPark(
override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException("Not used")
override fun getFilterList() = FilterList(
//LetterFilter(),
// LetterFilter(),
Filter.Header("NOTE: Ignored if using text search!"),
Filter.Separator(),
SortFilter(getSortFilter(), 10),
@ -381,124 +363,122 @@ open class MangaPark(
)
private fun getGenreFilter() = listOf(
TriStateFilterOption("artbook","Artbook"),
TriStateFilterOption("cartoon","Cartoon"),
TriStateFilterOption("comic","Comic"),
TriStateFilterOption("doujinshi","Doujinshi"),
TriStateFilterOption("imageset","Imageset"),
TriStateFilterOption("manga","Manga"),
TriStateFilterOption("manhua","Manhua"),
TriStateFilterOption("manhwa","Manhwa"),
TriStateFilterOption("webtoon","Webtoon"),
TriStateFilterOption("western","Western"),
TriStateFilterOption("josei","Josei"),
TriStateFilterOption("seinen","Seinen"),
TriStateFilterOption("shoujo","Shoujo"),
TriStateFilterOption("shoujo_ai","Shoujo ai"),
TriStateFilterOption("shounen","Shounen"),
TriStateFilterOption("shounen_ai","Shounen ai"),
TriStateFilterOption("yaoi","Yaoi"),
TriStateFilterOption("yuri","Yuri"),
TriStateFilterOption("ecchi","Ecchi"),
TriStateFilterOption("mature","Mature"),
TriStateFilterOption("adult","Adult"),
TriStateFilterOption("gore","Gore"),
TriStateFilterOption("violence","Violence"),
TriStateFilterOption("smut","Smut"),
TriStateFilterOption("hentai","Hentai"),
TriStateFilterOption("_4_koma","4-Koma"),
TriStateFilterOption("action","Action"),
TriStateFilterOption("adaptation","Adaptation"),
TriStateFilterOption("adventure","Adventure"),
TriStateFilterOption("aliens","Aliens"),
TriStateFilterOption("animals","Animals"),
TriStateFilterOption("anthology","Anthology"),
TriStateFilterOption("cars","cars"),
TriStateFilterOption("comedy","Comedy"),
TriStateFilterOption("cooking","Cooking"),
TriStateFilterOption("crime","crime"),
TriStateFilterOption("crossdressing","Crossdressing"),
TriStateFilterOption("delinquents","Delinquents"),
TriStateFilterOption("dementia","Dementia"),
TriStateFilterOption("demons","Demons"),
TriStateFilterOption("drama","Drama"),
TriStateFilterOption("fantasy","Fantasy"),
TriStateFilterOption("fan_colored","Fan-Colored"),
TriStateFilterOption("full_color","Full Color"),
TriStateFilterOption("game","Game"),
TriStateFilterOption("gender_bender","Gender Bender"),
TriStateFilterOption("genderswap","Genderswap"),
TriStateFilterOption("ghosts","Ghosts"),
TriStateFilterOption("gyaru","Gyaru"),
TriStateFilterOption("harem","Harem"),
TriStateFilterOption("harlequin","Harlequin"),
TriStateFilterOption("historical","Historical"),
TriStateFilterOption("horror","Horror"),
TriStateFilterOption("incest","Incest"),
TriStateFilterOption("isekai","Isekai"),
TriStateFilterOption("kids","Kids"),
TriStateFilterOption("loli","Loli"),
TriStateFilterOption("lolicon","lolicon"),
TriStateFilterOption("magic","Magic"),
TriStateFilterOption("magical_girls","Magical Girls"),
TriStateFilterOption("martial_arts","Martial Arts"),
TriStateFilterOption("mecha","Mecha"),
TriStateFilterOption("medical","Medical"),
TriStateFilterOption("military","Military"),
TriStateFilterOption("monster_girls","Monster Girls"),
TriStateFilterOption("monsters","Monsters"),
TriStateFilterOption("music","Music"),
TriStateFilterOption("mystery","Mystery"),
TriStateFilterOption("netorare","Netorare/NTR"),
TriStateFilterOption("ninja","Ninja"),
TriStateFilterOption("office_workers","Office Workers"),
TriStateFilterOption("oneshot","Oneshot"),
TriStateFilterOption("parody","parody"),
TriStateFilterOption("philosophical","Philosophical"),
TriStateFilterOption("police","Police"),
TriStateFilterOption("post_apocalyptic","Post-Apocalyptic"),
TriStateFilterOption("psychological","Psychological"),
TriStateFilterOption("reincarnation","Reincarnation"),
TriStateFilterOption("reverse_harem","Reverse Harem"),
TriStateFilterOption("romance","Romance"),
TriStateFilterOption("samurai","Samurai"),
TriStateFilterOption("school_life","School Life"),
TriStateFilterOption("sci_fi","Sci-Fi"),
TriStateFilterOption("shota","Shota"),
TriStateFilterOption("shotacon","shotacon"),
TriStateFilterOption("slice_of_life","Slice of Life"),
TriStateFilterOption("sm_bdsm","SM/BDSM"),
TriStateFilterOption("space","Space"),
TriStateFilterOption("sports","Sports"),
TriStateFilterOption("super_power","Super Power"),
TriStateFilterOption("superhero","Superhero"),
TriStateFilterOption("supernatural","Supernatural"),
TriStateFilterOption("survival","Survival"),
TriStateFilterOption("thriller","Thriller"),
TriStateFilterOption("time_travel","Time Travel"),
TriStateFilterOption("traditional_games","Traditional Games"),
TriStateFilterOption("tragedy","Tragedy"),
TriStateFilterOption("vampires","Vampires"),
TriStateFilterOption("video_games","Video Games"),
TriStateFilterOption("virtual_reality","Virtual Reality"),
TriStateFilterOption("wuxia","Wuxia"),
TriStateFilterOption("xianxia","Xianxia"),
TriStateFilterOption("xuanhuan","Xuanhuan"),
TriStateFilterOption("zombies","Zombies"),
TriStateFilterOption("artbook", "Artbook"),
TriStateFilterOption("cartoon", "Cartoon"),
TriStateFilterOption("comic", "Comic"),
TriStateFilterOption("doujinshi", "Doujinshi"),
TriStateFilterOption("imageset", "Imageset"),
TriStateFilterOption("manga", "Manga"),
TriStateFilterOption("manhua", "Manhua"),
TriStateFilterOption("manhwa", "Manhwa"),
TriStateFilterOption("webtoon", "Webtoon"),
TriStateFilterOption("western", "Western"),
TriStateFilterOption("josei", "Josei"),
TriStateFilterOption("seinen", "Seinen"),
TriStateFilterOption("shoujo", "Shoujo"),
TriStateFilterOption("shoujo_ai", "Shoujo ai"),
TriStateFilterOption("shounen", "Shounen"),
TriStateFilterOption("shounen_ai", "Shounen ai"),
TriStateFilterOption("yaoi", "Yaoi"),
TriStateFilterOption("yuri", "Yuri"),
TriStateFilterOption("ecchi", "Ecchi"),
TriStateFilterOption("mature", "Mature"),
TriStateFilterOption("adult", "Adult"),
TriStateFilterOption("gore", "Gore"),
TriStateFilterOption("violence", "Violence"),
TriStateFilterOption("smut", "Smut"),
TriStateFilterOption("hentai", "Hentai"),
TriStateFilterOption("_4_koma", "4-Koma"),
TriStateFilterOption("action", "Action"),
TriStateFilterOption("adaptation", "Adaptation"),
TriStateFilterOption("adventure", "Adventure"),
TriStateFilterOption("aliens", "Aliens"),
TriStateFilterOption("animals", "Animals"),
TriStateFilterOption("anthology", "Anthology"),
TriStateFilterOption("cars", "cars"),
TriStateFilterOption("comedy", "Comedy"),
TriStateFilterOption("cooking", "Cooking"),
TriStateFilterOption("crime", "crime"),
TriStateFilterOption("crossdressing", "Crossdressing"),
TriStateFilterOption("delinquents", "Delinquents"),
TriStateFilterOption("dementia", "Dementia"),
TriStateFilterOption("demons", "Demons"),
TriStateFilterOption("drama", "Drama"),
TriStateFilterOption("fantasy", "Fantasy"),
TriStateFilterOption("fan_colored", "Fan-Colored"),
TriStateFilterOption("full_color", "Full Color"),
TriStateFilterOption("game", "Game"),
TriStateFilterOption("gender_bender", "Gender Bender"),
TriStateFilterOption("genderswap", "Genderswap"),
TriStateFilterOption("ghosts", "Ghosts"),
TriStateFilterOption("gyaru", "Gyaru"),
TriStateFilterOption("harem", "Harem"),
TriStateFilterOption("harlequin", "Harlequin"),
TriStateFilterOption("historical", "Historical"),
TriStateFilterOption("horror", "Horror"),
TriStateFilterOption("incest", "Incest"),
TriStateFilterOption("isekai", "Isekai"),
TriStateFilterOption("kids", "Kids"),
TriStateFilterOption("loli", "Loli"),
TriStateFilterOption("lolicon", "lolicon"),
TriStateFilterOption("magic", "Magic"),
TriStateFilterOption("magical_girls", "Magical Girls"),
TriStateFilterOption("martial_arts", "Martial Arts"),
TriStateFilterOption("mecha", "Mecha"),
TriStateFilterOption("medical", "Medical"),
TriStateFilterOption("military", "Military"),
TriStateFilterOption("monster_girls", "Monster Girls"),
TriStateFilterOption("monsters", "Monsters"),
TriStateFilterOption("music", "Music"),
TriStateFilterOption("mystery", "Mystery"),
TriStateFilterOption("netorare", "Netorare/NTR"),
TriStateFilterOption("ninja", "Ninja"),
TriStateFilterOption("office_workers", "Office Workers"),
TriStateFilterOption("oneshot", "Oneshot"),
TriStateFilterOption("parody", "parody"),
TriStateFilterOption("philosophical", "Philosophical"),
TriStateFilterOption("police", "Police"),
TriStateFilterOption("post_apocalyptic", "Post-Apocalyptic"),
TriStateFilterOption("psychological", "Psychological"),
TriStateFilterOption("reincarnation", "Reincarnation"),
TriStateFilterOption("reverse_harem", "Reverse Harem"),
TriStateFilterOption("romance", "Romance"),
TriStateFilterOption("samurai", "Samurai"),
TriStateFilterOption("school_life", "School Life"),
TriStateFilterOption("sci_fi", "Sci-Fi"),
TriStateFilterOption("shota", "Shota"),
TriStateFilterOption("shotacon", "shotacon"),
TriStateFilterOption("slice_of_life", "Slice of Life"),
TriStateFilterOption("sm_bdsm", "SM/BDSM"),
TriStateFilterOption("space", "Space"),
TriStateFilterOption("sports", "Sports"),
TriStateFilterOption("super_power", "Super Power"),
TriStateFilterOption("superhero", "Superhero"),
TriStateFilterOption("supernatural", "Supernatural"),
TriStateFilterOption("survival", "Survival"),
TriStateFilterOption("thriller", "Thriller"),
TriStateFilterOption("time_travel", "Time Travel"),
TriStateFilterOption("traditional_games", "Traditional Games"),
TriStateFilterOption("tragedy", "Tragedy"),
TriStateFilterOption("vampires", "Vampires"),
TriStateFilterOption("video_games", "Video Games"),
TriStateFilterOption("virtual_reality", "Virtual Reality"),
TriStateFilterOption("wuxia", "Wuxia"),
TriStateFilterOption("xianxia", "Xianxia"),
TriStateFilterOption("xuanhuan", "Xuanhuan"),
TriStateFilterOption("zombies", "Zombies"),
// Hidden Genres
TriStateFilterOption("award_winning", "Award Winning"),
TriStateFilterOption("youkai", "Youkai"),
TriStateFilterOption("uncategorized", "Uncategorized")
)
private inline fun <reified T> Iterable<*>.findInstance() = find { it is T } as? T
companion object {
const val PREFIX_ID_SEARCH = "id:"
const val CryptoJSUrl = "https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"
}
}

View File

@ -11,7 +11,7 @@ class MangaParkFactory : SourceFactory {
class LanguageOption(val lang: String, val siteLang: String = lang)
private val languages = listOf(
//LanguageOption("<Language Format>","<Language Format used in site.>"),
// LanguageOption("<Language Format>","<Language Format used in site.>"),
LanguageOption("en"),
LanguageOption("ar"),
LanguageOption("bg"),
@ -34,11 +34,11 @@ private val languages = listOf(
LanguageOption("ms"),
LanguageOption("pl"),
LanguageOption("pt"),
LanguageOption("pt-BR","pt_br"),
LanguageOption("pt-BR", "pt_br"),
LanguageOption("ro"),
LanguageOption("ru"),
LanguageOption("es"),
LanguageOption("es-419","es_419"),
LanguageOption("es-419", "es_419"),
LanguageOption("sv"),
LanguageOption("th"),
LanguageOption("tr"),
@ -56,10 +56,10 @@ private val languages = listOf(
LanguageOption("km"),
LanguageOption("ca"),
LanguageOption("ceb"),
LanguageOption("zh-rHK","zh_hk"),
LanguageOption("zh-rTW","zh_tw"),
LanguageOption("zh-rHK", "zh_hk"),
LanguageOption("zh-rTW", "zh_tw"),
LanguageOption("hr"),
LanguageOption("en-US","en_us"),
LanguageOption("en-US", "en_us"),
LanguageOption("eo"),
LanguageOption("et"),
LanguageOption("fo"),
@ -116,5 +116,5 @@ private val languages = listOf(
LanguageOption("zu"),
LanguageOption("other", "_t"),
LanguageOption("eu"),
LanguageOption("pt-PT","pt_pt")
LanguageOption("pt-PT", "pt_pt")
)