Fix incorrect ResponseBody parsing (#12893)
* Fix incorrect ResponseBody parsing * enable rate limit
This commit is contained in:
parent
5d8494e775
commit
e0e3afa793
|
@ -5,7 +5,7 @@ ext {
|
||||||
extName = 'Koushoku'
|
extName = 'Koushoku'
|
||||||
pkgNameSuffix = 'en.koushoku'
|
pkgNameSuffix = 'en.koushoku'
|
||||||
extClass = '.Koushoku'
|
extClass = '.Koushoku'
|
||||||
extVersionCode = 12
|
extVersionCode = 13
|
||||||
isNsfw = true
|
isNsfw = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ import eu.kanade.tachiyomi.source.online.ParsedHttpSource
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import okhttp3.Headers
|
import okhttp3.Headers
|
||||||
import okhttp3.HttpUrl
|
import okhttp3.HttpUrl
|
||||||
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
|
@ -20,15 +21,15 @@ import okhttp3.Response
|
||||||
import org.jsoup.nodes.Document
|
import org.jsoup.nodes.Document
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import java.net.URL
|
|
||||||
|
|
||||||
class Koushoku : ParsedHttpSource() {
|
class Koushoku : ParsedHttpSource() {
|
||||||
companion object {
|
companion object {
|
||||||
const val PREFIX_ID_SEARCH = "id:"
|
const val PREFIX_ID_SEARCH = "id:"
|
||||||
|
|
||||||
val archiveRegex = "/archive/(\\d+)".toRegex()
|
const val thumbnailSelector = "figure img"
|
||||||
const val thumbnailSelector = ".thumbnail img"
|
const val magazinesSelector = ".metadata a[href^='/magazines/']"
|
||||||
const val magazinesSelector = ".metadata .magazines a"
|
|
||||||
|
private val PATTERN_IMAGES = "(.+/)(\\d+)(.*)".toRegex()
|
||||||
}
|
}
|
||||||
|
|
||||||
override val baseUrl = "https://koushoku.org"
|
override val baseUrl = "https://koushoku.org"
|
||||||
|
@ -42,17 +43,17 @@ class Koushoku : ParsedHttpSource() {
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
override fun headersBuilder(): Headers.Builder = super.headersBuilder()
|
override fun headersBuilder(): Headers.Builder = super.headersBuilder()
|
||||||
.set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36")
|
.set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36")
|
||||||
.add("Referer", "$baseUrl/")
|
.add("Referer", "$baseUrl/")
|
||||||
|
|
||||||
override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/?page=$page", headers)
|
override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/?page=$page", headers)
|
||||||
override fun latestUpdatesSelector() = "#archives.feed .entries > .entry"
|
override fun latestUpdatesSelector() = "#archives.feed .entries > .entry"
|
||||||
override fun latestUpdatesNextPageSelector() = "#archives.feed .pagination .next"
|
override fun latestUpdatesNextPageSelector() = "footer nav li:has(a.active) + li:not(:last-child) > a"
|
||||||
|
|
||||||
override fun latestUpdatesFromElement(element: Element) = SManga.create().apply {
|
override fun latestUpdatesFromElement(element: Element) = SManga.create().apply {
|
||||||
setUrlWithoutDomain(element.select("a").attr("href"))
|
setUrlWithoutDomain(element.selectFirst("a").attr("href"))
|
||||||
title = element.select(".title").text()
|
title = element.selectFirst("[title]").attr("title")
|
||||||
thumbnail_url = element.select(thumbnailSelector).attr("src")
|
thumbnail_url = element.selectFirst(thumbnailSelector).absUrl("src")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun searchMangaByIdRequest(id: String) = GET("$baseUrl/archive/$id", headers)
|
private fun searchMangaByIdRequest(id: String) = GET("$baseUrl/archive/$id", headers)
|
||||||
|
@ -131,13 +132,13 @@ class Koushoku : ParsedHttpSource() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun mangaDetailsParse(document: Document) = SManga.create().apply {
|
override fun mangaDetailsParse(document: Document) = SManga.create().apply {
|
||||||
title = document.selectFirst(".metadata .title").text()
|
title = document.selectFirst(".metadata > h1").text()
|
||||||
|
|
||||||
// Reuse cover from browse
|
// Reuse cover from browse
|
||||||
thumbnail_url = document.selectFirst(thumbnailSelector).attr("src")
|
thumbnail_url = document.selectFirst(thumbnailSelector).absUrl("src")
|
||||||
.replace(Regex("/\\d+\\.webp\$"), "/288.webp")
|
.replace(Regex("/\\d+\\.webp\$"), "/288.webp")
|
||||||
|
|
||||||
artist = document.select(".metadata .artists a, .metadata .circles a")
|
artist = document.select(".metadata a[href^='/artists/'], .metadata a[href^='/circles/']")
|
||||||
.joinToString { it.text() }
|
.joinToString { it.text() }
|
||||||
author = artist
|
author = artist
|
||||||
genre = document.select(".metadata .tags a, $magazinesSelector")
|
genre = document.select(".metadata .tags a, $magazinesSelector")
|
||||||
|
@ -153,7 +154,7 @@ class Koushoku : ParsedHttpSource() {
|
||||||
SChapter.create().apply {
|
SChapter.create().apply {
|
||||||
setUrlWithoutDomain(response.request.url.encodedPath)
|
setUrlWithoutDomain(response.request.url.encodedPath)
|
||||||
name = "Chapter"
|
name = "Chapter"
|
||||||
date_upload = document.select(".metadata .published td:nth-child(2)")
|
date_upload = document.select("tr > td:first-child:contains(Uploaded Date) + td")
|
||||||
.attr("data-unix").toLong() * 1000
|
.attr("data-unix").toLong() * 1000
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -171,22 +172,26 @@ class Koushoku : ParsedHttpSource() {
|
||||||
if (totalPages == 0)
|
if (totalPages == 0)
|
||||||
throw UnsupportedOperationException("Error: Empty pages (try Webview)")
|
throw UnsupportedOperationException("Error: Empty pages (try Webview)")
|
||||||
|
|
||||||
val id = archiveRegex.find(document.location())?.groups?.get(1)?.value
|
val url = document.selectFirst(".main img, main img").absUrl("src")
|
||||||
if (id.isNullOrEmpty())
|
val match = PATTERN_IMAGES.find(url)!!
|
||||||
throw UnsupportedOperationException("Error: Unknown archive id")
|
val prefix = match.groupValues[1]
|
||||||
|
val suffix = match.groupValues[3]
|
||||||
val url = URL(document.selectFirst(".main img, main img").attr("src"))
|
|
||||||
val origin = "${url.protocol}://${url.host}"
|
|
||||||
|
|
||||||
return (1..totalPages).map {
|
return (1..totalPages).map {
|
||||||
Page(it, "", "$origin/data/$id/$it.jpg")
|
Page(it, "", "$prefix$it$suffix")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun imageRequest(page: Page): Request {
|
override fun imageRequest(page: Page): Request {
|
||||||
val newHeaders = headersBuilder()
|
val url = page.imageUrl!!.toHttpUrl()
|
||||||
.add("Origin", baseUrl)
|
|
||||||
.build()
|
val newHeaders = if (baseUrl.toHttpUrl().host != url.host) {
|
||||||
|
headersBuilder()
|
||||||
|
.add("Origin", baseUrl)
|
||||||
|
.build()
|
||||||
|
} else {
|
||||||
|
headers
|
||||||
|
}
|
||||||
|
|
||||||
return GET(page.imageUrl!!, newHeaders)
|
return GET(page.imageUrl!!, newHeaders)
|
||||||
}
|
}
|
||||||
|
@ -257,17 +262,17 @@ class Koushoku : ParsedHttpSource() {
|
||||||
append("\n")
|
append("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
val parodies = document.select(".metadata .parodies a")
|
val parodies = document.select(".metadata a[href^='/parodies/']")
|
||||||
if (parodies.isNotEmpty()) {
|
if (parodies.isNotEmpty()) {
|
||||||
append("Parodies: ")
|
append("Parodies: ")
|
||||||
append(parodies.joinToString { it.text() })
|
append(parodies.joinToString { it.text() })
|
||||||
append("\n")
|
append("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
val pages = document.selectFirst(".metadata .pages td:nth-child(2)")
|
val pages = document.selectFirst("tr > td:first-child:contains(Pages) + td")
|
||||||
append("Pages: ").append(pages.text()).append("\n")
|
append("Pages: ").append(pages.text()).append("\n")
|
||||||
|
|
||||||
val size = document.selectFirst(".metadata .size td:nth-child(2)")
|
val size = document.selectFirst("tr > td:first-child:contains(Size) + td")
|
||||||
append("Size: ").append(size.text())
|
append("Size: ").append(size.text())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package eu.kanade.tachiyomi.extension.en.koushoku
|
package eu.kanade.tachiyomi.extension.en.koushoku
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
|
@ -21,46 +20,48 @@ class KoushokuWebViewInterceptor : Interceptor {
|
||||||
val response = chain.proceed(request)
|
val response = chain.proceed(request)
|
||||||
|
|
||||||
if (response.headers("Content-Type").any { it.contains("text/html") }) {
|
if (response.headers("Content-Type").any { it.contains("text/html") }) {
|
||||||
val responseBody = response.peekBody(1 * 1024 * 1024).toString()
|
val responseBody = response.peekBody(1 * 1024 * 1024).string()
|
||||||
val document = Jsoup.parse(responseBody)
|
if (response.code == 403) {
|
||||||
|
val document = Jsoup.parse(responseBody)
|
||||||
if (document.selectFirst("h1")?.text()?.contains(Regex("banned$")) == true) {
|
if (document.selectFirst("h1")?.text()?.contains(Regex("banned$")) == true) {
|
||||||
throw IOException("You have been banned. Check WebView for details.")
|
throw IOException("You have been banned. Check WebView for details.")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
if (response.networkResponse != null) {
|
||||||
proceedWithWebView(response)
|
try {
|
||||||
} catch (e: Exception) {
|
proceedWithWebView(response, responseBody)
|
||||||
throw IOException(e)
|
} catch (e: Exception) {
|
||||||
|
throw IOException(e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("SetJavaScriptEnabled")
|
private fun proceedWithWebView(response: Response, responseBody: String) {
|
||||||
private fun proceedWithWebView(response: Response) {
|
|
||||||
val latch = CountDownLatch(1)
|
val latch = CountDownLatch(1)
|
||||||
|
|
||||||
val handler = Handler(Looper.getMainLooper())
|
val handler = Handler(Looper.getMainLooper())
|
||||||
|
|
||||||
handler.post {
|
handler.post {
|
||||||
val webview = WebView(Injekt.get<Application>())
|
val webView = WebView(Injekt.get<Application>())
|
||||||
with(webview.settings) {
|
with(webView.settings) {
|
||||||
javaScriptEnabled = true
|
|
||||||
loadsImagesAutomatically = false
|
loadsImagesAutomatically = false
|
||||||
userAgentString = response.request.header("User-Agent")
|
userAgentString = response.request.header("User-Agent")
|
||||||
}
|
}
|
||||||
|
|
||||||
webview.webViewClient = object : WebViewClient() {
|
webView.webViewClient = object : WebViewClient() {
|
||||||
override fun onPageFinished(view: WebView, url: String) {
|
override fun onPageFinished(view: WebView, url: String) {
|
||||||
|
webView.stopLoading()
|
||||||
|
webView.destroy()
|
||||||
latch.countDown()
|
latch.countDown()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
webview.loadDataWithBaseURL(
|
webView.loadDataWithBaseURL(
|
||||||
response.request.url.toString(),
|
response.request.url.toString(),
|
||||||
response.peekBody(1 * 1024 * 1024).toString(),
|
responseBody,
|
||||||
"text/html",
|
"text/html",
|
||||||
"utf-8",
|
"utf-8",
|
||||||
null
|
null
|
||||||
|
|
Loading…
Reference in New Issue