MangaPark v3 Fixes (#7516)

* Update build.gradle

* Update res

* Update MangaParkUrlActivity.kt

* Update MangaParkFactory.kt

* Update MangaPark.kt
This commit is contained in:
FourTOne5 2021-06-07 16:52:38 +06:00 committed by GitHub
parent 1d3c14b75e
commit bf8b5d5df9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 264 additions and 239 deletions

View File

@ -1,11 +1,12 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlinx-serialization'
ext {
extName = 'MangaPark v3'
pkgNameSuffix = 'all.mangapark'
extClass = '.MangaParkFactory'
extVersionCode = 2
extVersionCode = 3
libVersion = '1.2'
containsNsfw = true
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 77 KiB

View File

@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.extension.all.mangapark
import com.squareup.duktape.Duktape
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.network.asObservableSuccess
import eu.kanade.tachiyomi.source.model.Filter
import eu.kanade.tachiyomi.source.model.FilterList
@ -11,29 +12,38 @@ 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.json.Json
import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.jsonArray
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 org.json.JSONArray
import org.json.JSONObject
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
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 name : String = "MangaPark v3"
override val baseUrl : String = "https://mangapark.net"
override val supportsLatest = true
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
private val json : Json by injectLazy()
override val client : OkHttpClient = network.cloudflareClient.newBuilder()
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.build()
@ -47,13 +57,11 @@ open class MangaPark(
}
override fun latestUpdatesFromElement(element: Element): SManga {
val manga = SManga.create()
val item = element.select("a.position-relative")
val imgurl = item.select("img").attr("abs:src")
manga.setUrlWithoutDomain(item.attr("href"))
manga.title = element.select("a.fw-bold").text()
manga.thumbnail_url = imgurl
return manga
return SManga.create().apply {
setUrlWithoutDomain(element.select("a.fw-bold").attr("href"))
title = element.select("a.fw-bold").text()
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)"
@ -70,11 +78,11 @@ open class MangaPark(
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
return when {
query.startsWith("ID:") -> {
val id = query.substringAfter("ID:")
query.startsWith(PREFIX_ID_SEARCH) -> {
val id = query.removePrefix(PREFIX_ID_SEARCH)
client.newCall(GET("$baseUrl/comic/$id", headers)).asObservableSuccess()
.map { response ->
queryIDParse(response, id)
mangaFromID(response, id)
}
}
@ -82,7 +90,7 @@ open class MangaPark(
val url = "$baseUrl/search?word=$query&page=$page"
client.newCall(GET(url, headers)).asObservableSuccess()
.map { response ->
queryParse(response)
searchParse(response)
}
}
@ -96,7 +104,6 @@ open class MangaPark(
val url = "$baseUrl/browse".toHttpUrlOrNull()!!.newBuilder()
url.addQueryParameter("page", page.toString())
with (sortFilter) {
if (reverseSortFilter.state) {
url.addQueryParameter("sort","${this.selected}.az")
@ -120,30 +127,32 @@ open class MangaPark(
client.newCall(GET(url.build().toString(), headers)).asObservableSuccess()
.map { response ->
queryParse(response)
searchParse(response)
}
}
}
}
private fun queryIDParse(response: Response, id: String): MangasPage {
val document = response.asJsoup()
val infoElement = document.select("div#mainer div.container-fluid")
val manga = SManga.create()
manga.title = infoElement.select("h3").text()
manga.thumbnail_url = document.select("div.attr-cover img")
.attr("abs:src")
manga.url = infoElement.select("h3 a").attr("abs:href")
private fun mangaFromID(response: Response, id: String): MangasPage {
val infoElement = response.asJsoup().select("div#mainer div.container-fluid")
val manga = SManga.create().apply {
url = "/comic/$id"
title = infoElement.select("h3.item-title").text()
thumbnail_url = infoElement.select("div.detail-set div.attr-cover img").attr("abs:src")
}
return MangasPage(listOf(manga), false)
}
private fun queryParse(response: Response): MangasPage {
private fun searchParse(response: Response): MangasPage {
val mangas = mutableListOf<SManga>()
val document = response.asJsoup()
document.select("div#search-list div.col").forEach { element ->
response.asJsoup().select("div#search-list div.col").forEach { element ->
mangas.add(latestUpdatesFromElement(element))
}
val nextPage = document.select(latestUpdatesNextPageSelector()).first() != null
val nextPage = response.asJsoup().select(latestUpdatesNextPageSelector()).first() != null
return MangasPage(mangas, nextPage)
}
@ -152,32 +161,24 @@ open class MangaPark(
override fun searchMangaFromElement(element: Element) = throw UnsupportedOperationException("Not used")
override fun searchMangaNextPageSelector() = throw UnsupportedOperationException("Not used")
override fun mangaDetailsRequest(manga: SManga): Request {
if (manga.url.startsWith("http")) {
return GET(manga.url, headers)
}
return super.mangaDetailsRequest(manga)
}
override fun mangaDetailsParse(document: Document): SManga {
val infoElement = document.select("div#mainer div.container-fluid")
val manga = SManga.create()
val genres = mutableListOf<String>()
val status = infoElement.select("div.attr-item:contains(status) span").text()
infoElement.select("div.attr-item:contains(genres) span").text().split(
" / "
.toRegex()
).forEach { element ->
genres.add(element)
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())
}
manga.title = infoElement.select("h3").text()
manga.author = infoElement.select("div.attr-item:contains(author) a:first-child").text().split(" / ".toRegex()).joinToString(", ")
manga.status = parseStatus(status)
manga.genre = infoElement.select("div.attr-item:contains(genre) span").text()
manga.description = infoElement.select("div.limit-height-body").text() //Needs to put new line before extra and notice and stuff.
manga.thumbnail_url = document.select("div.attr-cover img")
.attr("abs:src")
return manga
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() }
status = parseStatus(statusStr)
thumbnail_url = infoElement.select("div.detail-set div.attr-cover img").attr("abs:src")
genre = genreList.joinToString(", ") { it.trim() }
}
}
private fun parseStatus(status: String?) = when {
@ -189,73 +190,71 @@ open class MangaPark(
}
override fun chapterListRequest(manga: SManga): Request {
if (manga.url.startsWith("http")) {
return GET(manga.url, headers)
val url = manga.url
val sid = url.split("/")[2]
val jsonPayload = buildJsonObject {
put("lang", siteLang)
put("sid", sid)
}
return super.chapterListRequest(manga)
val requestBody = jsonPayload.toString().toRequestBody("application/json;charset=UTF-8".toMediaType())
val refererUrl = "$baseUrl/$url".toHttpUrlOrNull()!!.newBuilder()
.toString()
val newHeaders = headersBuilder()
.add("Content-Length", requestBody.contentLength().toString())
.add("Content-Type", requestBody.contentType().toString())
.set("Referer", refererUrl)
.build()
return POST(
"$baseUrl/ajax.reader.subject.episodes.lang",
headers = newHeaders,
body = requestBody
)
}
override fun chapterListSelector() = "div#mainer div.container-fluid div.episode-list div#episodes-lang-$siteLang div.p-2"
override fun chapterListSelector() = "div.episode-item"
override fun chapterFromElement(element: Element): SChapter {
val chapter = SChapter.create()
val urlElement = element.select("a.chapt")
val url = urlElement.attr("href")
val time = element.select("div.extra > i.ps-2").text()
chapter.setUrlWithoutDomain(url)
chapter.name = urlElement.text()
chapter.chapter_number = url.split("/".toRegex()).last().toFloat()
if (time != "") {
chapter.date_upload = parseChapterDate(time)
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()
if (time != "") { date_upload = parseChapterDate(time) }
setUrlWithoutDomain(urlElement.attr("href"))
}
return chapter
}
private fun parseChapterDate(date: String): Long {
val value = date.split(' ')[0].toInt()
val timeStr = date.split(' ')[1].removeSuffix("s")
return when {
"secs" in date -> Calendar.getInstance().apply {
return when (timeStr) {
"sec" -> Calendar.getInstance().apply {
add(Calendar.SECOND, value * -1)
}.timeInMillis
"mins" in date -> Calendar.getInstance().apply {
"min" -> Calendar.getInstance().apply {
add(Calendar.MINUTE, value * -1)
}.timeInMillis
"hours" in date -> Calendar.getInstance().apply {
"hour" -> Calendar.getInstance().apply {
add(Calendar.HOUR_OF_DAY, value * -1)
}.timeInMillis
"days" in date -> Calendar.getInstance().apply {
"day" -> Calendar.getInstance().apply {
add(Calendar.DATE, value * -1)
}.timeInMillis
"weeks" in date -> Calendar.getInstance().apply {
"week" -> Calendar.getInstance().apply {
add(Calendar.DATE, value * 7 * -1)
}.timeInMillis
"months" in date -> Calendar.getInstance().apply {
"month" -> Calendar.getInstance().apply {
add(Calendar.MONTH, value * -1)
}.timeInMillis
"years" in date -> Calendar.getInstance().apply {
add(Calendar.YEAR, value * -1)
}.timeInMillis
"sec" in date -> Calendar.getInstance().apply {
add(Calendar.SECOND, value * -1)
}.timeInMillis
"min" in date -> Calendar.getInstance().apply {
add(Calendar.MINUTE, value * -1)
}.timeInMillis
"hour" in date -> Calendar.getInstance().apply {
add(Calendar.HOUR_OF_DAY, value * -1)
}.timeInMillis
"day" in date -> Calendar.getInstance().apply {
add(Calendar.DATE, value * -1)
}.timeInMillis
"week" in date -> Calendar.getInstance().apply {
add(Calendar.DATE, value * 7 * -1)
}.timeInMillis
"month" in date -> Calendar.getInstance().apply {
add(Calendar.MONTH, value * -1)
}.timeInMillis
"year" in date -> Calendar.getInstance().apply {
"year" -> Calendar.getInstance().apply {
add(Calendar.YEAR, value * -1)
}.timeInMillis
else -> {
@ -264,28 +263,46 @@ open class MangaPark(
}
}
override fun pageListRequest(chapter: SChapter): Request {
if (chapter.url.startsWith("http")) {
return GET(chapter.url, headers)
}
return super.pageListRequest(chapter)
}
override fun pageListParse(document: Document): List<Page> {
val viewer = document.select("div#viewer")
val pages = mutableListOf<Page>()
viewer.select("div.item").forEach() { i ->
val index = i.select("span").text().split("/".toRegex())[0].toInt() - 1
val imageUrl = i.select("img").attr("abs:src")
pages.add(Page(index, "", imageUrl))
val duktape = Duktape.create()
val script = document.select("script").html()
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 amWord = script.substringAfter("const amWord = ").substringBefore(";")
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
}
private val cryptoJS by lazy {
client.newCall(
GET(
CryptoJSUrl,
headers
)
).execute().body!!.string()
}
override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException("Not used")
// Done Down
override fun getFilterList() = FilterList(
//LetterFilter(),
@ -467,4 +484,13 @@ open class MangaPark(
)
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

@ -12,112 +12,109 @@ 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("en", "en"),
//LanguageOption("ar"),
//LanguageOption("bg"),
//LanguageOption("zh"),
//LanguageOption("cs"),
//LanguageOption("da"),
//LanguageOption("nl"),
//LanguageOption("fil"),
//LanguageOption("fi"),
//LanguageOption("fr"),
//LanguageOption("de"),
//LanguageOption("el"),
//LanguageOption("he"),
//LanguageOption("hi"),
//LanguageOption("hu"),
//LanguageOption("id"),
//LanguageOption("it"),
//LanguageOption("ja"),
//LanguageOption("ko"),
//LanguageOption("ms"),
//LanguageOption("pl"),
//LanguageOption("pt"),
//LanguageOption("pt-BR","pt_br"),
//LanguageOption("ro"),
//LanguageOption("ru"),
//LanguageOption("es"),
//LanguageOption("es-419","es_419"),
//LanguageOption("sv"),
//LanguageOption("th"),
//LanguageOption("tr"),
//LanguageOption("uk"),
//LanguageOption("vi"),
//LanguageOption("af"),
//LanguageOption("sq"),
//LanguageOption("am"),
//LanguageOption("hy"),
//LanguageOption("az"),
//LanguageOption("be"),
//LanguageOption("bn"),
//LanguageOption("bs"),
//LanguageOption("my"),
//LanguageOption("km"),
//LanguageOption("ca"),
//LanguageOption("ceb"),
//LanguageOption("zh-rHK","zh_hk"),
//LanguageOption("zh-rTW","zh_tw"),
//LanguageOption("hr"),
//LanguageOption("en-US","en_us"),
//LanguageOption("eo"),
//LanguageOption("et"),
//LanguageOption("fo"),
//LanguageOption("ka"),
//LanguageOption("gn"),
//LanguageOption("gu"),
//LanguageOption("ht",),
//LanguageOption("ha"),
//LanguageOption("is"),
//LanguageOption("ig"),
//LanguageOption("ga"),
//LanguageOption("jv"),
//LanguageOption("kn"),
//LanguageOption("kk"),
//LanguageOption("ku"),
//LanguageOption("ky"),
//LanguageOption("lo"),
//LanguageOption("lv"),
//LanguageOption("lt"),
//LanguageOption("lb"),
//LanguageOption("mk"),
//LanguageOption("mg"),
//LanguageOption("ml"),
//LanguageOption("mt"),
//LanguageOption("mi"),
//LanguageOption("mr"),
//LanguageOption("mo"),
//LanguageOption("mn"),
//LanguageOption("ne"),
//LanguageOption("no"),
//LanguageOption("ny"),
//LanguageOption("ps"),
//LanguageOption("fa"),
//LanguageOption("rm"),
//LanguageOption("sm"),
//LanguageOption("sr"),
//LanguageOption("sh",),
//LanguageOption("st"),
//LanguageOption("sn"),
//LanguageOption("sd"),
//LanguageOption("si"),
//LanguageOption("sk"),
//LanguageOption("sl"),
//LanguageOption("so"),
//LanguageOption("sw"),
//LanguageOption("tg"),
//LanguageOption("ta"),
//LanguageOption("ti"),
//LanguageOption("to"),
//LanguageOption("tk"),
//LanguageOption("ur"),
//LanguageOption("uz"),
//LanguageOption("yo"),
//LanguageOption("zu"),
//LanguageOption("other", "_t"),
// Lang options from bato.to brows not in publish.bato.to
//LanguageOption("eu"),
//LanguageOption("pt-PT","pt_pt"),
// Lang options that got removed
// Pair("xh", "xh"),
LanguageOption("en"),
LanguageOption("ar"),
LanguageOption("bg"),
LanguageOption("zh"),
LanguageOption("cs"),
LanguageOption("da"),
LanguageOption("nl"),
LanguageOption("fil"),
LanguageOption("fi"),
LanguageOption("fr"),
LanguageOption("de"),
LanguageOption("el"),
LanguageOption("he"),
LanguageOption("hi"),
LanguageOption("hu"),
LanguageOption("id"),
LanguageOption("it"),
LanguageOption("ja"),
LanguageOption("ko"),
LanguageOption("ms"),
LanguageOption("pl"),
LanguageOption("pt"),
LanguageOption("pt-BR","pt_br"),
LanguageOption("ro"),
LanguageOption("ru"),
LanguageOption("es"),
LanguageOption("es-419","es_419"),
LanguageOption("sv"),
LanguageOption("th"),
LanguageOption("tr"),
LanguageOption("uk"),
LanguageOption("vi"),
LanguageOption("af"),
LanguageOption("sq"),
LanguageOption("am"),
LanguageOption("hy"),
LanguageOption("az"),
LanguageOption("be"),
LanguageOption("bn"),
LanguageOption("bs"),
LanguageOption("my"),
LanguageOption("km"),
LanguageOption("ca"),
LanguageOption("ceb"),
LanguageOption("zh-rHK","zh_hk"),
LanguageOption("zh-rTW","zh_tw"),
LanguageOption("hr"),
LanguageOption("en-US","en_us"),
LanguageOption("eo"),
LanguageOption("et"),
LanguageOption("fo"),
LanguageOption("ka"),
LanguageOption("gn"),
LanguageOption("gu"),
LanguageOption("ht",),
LanguageOption("ha"),
LanguageOption("is"),
LanguageOption("ig"),
LanguageOption("ga"),
LanguageOption("jv"),
LanguageOption("kn"),
LanguageOption("kk"),
LanguageOption("ku"),
LanguageOption("ky"),
LanguageOption("lo"),
LanguageOption("lv"),
LanguageOption("lt"),
LanguageOption("lb"),
LanguageOption("mk"),
LanguageOption("mg"),
LanguageOption("ml"),
LanguageOption("mt"),
LanguageOption("mi"),
LanguageOption("mr"),
LanguageOption("mo"),
LanguageOption("mn"),
LanguageOption("ne"),
LanguageOption("no"),
LanguageOption("ny"),
LanguageOption("ps"),
LanguageOption("fa"),
LanguageOption("rm"),
LanguageOption("sm"),
LanguageOption("sr"),
LanguageOption("sh",),
LanguageOption("st"),
LanguageOption("sn"),
LanguageOption("sd"),
LanguageOption("si"),
LanguageOption("sk"),
LanguageOption("sl"),
LanguageOption("so"),
LanguageOption("sw"),
LanguageOption("tg"),
LanguageOption("ta"),
LanguageOption("ti"),
LanguageOption("to"),
LanguageOption("tk"),
LanguageOption("ur"),
LanguageOption("uz"),
LanguageOption("yo"),
LanguageOption("zu"),
LanguageOption("other", "_t"),
LanguageOption("eu"),
LanguageOption("pt-PT","pt_pt")
)

View File

@ -1,4 +1,5 @@
package eu.kanade.tachiyomi.extension.all.mangapark
import android.app.Activity
import android.content.ActivityNotFoundException
import android.content.Intent
@ -42,7 +43,7 @@ class MangaParkUrlActivity : Activity() {
private fun fromGuya(pathSegments: MutableList<String>): String? {
return if (pathSegments.size >= 2) {
val id = pathSegments[1]
"ID:$id"
"id:$id"
} else {
null
}