Fix missing response at SuperMangas. (#6180)

This commit is contained in:
Alessandro Jean 2021-03-15 10:14:23 -03:00 committed by GitHub
parent 644e5e556d
commit 4df4d1b562
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 84 additions and 20 deletions

View File

@ -5,7 +5,7 @@ ext {
extName = 'Super Mangás' extName = 'Super Mangás'
pkgNameSuffix = 'pt.supermangas' pkgNameSuffix = 'pt.supermangas'
extClass = '.SuperMangasFactory' extClass = '.SuperMangasFactory'
extVersionCode = 6 extVersionCode = 7
libVersion = '1.2' libVersion = '1.2'
containsNsfw = true containsNsfw = true
} }

View File

@ -8,6 +8,7 @@ import com.github.salomonbrys.kotson.obj
import com.github.salomonbrys.kotson.string import com.github.salomonbrys.kotson.string
import com.google.gson.JsonObject import com.google.gson.JsonObject
import com.google.gson.JsonParser import com.google.gson.JsonParser
import com.squareup.duktape.Duktape
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.POST import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.source.model.Filter import eu.kanade.tachiyomi.source.model.Filter
@ -21,12 +22,15 @@ import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.FormBody import okhttp3.FormBody
import okhttp3.Headers import okhttp3.Headers
import okhttp3.HttpUrl import okhttp3.HttpUrl
import okhttp3.Interceptor
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import okhttp3.RequestBody
import okhttp3.Response import okhttp3.Response
import org.jsoup.Jsoup import org.jsoup.Jsoup
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import java.net.URLEncoder
typealias Content = Triple<String, String, String> typealias Content = Triple<String, String, String>
@ -40,14 +44,16 @@ abstract class SuperMangasGeneric(
override val supportsLatest = true override val supportsLatest = true
override val client: OkHttpClient = network.cloudflareClient override val client: OkHttpClient = network.cloudflareClient.newBuilder()
.addInterceptor(::paginatorIntercept)
.build()
override fun headersBuilder(): Headers.Builder = Headers.Builder() override fun headersBuilder(): Headers.Builder = Headers.Builder()
.add("User-Agent", USER_AGENT)
.add("Origin", baseUrl)
.add("Referer", baseUrl)
.add("Accept", ACCEPT_COMMON) .add("Accept", ACCEPT_COMMON)
.add("Accept-Language", ACCEPT_LANGUAGE) .add("Accept-Language", ACCEPT_LANGUAGE)
.add("Origin", baseUrl)
.add("Referer", baseUrl)
.add("User-Agent", USER_AGENT)
protected open val defaultFilter = mutableMapOf( protected open val defaultFilter = mutableMapOf(
"filter_display_view" to "lista", "filter_display_view" to "lista",
@ -77,6 +83,7 @@ abstract class SuperMangasGeneric(
filterGenreDel: List<String> = emptyList(), filterGenreDel: List<String> = emptyList(),
page: Int = 1 page: Int = 1
): Request { ): Request {
val filters = jsonObject( val filters = jsonObject(
"filter_data" to filterData.toUrlQueryParams(), "filter_data" to filterData.toUrlQueryParams(),
"filter_genre_add" to jsonArray(filterGenreAdd), "filter_genre_add" to jsonArray(filterGenreAdd),
@ -95,7 +102,7 @@ abstract class SuperMangasGeneric(
.add("X-Requested-With", "XMLHttpRequest") .add("X-Requested-With", "XMLHttpRequest")
.add("Content-Type", form.contentType().toString()) .add("Content-Type", form.contentType().toString())
.add("Content-Length", form.contentLength().toString()) .add("Content-Length", form.contentLength().toString())
.add("Host", "www." + baseUrl.substringAfter("//")) .set("Accept", ACCEPT_JSON)
.set("Referer", "$baseUrl/$typeUrl") .set("Referer", "$baseUrl/$typeUrl")
.build() .build()
@ -108,6 +115,24 @@ abstract class SuperMangasGeneric(
setUrlWithoutDomain(element.attr("href")) setUrlWithoutDomain(element.attr("href"))
} }
private fun paginatorTokenRequest(): Request = GET("$baseUrl/$listPath", headers)
private fun paginatorTokenParse(document: Document): String {
val script = document.select("script:containsData(ajaxSetup)").firstOrNull()
?: return ""
val scriptContent = script.data()
.substringAfter("eval")
.substringBefore("function checkSize")
.substringBefore("eval")
.substringBeforeLast(")")
.replace("return p}", "return p})")
val unpacked = Duktape.create().evaluate(scriptContent) as String
return unpacked.substringAfter("TOKEN_CSRF=\"").substringBefore("\";")
}
override fun popularMangaRequest(page: Int): Request = genericPaginatedRequest(listPath, page = page) override fun popularMangaRequest(page: Int): Request = genericPaginatedRequest(listPath, page = page)
override fun popularMangaParse(response: Response): MangasPage { override fun popularMangaParse(response: Response): MangasPage {
@ -122,9 +147,12 @@ abstract class SuperMangasGeneric(
popularMangaFromElement(element) popularMangaFromElement(element)
} }
val requestBody = response.request().body() as FormBody val requestBody = response.request().body().bodyToString()
val totalPage = result["total_page"].string.toInt() val totalPage = result["total_page"].string.toInt()
val page = requestBody.value("page").toInt() val page = requestBody
.substringAfter("page=")
.substringBefore("&")
.toInt()
val hasNextPage = page < totalPage val hasNextPage = page < totalPage
return MangasPage(mangas, hasNextPage) return MangasPage(mangas, hasNextPage)
@ -311,6 +339,33 @@ abstract class SuperMangasGeneric(
return GET(page.imageUrl!!, newHeaders) return GET(page.imageUrl!!, newHeaders)
} }
private fun paginatorIntercept(chain: Interceptor.Chain): Response {
if (!chain.request().url().toString().contains("paginator.inc")) {
return chain.proceed(chain.request())
}
val csrfTokenRequest = paginatorTokenRequest()
val csrfTokenResponse = chain.proceed(csrfTokenRequest)
val csrfTokenDocument = csrfTokenResponse.asJsoup()
val csrfToken = paginatorTokenParse(csrfTokenDocument)
val totalPage = csrfTokenDocument.select("select.pageSelect option").last()
.attr("value")
val body = chain.request().body()!!
val newBody = "token=" + URLEncoder.encode(csrfToken, "utf-8") +
"&total_page=" + totalPage + "&" + body.bodyToString()
val requestBody = RequestBody.create(body.contentType(), newBody)
val newRequest = chain.request().newBuilder()
.header("Content-Length", newBody.length.toString())
.post(requestBody)
.build()
return chain.proceed(newRequest)
}
protected class Tag(val id: String, name: String) : Filter.TriState(name) protected class Tag(val id: String, name: String) : Filter.TriState(name)
protected class ContentFilter(contents: List<Content>) : Filter.Select<String>( protected class ContentFilter(contents: List<Content>) : Filter.Select<String>(
@ -352,25 +407,34 @@ abstract class SuperMangasGeneric(
else -> SManga.UNKNOWN else -> SManga.UNKNOWN
} }
protected fun Response.asJsonObject(): JsonObject = protected fun Response.asJsonObject(): JsonObject {
JSON_PARSER.parse(body()!!.string().substringAfter("</b>")).obj val body = body()!!.string().substringAfter("</b>")
if (body.isEmpty()) {
throw Exception(BLOCK_MESSAGE)
}
return JSON_PARSER.parse(body).obj
}
private fun RequestBody?.bodyToString(): String {
if (this == null) return ""
val buffer = okio.Buffer()
writeTo(buffer)
return buffer.readUtf8()
}
private fun Map<String, String>.toUrlQueryParams(): String = private fun Map<String, String>.toUrlQueryParams(): String =
map { (k, v) -> "$k=$v" }.joinToString("&") map { (k, v) -> "$k=$v" }.joinToString("&")
private fun FormBody.value(name: String): String {
return (0 until size())
.first { name(it) == name }
.let { value(it) }
}
companion object { companion object {
private const val ACCEPT_COMMON = "text/html,application/xhtml+xml,application/xml;q=0.9," + private const val ACCEPT_COMMON = "text/html,application/xhtml+xml,application/xml;q=0.9," +
"image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9" "image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"
private const val ACCEPT_JSON = "application/json, text/javascript, */*; q=0.01" private const val ACCEPT_JSON = "application/json, text/javascript, */*; q=0.01"
private const val ACCEPT_LANGUAGE = "pt-BR,pt;q=0.9,en-US;q=0.8,en;q=0.7,es;q=0.6,gl;q=0.5" private const val ACCEPT_LANGUAGE = "pt-BR,pt;q=0.9,en-US;q=0.8,en;q=0.7,es;q=0.6,gl;q=0.5"
private const val USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " + private const val USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " +
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.182 Safari/537.36" "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36"
private const val BLOCK_MESSAGE = "O site está bloqueando o Tachiyomi. Tente novamente mais tarde ou migre para outra fonte."
private val JSON_PARSER by lazy { JsonParser() } private val JSON_PARSER by lazy { JsonParser() }

View File

@ -18,7 +18,7 @@ import org.jsoup.Jsoup
@Nsfw @Nsfw
class SuperHentais : SuperMangasGeneric( class SuperHentais : SuperMangasGeneric(
"Super Hentais", "Super Hentais",
"https://superhentais.com", "https://www.superhentais.com",
"hentai-manga" "hentai-manga"
) { ) {
// Hardcode the id because the language wasn't specific. // Hardcode the id because the language wasn't specific.

View File

@ -13,9 +13,9 @@ import okhttp3.Response
class SuperMangas : SuperMangasGeneric( class SuperMangas : SuperMangasGeneric(
"Super Mangás", "Super Mangás",
"https://supermangas.site" "https://www.supermangas.site"
) { ) {
override val client: OkHttpClient = network.cloudflareClient.newBuilder() override val client: OkHttpClient = super.client.newBuilder()
.addInterceptor(::tempCoverImageFixIntercept) .addInterceptor(::tempCoverImageFixIntercept)
.build() .build()