From 55fb24a51f145a8d5c85bf5d7407d9c5aacd690b Mon Sep 17 00:00:00 2001 From: Blatzar <46196380+Blatzar@users.noreply.github.com> Date: Sun, 16 Jan 2022 16:35:06 +0100 Subject: [PATCH] made WebViewResolver.kt more powerful --- .../cloudstream3/network/WebViewResolver.kt | 86 +++++++++++++++---- 1 file changed, 68 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/network/WebViewResolver.kt b/app/src/main/java/com/lagradost/cloudstream3/network/WebViewResolver.kt index 32bf1db3..81eba446 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/network/WebViewResolver.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/network/WebViewResolver.kt @@ -8,24 +8,40 @@ import com.lagradost.cloudstream3.USER_AGENT import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.utils.Coroutines.main import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.runBlocking import okhttp3.Interceptor import okhttp3.Request import okhttp3.Response import java.net.URI import java.util.concurrent.TimeUnit +import kotlin.concurrent.thread + +/** + * When used as Interceptor additionalUrls cannot be returned, use WebViewResolver(...).resolveUsingWebView(...) + * @param interceptUrl will stop the WebView when reaching this url. + * @param additionalUrls this will make resolveUsingWebView also return all other requests matching the list of Regex. + * */ +class WebViewResolver(val interceptUrl: Regex, val additionalUrls: List = emptyList()) : + Interceptor { -class WebViewResolver(val interceptUrl: Regex) : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { val request = chain.request() return runBlocking { - val fixedRequest = resolveUsingWebView(request) + val fixedRequest = resolveUsingWebView(request).first return@runBlocking chain.proceed(fixedRequest ?: request) } } + /** + * @param requestCallBack asynchronously return matched requests by either interceptUrl or additionalUrls. + * @return the final request (by interceptUrl) and all the collected urls (by additionalUrls). + * */ @SuppressLint("SetJavaScriptEnabled") - suspend fun resolveUsingWebView(request: Request): Request? { + suspend fun resolveUsingWebView( + request: Request, + requestCallBack: (Request) -> Unit = {} + ): Pair> { val url = request.url.toString() val headers = request.headers println("Initial web-view request: $url") @@ -41,17 +57,21 @@ class WebViewResolver(val interceptUrl: Regex) : Interceptor { } var fixedRequest: Request? = null + val extraRequestList = mutableListOf() main { // Useful for debugging // WebView.setWebContentsDebuggingEnabled(true) webView = WebView( - AcraApplication.context ?: throw RuntimeException("No base context in WebViewResolver") + AcraApplication.context + ?: throw RuntimeException("No base context in WebViewResolver") ).apply { // Bare minimum to bypass captcha settings.javaScriptEnabled = true settings.domStorageEnabled = true settings.userAgentString = USER_AGENT + // Blocks unnecessary images, remove if captcha fucks. + settings.blockNetworkImage = true } webView?.webViewClient = object : WebViewClient() { @@ -63,23 +83,19 @@ class WebViewResolver(val interceptUrl: Regex) : Interceptor { // println("Loading WebView URL: $webViewUrl") if (interceptUrl.containsMatchIn(webViewUrl)) { - fixedRequest = getRequestCreator( - webViewUrl, - request.requestHeaders, - null, - mapOf(), - mapOf(), - 10, - TimeUnit.MINUTES - ) - + fixedRequest = request.toRequest().also(requestCallBack) println("Web-view request finished: $webViewUrl") destroyWebView() return null } + if (additionalUrls.any { it.containsMatchIn(webViewUrl) }) { + extraRequestList.add(request.toRequest().also(requestCallBack)) + } + // Suppress image requests as we don't display them anywhere // Less data, low chance of causing issues. + // blockNetworkImage also does this job but i will keep it for the future. val blacklistedFiles = listOf(".jpg", ".png", ".webp", ".jpeg", ".webm", ".mp4") /** NOTE! request.requestHeaders is not perfect! @@ -97,7 +113,10 @@ class WebViewResolver(val interceptUrl: Regex) : Interceptor { null ) - webViewUrl.contains("recaptcha") -> super.shouldInterceptRequest(view, request) + webViewUrl.contains("recaptcha") -> super.shouldInterceptRequest( + view, + request + ) request.method == "GET" -> app.get( webViewUrl, @@ -115,7 +134,11 @@ class WebViewResolver(val interceptUrl: Regex) : Interceptor { } } - override fun onReceivedSslError(view: WebView?, handler: SslErrorHandler?, error: SslError?) { + override fun onReceivedSslError( + view: WebView?, + handler: SslErrorHandler?, + error: SslError? + ) { handler?.proceed() // Ignore ssl issues } } @@ -130,14 +153,41 @@ class WebViewResolver(val interceptUrl: Regex) : Interceptor { // A bit sloppy, but couldn't find a better way while (loop < totalTime / delayTime) { - if (fixedRequest != null) return fixedRequest + if (fixedRequest != null) return fixedRequest to extraRequestList delay(delayTime) loop += 1 } println("Web-view timeout after ${totalTime / 1000}s") destroyWebView() - return null + return null to extraRequestList + } + + fun WebResourceRequest.toRequest(): Request { + val webViewUrl = this.url.toString() + + return when (this.method) { + "POST" -> postRequestCreator( + webViewUrl, + this.requestHeaders, + null, + emptyMap(), + emptyMap(), + emptyMap(), + 10, + TimeUnit.MINUTES + ) +// "GET", + else -> getRequestCreator( + webViewUrl, + this.requestHeaders, + null, + emptyMap(), + emptyMap(), + 10, + TimeUnit.MINUTES + ) + } } fun Response.toWebResourceResponse(): WebResourceResponse {