diff --git a/app/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt index 69fa75e7d..24cc485c5 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt @@ -3,7 +3,10 @@ package eu.kanade.tachiyomi.network import android.content.Context import android.os.Build import exh.log.maybeInjectEHLogger +import exh.patch.MANGADEX_DOMAIN +import exh.patch.MANGADEX_SOURCE_ID import exh.patch.attachMangaDexLogin +import exh.patch.detectCaptchas import okhttp3.* import java.io.File import java.io.IOException @@ -33,6 +36,7 @@ open class NetworkHelper(context: Context) { open val cloudflareClient = client.newBuilder() .addInterceptor(CloudflareInterceptor(context)) .attachMangaDexLogin() + .detectCaptchas(context, MANGADEX_SOURCE_ID, listOf(MANGADEX_DOMAIN)) .build() private fun OkHttpClient.Builder.enableTLS12(): OkHttpClient.Builder { diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/HttpSource.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/HttpSource.kt index cf7df3608..900b3e635 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/HttpSource.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/online/HttpSource.kt @@ -6,9 +6,8 @@ import eu.kanade.tachiyomi.data.preference.getOrDefault import eu.kanade.tachiyomi.network.* import eu.kanade.tachiyomi.source.CatalogueSource import eu.kanade.tachiyomi.source.model.* +import exh.patch.detectCaptchas import exh.source.DelegatedHttpSource -import exh.ui.captcha.BrowserActionActivity -import exh.util.interceptAsHtml import okhttp3.* import rx.Observable import uy.kohesive.injekt.Injekt @@ -79,22 +78,10 @@ abstract class HttpSource : CatalogueSource { * Default network client for doing requests. */ open val client: OkHttpClient - get() = delegate?.baseHttpClient ?: network.client.newBuilder().addInterceptor { chain -> - // Automatic captcha detection - val response = chain.proceed(chain.request()) - if(!response.isSuccessful) { - response.interceptAsHtml { doc -> - if (doc.getElementsByClass("g-recaptcha").isNotEmpty()) { - // Found it, allow the user to solve this thing - BrowserActionActivity.launchUniversal( - Injekt.get(), - this, - chain.request().url().toString() - ) - } - } - } else response - }.build() + get() = delegate?.baseHttpClient ?: network.client + .newBuilder() + .detectCaptchas(Injekt.get(), id, null) + .build() /** * Headers builder for requests. Implementations can override this method for custom headers. diff --git a/app/src/main/java/exh/patch/MangaDexLogin.kt b/app/src/main/java/exh/patch/MangaDexLogin.kt index bd2fec759..9092b6e67 100644 --- a/app/src/main/java/exh/patch/MangaDexLogin.kt +++ b/app/src/main/java/exh/patch/MangaDexLogin.kt @@ -27,7 +27,7 @@ private fun verifyComplete(url: String): Boolean { fun OkHttpClient.Builder.attachMangaDexLogin() = addInterceptor { chain -> val response = chain.proceed(chain.request()) - if(response.request().url().host() == "mangadex.org") { + if(response.request().url().host() == MANGADEX_DOMAIN) { response.interceptAsHtml { doc -> if (doc.title().trim().equals("Login - MangaDex", true)) { BrowserActionActivity.launchAction( @@ -36,7 +36,7 @@ fun OkHttpClient.Builder.attachMangaDexLogin() = HIDE_SCRIPT, "https://mangadex.org/login", "Login", - (Injekt.get().get(2499283573021220255) as? HttpSource)?.headers?.toMultimap()?.mapValues { + (Injekt.get().get(MANGADEX_SOURCE_ID) as? HttpSource)?.headers?.toMultimap()?.mapValues { it.value.joinToString(",") } ?: emptyMap() ) @@ -44,3 +44,6 @@ fun OkHttpClient.Builder.attachMangaDexLogin() = } } else response } + +const val MANGADEX_SOURCE_ID = 2499283573021220255 +const val MANGADEX_DOMAIN = "mangadex.org" diff --git a/app/src/main/java/exh/patch/UniversalCaptchaDetection.kt b/app/src/main/java/exh/patch/UniversalCaptchaDetection.kt new file mode 100644 index 000000000..d5a1c8044 --- /dev/null +++ b/app/src/main/java/exh/patch/UniversalCaptchaDetection.kt @@ -0,0 +1,28 @@ +package exh.patch + +import android.content.Context +import exh.ui.captcha.BrowserActionActivity +import exh.util.interceptAsHtml +import okhttp3.OkHttpClient + +fun OkHttpClient.Builder.detectCaptchas(context: Context, sourceId: Long, domains: List? = null): OkHttpClient.Builder { + return addInterceptor { chain -> + // Automatic captcha detection + val response = chain.proceed(chain.request()) + if(!response.isSuccessful) { + if(domains != null && response.request().url().host() !in domains) + return@addInterceptor response + + response.interceptAsHtml { doc -> + if (doc.getElementsByClass("g-recaptcha").isNotEmpty()) { + // Found it, allow the user to solve this thing + BrowserActionActivity.launchUniversal( + context, + sourceId, + chain.request().url().toString() + ) + } + } + } else response + } +} \ No newline at end of file diff --git a/app/src/main/java/exh/ui/captcha/BrowserActionActivity.kt b/app/src/main/java/exh/ui/captcha/BrowserActionActivity.kt index 799fd78e9..924e26615 100644 --- a/app/src/main/java/exh/ui/captcha/BrowserActionActivity.kt +++ b/app/src/main/java/exh/ui/captcha/BrowserActionActivity.kt @@ -648,6 +648,17 @@ class BrowserActionActivity : AppCompatActivity() { context.startActivity(intent) } + fun launchUniversal(context: Context, + sourceId: Long, + url: String) { + val intent = baseIntent(context).apply { + putExtra(SOURCE_ID_EXTRA, sourceId) + putExtra(URL_EXTRA, url) + } + + context.startActivity(intent) + } + fun launchAction(context: Context, completionVerifier: ActionCompletionVerifier, script: String?, diff --git a/app/src/main/java/exh/util/OkHttpUtil.kt b/app/src/main/java/exh/util/OkHttpUtil.kt index bdafb258f..28ace9c3f 100644 --- a/app/src/main/java/exh/util/OkHttpUtil.kt +++ b/app/src/main/java/exh/util/OkHttpUtil.kt @@ -8,24 +8,24 @@ import org.jsoup.nodes.Document fun Response.interceptAsHtml(block: (Document) -> Unit): Response { val body = body() - if(body != null) { - if (body.contentType()?.type() == "text" - && body.contentType()?.subtype() == "html") { - val bodyString = body.string() - val rebuiltResponse = newBuilder() - .body(ResponseBody.create(body.contentType(), bodyString)) - .build() - try { - // Search for captcha - val parsed = asJsoup(html = bodyString) - block(parsed) - } catch (t: Throwable) { - // Ignore all errors - XLog.w("Interception error!", t) - } - - return rebuiltResponse + if (body?.contentType()?.type() == "text" + && body.contentType()?.subtype() == "html") { + val bodyString = body.string() + val rebuiltResponse = newBuilder() + .body(ResponseBody.create(body.contentType(), bodyString)) + .build() + try { + // Search for captcha + val parsed = asJsoup(html = bodyString) + block(parsed) + } catch (t: Throwable) { + // Ignore all errors + XLog.w("Interception error!", t) + } finally { + close() } + + return rebuiltResponse } return this } \ No newline at end of file