From 26fa0af5016c98d1cdeb499f119f8aba0159fd4b Mon Sep 17 00:00:00 2001 From: Vetle Ledaal Date: Sun, 31 Jul 2022 16:12:19 +0000 Subject: [PATCH] Koushoku: fix temp ban again (#12825) --- src/en/koushoku/build.gradle | 2 +- .../extension/en/koushoku/Koushoku.kt | 92 +++++-------------- .../en/koushoku/KoushokuWebViewInterceptor.kt | 70 ++++++++++++++ 3 files changed, 94 insertions(+), 70 deletions(-) create mode 100644 src/en/koushoku/src/eu/kanade/tachiyomi/extension/en/koushoku/KoushokuWebViewInterceptor.kt diff --git a/src/en/koushoku/build.gradle b/src/en/koushoku/build.gradle index c3a7f2b40..982e9282a 100644 --- a/src/en/koushoku/build.gradle +++ b/src/en/koushoku/build.gradle @@ -5,7 +5,7 @@ ext { extName = 'Koushoku' pkgNameSuffix = 'en.koushoku' extClass = '.Koushoku' - extVersionCode = 10 + extVersionCode = 11 isNsfw = true } diff --git a/src/en/koushoku/src/eu/kanade/tachiyomi/extension/en/koushoku/Koushoku.kt b/src/en/koushoku/src/eu/kanade/tachiyomi/extension/en/koushoku/Koushoku.kt index 79d158fe6..6bbfd7b96 100644 --- a/src/en/koushoku/src/eu/kanade/tachiyomi/extension/en/koushoku/Koushoku.kt +++ b/src/en/koushoku/src/eu/kanade/tachiyomi/extension/en/koushoku/Koushoku.kt @@ -11,7 +11,6 @@ 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 okhttp3.CacheControl import okhttp3.Headers import okhttp3.HttpUrl import okhttp3.HttpUrl.Companion.toHttpUrlOrNull @@ -38,7 +37,8 @@ class Koushoku : ParsedHttpSource() { override val supportsLatest = true override val client: OkHttpClient = network.cloudflareClient.newBuilder() - .rateLimit(1) + .addInterceptor(KoushokuWebViewInterceptor()) + .rateLimit(1, 4) .build() override fun headersBuilder(): Headers.Builder = super.headersBuilder() @@ -123,9 +123,21 @@ class Koushoku : ParsedHttpSource() { override fun popularMangaNextPageSelector() = latestUpdatesNextPageSelector() override fun popularMangaFromElement(element: Element) = latestUpdatesFromElement(element) + override fun fetchMangaDetails(manga: SManga): Observable { + return if (!manga.initialized) { + super.fetchMangaDetails(manga) + } else { + Observable.just(manga) + } + } + override fun mangaDetailsParse(document: Document) = SManga.create().apply { title = document.selectFirst(".metadata .title").text() + + // Reuse cover from browse thumbnail_url = document.selectFirst(thumbnailSelector).attr("src") + .replace(Regex("/\\d+\\.webp\$"), "/288.webp") + artist = document.select(".metadata .artists a, .metadata .circles a") .joinToString { it.text() } author = artist @@ -139,7 +151,7 @@ class Koushoku : ParsedHttpSource() { override fun chapterListParse(response: Response): List { val document = response.asJsoup() - antiBan(document) + return listOf( SChapter.create().apply { setUrlWithoutDomain(response.request.url.encodedPath) @@ -174,6 +186,14 @@ class Koushoku : ParsedHttpSource() { } } + override fun imageRequest(page: Page): Request { + val newHeaders = headersBuilder() + .add("Origin", baseUrl) + .build() + + return GET(page.imageUrl!!, newHeaders) + } + override fun imageUrlParse(document: Document) = throw UnsupportedOperationException("Not used") override fun getFilterList() = FilterList( @@ -253,70 +273,4 @@ class Koushoku : ParsedHttpSource() { val size = document.selectFirst(".metadata .size td:nth-child(2)") append("Size: ").append(size.text()) } - - // anti-ban - - override fun popularMangaParse(response: Response): MangasPage { - val document = response.asJsoup() - antiBan(document) - - val mangas = document.select(popularMangaSelector()).map { element -> - popularMangaFromElement(element) - } - - val hasNextPage = popularMangaNextPageSelector()?.let { selector -> - document.select(selector).first() - } != null - - return MangasPage(mangas, hasNextPage) - } - - override fun searchMangaParse(response: Response): MangasPage { - val document = response.asJsoup() - antiBan(document) - - val mangas = document.select(searchMangaSelector()).map { element -> - searchMangaFromElement(element) - } - - val hasNextPage = searchMangaNextPageSelector()?.let { selector -> - document.select(selector).first() - } != null - - return MangasPage(mangas, hasNextPage) - } - - override fun latestUpdatesParse(response: Response): MangasPage { - val document = response.asJsoup() - antiBan(document) - - val mangas = document.select(latestUpdatesSelector()).map { element -> - latestUpdatesFromElement(element) - } - - val hasNextPage = latestUpdatesNextPageSelector()?.let { selector -> - document.select(selector).first() - } != null - - return MangasPage(mangas, hasNextPage) - } - - override fun mangaDetailsParse(response: Response): SManga { - return mangaDetailsParse(response.asJsoup()) - } - - override fun pageListParse(response: Response): List { - val document = response.asJsoup() - antiBan(document) - return pageListParse(document) - } - - private fun antiBan(document: Document) { - val styles = document.select("link[rel=stylesheet]") - - styles.forEach { - val request = GET(it.absUrl("href"), headers, CacheControl.FORCE_NETWORK) - runCatching { client.newCall(request).execute().close() } - } - } } diff --git a/src/en/koushoku/src/eu/kanade/tachiyomi/extension/en/koushoku/KoushokuWebViewInterceptor.kt b/src/en/koushoku/src/eu/kanade/tachiyomi/extension/en/koushoku/KoushokuWebViewInterceptor.kt new file mode 100644 index 000000000..93e925bc8 --- /dev/null +++ b/src/en/koushoku/src/eu/kanade/tachiyomi/extension/en/koushoku/KoushokuWebViewInterceptor.kt @@ -0,0 +1,70 @@ +package eu.kanade.tachiyomi.extension.en.koushoku + +import android.annotation.SuppressLint +import android.app.Application +import android.os.Handler +import android.os.Looper +import android.util.Log +import android.webkit.WebView +import android.webkit.WebViewClient +import okhttp3.Interceptor +import okhttp3.Response +import org.jsoup.Jsoup +import uy.kohesive.injekt.Injekt +import uy.kohesive.injekt.api.get +import java.io.IOException +import java.util.concurrent.CountDownLatch + +class KoushokuWebViewInterceptor : Interceptor { + + override fun intercept(chain: Interceptor.Chain): Response { + val request = chain.request() + val response = chain.proceed(request) + + val responseBody = response.peekBody(1 * 1024 * 1024).toString() + val document = Jsoup.parse(responseBody) + if (document.selectFirst("h1")?.text()?.contains(Regex("banned$")) == true) { + throw Exception("You have been banned. Check WebView for details.") + } else if (response.headers("Content-Type").any { it.contains("text/html") }) { + try { + proceedWithWebView(response) + } catch (e: Exception) { + throw IOException(e) + } + } + + return response + } + + @SuppressLint("SetJavaScriptEnabled") + private fun proceedWithWebView(response: Response) { + val latch = CountDownLatch(1) + + val handler = Handler(Looper.getMainLooper()) + + handler.post { + val webview = WebView(Injekt.get()) + with(webview.settings) { + javaScriptEnabled = true + loadsImagesAutomatically = false + userAgentString = response.request.header("User-Agent") + } + + webview.webViewClient = object : WebViewClient() { + override fun onPageFinished(view: WebView, url: String) { + latch.countDown() + } + } + + webview.loadDataWithBaseURL( + response.request.url.toString(), + response.peekBody(1 * 1024 * 1024).toString(), + "text/html", + "utf-8", + null + ) + } + + latch.await() + } +}