[mgo] fix selectors and ratelimit (#15031)

* [Mgo] Update selectors

* Add rate limit

* chore: bump version
This commit is contained in:
beerpsi 2023-01-19 21:51:37 +07:00 committed by GitHub
parent 2cd0dcd55f
commit fe7492cc83
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 40 additions and 35 deletions

View File

@ -5,7 +5,7 @@ ext {
extName = 'Mangago' extName = 'Mangago'
pkgNameSuffix = 'en.mangago' pkgNameSuffix = 'en.mangago'
extClass = '.Mangago' extClass = '.Mangago'
extVersionCode = 9 extVersionCode = 10
isNsfw = true isNsfw = true
} }

View File

@ -7,6 +7,7 @@ import android.graphics.Rect
import android.util.Base64 import android.util.Base64
import app.cash.quickjs.QuickJs import app.cash.quickjs.QuickJs
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.interceptor.rateLimit
import eu.kanade.tachiyomi.source.model.Filter import eu.kanade.tachiyomi.source.model.Filter
import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.source.model.Page
@ -40,18 +41,22 @@ class Mangago : ParsedHttpSource() {
override val supportsLatest = true override val supportsLatest = true
override val client = network.cloudflareClient.newBuilder().addInterceptor { chain -> override val client = network.cloudflareClient.newBuilder()
val response = chain.proceed(chain.request()) .rateLimit(1, 2)
.addInterceptor { chain ->
val response = chain.proceed(chain.request())
val key = response.request.url.queryParameter("desckey") ?: return@addInterceptor response val key =
val cols = response.request.url.queryParameter("cols")?.toIntOrNull() ?: return@addInterceptor response response.request.url.queryParameter("desckey") ?: return@addInterceptor response
val cols = response.request.url.queryParameter("cols")?.toIntOrNull()
?: return@addInterceptor response
val image = unscrambleImage(response.body!!.byteStream(), key, cols) val image = unscrambleImage(response.body!!.byteStream(), key, cols)
val body = image.toResponseBody("image/jpeg".toMediaTypeOrNull()) val body = image.toResponseBody("image/jpeg".toMediaTypeOrNull())
return@addInterceptor response.newBuilder() return@addInterceptor response.newBuilder()
.body(body) .body(body)
.build() .build()
}.build() }.build()
override fun headersBuilder(): Headers.Builder = super.headersBuilder() override fun headersBuilder(): Headers.Builder = super.headersBuilder()
.add("Referer", "$baseUrl/") .add("Referer", "$baseUrl/")
@ -91,7 +96,8 @@ class Mangago : ParsedHttpSource() {
override fun popularMangaNextPageSelector() = genreListingNextPageSelector override fun popularMangaNextPageSelector() = genreListingNextPageSelector
override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/genre/all/$page/?f=1&o=1&sortby=update_date&e=", headers) override fun latestUpdatesRequest(page: Int) =
GET("$baseUrl/genre/all/$page/?f=1&o=1&sortby=update_date&e=", headers)
override fun latestUpdatesSelector() = genreListingSelector override fun latestUpdatesSelector() = genreListingSelector
@ -144,31 +150,26 @@ class Mangago : ParsedHttpSource() {
override fun searchMangaNextPageSelector() = genreListingNextPageSelector override fun searchMangaNextPageSelector() = genreListingNextPageSelector
override fun mangaDetailsParse(document: Document) = SManga.create().apply { override fun mangaDetailsParse(document: Document) = SManga.create().apply {
val coverElement = document.select(".left.cover > img") document.getElementById("information").let {
title = it.selectFirst(".w-title h1").text()
title = coverElement.attr("alt") thumbnail_url = it.selectFirst("img").attr("abs:src")
thumbnail_url = coverElement.attr("src") description = it.selectFirst(".manga_summary").text()
document.select(".manga_right td").forEach { it.select(".manga_info li").forEach { el ->
when (it.getElementsByTag("label").text().trim().lowercase()) { when (el.selectFirst("b").text().trim().lowercase()) {
"status:" -> { "alternative:" -> description += "\n\n${el.text()}"
status = when (it.selectFirst("span").text().trim().lowercase()) { "status:" -> when (el.selectFirst("span").text().trim().lowercase()) {
"ongoing" -> SManga.ONGOING "ongoing" -> SManga.ONGOING
"completed" -> SManga.COMPLETED "completed" -> SManga.COMPLETED
else -> SManga.UNKNOWN else -> SManga.UNKNOWN
} }
} "author(s):" -> author = el.select("a").joinToString { it.text() }
"author:" -> { "genre(s):" -> genre = el.select("a").joinToString { it.text() }
author = it.selectFirst("a").text()
}
"genre(s):" -> {
genre = it.getElementsByTag("a").joinToString { it.text() }
} }
} }
} }
description = document.selectFirst(".manga_summary").ownText().trim()
} }
override fun chapterListSelector() = "#chapter_table > tbody > tr" override fun chapterListSelector() = "table > tbody > tr"
override fun chapterFromElement(element: Element) = SChapter.create().apply { override fun chapterFromElement(element: Element) = SChapter.create().apply {
val link = element.getElementsByTag("a") val link = element.getElementsByTag("a")
@ -176,7 +177,7 @@ class Mangago : ParsedHttpSource() {
setUrlWithoutDomain(link.attr("href")) setUrlWithoutDomain(link.attr("href"))
name = link.text().trim() name = link.text().trim()
date_upload = kotlin.runCatching { date_upload = kotlin.runCatching {
dateFormat.parse(element.getElementsByClass("no").text().trim())?.time dateFormat.parse(element.select("td:last-child").text().trim())?.time
}.getOrNull() ?: 0L }.getOrNull() ?: 0L
} }
@ -191,7 +192,8 @@ class Mangago : ParsedHttpSource() {
it.attr("src").contains("chapter.js", ignoreCase = true) it.attr("src").contains("chapter.js", ignoreCase = true)
}.attr("abs:src") }.attr("abs:src")
val obfuscatedChapterJs = client.newCall(GET(chapterJsUrl, headers)).execute().body!!.string() val obfuscatedChapterJs =
client.newCall(GET(chapterJsUrl, headers)).execute().body!!.string()
val deobfChapterJs = SoJsonV4Deobfuscator.decode(obfuscatedChapterJs) val deobfChapterJs = SoJsonV4Deobfuscator.decode(obfuscatedChapterJs)
val key = findHexEncodedVariable(deobfChapterJs, "key").decodeHex() val key = findHexEncodedVariable(deobfChapterJs, "key").decodeHex()
@ -238,7 +240,8 @@ class Mangago : ParsedHttpSource() {
} }
} }
override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException("Not used") override fun imageUrlParse(document: Document): String =
throw UnsupportedOperationException("Not used")
override fun getFilterList(): FilterList = FilterList( override fun getFilterList(): FilterList = FilterList(
Filter.Header("Ignored if using text search"), Filter.Header("Ignored if using text search"),
@ -396,9 +399,10 @@ class Mangago : ParsedHttpSource() {
return output.toByteArray() return output.toByteArray()
} }
private fun buildCookies(cookies: Map<String, String>) = cookies.entries.joinToString(separator = "; ", postfix = ";") { private fun buildCookies(cookies: Map<String, String>) =
"${URLEncoder.encode(it.key, "UTF-8")}=${URLEncoder.encode(it.value, "UTF-8")}" cookies.entries.joinToString(separator = "; ", postfix = ";") {
} "${URLEncoder.encode(it.key, "UTF-8")}=${URLEncoder.encode(it.value, "UTF-8")}"
}
private fun String.decodeHex(): ByteArray { private fun String.decodeHex(): ByteArray {
check(length % 2 == 0) { "Must have an even length" } check(length % 2 == 0) { "Must have an even length" }
@ -429,7 +433,8 @@ class Mangago : ParsedHttpSource() {
} }
} }
private val jsFilters = listOf("jQuery", "document", "getContext", "toDataURL", "getImageData", "width", "height") private val jsFilters =
listOf("jQuery", "document", "getContext", "toDataURL", "getImageData", "width", "height")
private val hashCipher = "AES/CBC/ZEROBYTEPADDING" private val hashCipher = "AES/CBC/ZEROBYTEPADDING"