made WebViewResolver.kt more powerful

This commit is contained in:
Blatzar 2022-01-16 16:35:06 +01:00
parent ef9d6e11a7
commit 55fb24a51f

View file

@ -8,24 +8,40 @@ import com.lagradost.cloudstream3.USER_AGENT
import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.utils.Coroutines.main import com.lagradost.cloudstream3.utils.Coroutines.main
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import okhttp3.Interceptor import okhttp3.Interceptor
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import java.net.URI import java.net.URI
import java.util.concurrent.TimeUnit 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<Regex> = emptyList()) :
Interceptor {
class WebViewResolver(val interceptUrl: Regex) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response { override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request() val request = chain.request()
return runBlocking { return runBlocking {
val fixedRequest = resolveUsingWebView(request) val fixedRequest = resolveUsingWebView(request).first
return@runBlocking chain.proceed(fixedRequest ?: request) 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") @SuppressLint("SetJavaScriptEnabled")
suspend fun resolveUsingWebView(request: Request): Request? { suspend fun resolveUsingWebView(
request: Request,
requestCallBack: (Request) -> Unit = {}
): Pair<Request?, List<Request>> {
val url = request.url.toString() val url = request.url.toString()
val headers = request.headers val headers = request.headers
println("Initial web-view request: $url") println("Initial web-view request: $url")
@ -41,17 +57,21 @@ class WebViewResolver(val interceptUrl: Regex) : Interceptor {
} }
var fixedRequest: Request? = null var fixedRequest: Request? = null
val extraRequestList = mutableListOf<Request>()
main { main {
// Useful for debugging // Useful for debugging
// WebView.setWebContentsDebuggingEnabled(true) // WebView.setWebContentsDebuggingEnabled(true)
webView = WebView( webView = WebView(
AcraApplication.context ?: throw RuntimeException("No base context in WebViewResolver") AcraApplication.context
?: throw RuntimeException("No base context in WebViewResolver")
).apply { ).apply {
// Bare minimum to bypass captcha // Bare minimum to bypass captcha
settings.javaScriptEnabled = true settings.javaScriptEnabled = true
settings.domStorageEnabled = true settings.domStorageEnabled = true
settings.userAgentString = USER_AGENT settings.userAgentString = USER_AGENT
// Blocks unnecessary images, remove if captcha fucks.
settings.blockNetworkImage = true
} }
webView?.webViewClient = object : WebViewClient() { webView?.webViewClient = object : WebViewClient() {
@ -63,23 +83,19 @@ class WebViewResolver(val interceptUrl: Regex) : Interceptor {
// println("Loading WebView URL: $webViewUrl") // println("Loading WebView URL: $webViewUrl")
if (interceptUrl.containsMatchIn(webViewUrl)) { if (interceptUrl.containsMatchIn(webViewUrl)) {
fixedRequest = getRequestCreator( fixedRequest = request.toRequest().also(requestCallBack)
webViewUrl,
request.requestHeaders,
null,
mapOf(),
mapOf(),
10,
TimeUnit.MINUTES
)
println("Web-view request finished: $webViewUrl") println("Web-view request finished: $webViewUrl")
destroyWebView() destroyWebView()
return null return null
} }
if (additionalUrls.any { it.containsMatchIn(webViewUrl) }) {
extraRequestList.add(request.toRequest().also(requestCallBack))
}
// Suppress image requests as we don't display them anywhere // Suppress image requests as we don't display them anywhere
// Less data, low chance of causing issues. // 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") val blacklistedFiles = listOf(".jpg", ".png", ".webp", ".jpeg", ".webm", ".mp4")
/** NOTE! request.requestHeaders is not perfect! /** NOTE! request.requestHeaders is not perfect!
@ -97,7 +113,10 @@ class WebViewResolver(val interceptUrl: Regex) : Interceptor {
null null
) )
webViewUrl.contains("recaptcha") -> super.shouldInterceptRequest(view, request) webViewUrl.contains("recaptcha") -> super.shouldInterceptRequest(
view,
request
)
request.method == "GET" -> app.get( request.method == "GET" -> app.get(
webViewUrl, 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 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 // A bit sloppy, but couldn't find a better way
while (loop < totalTime / delayTime) { while (loop < totalTime / delayTime) {
if (fixedRequest != null) return fixedRequest if (fixedRequest != null) return fixedRequest to extraRequestList
delay(delayTime) delay(delayTime)
loop += 1 loop += 1
} }
println("Web-view timeout after ${totalTime / 1000}s") println("Web-view timeout after ${totalTime / 1000}s")
destroyWebView() 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 { fun Response.toWebResourceResponse(): WebResourceResponse {