mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
made WebViewResolver.kt more powerful
This commit is contained in:
parent
ef9d6e11a7
commit
55fb24a51f
1 changed files with 68 additions and 18 deletions
|
@ -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 {
|
||||||
|
|
Loading…
Reference in a new issue