1
0
mirror of https://github.com/TeamNewPipe/NewPipe synced 2025-02-13 01:20:07 +00:00

Detect when WebView is broken and return null poToken

Some old Android devices have a broken WebView implementation, that can't execute the poToken code. This is now detected and the getWebClientPoToken return null instead of throwing an error in such a case, to allow the extractor to try to extract the video data even without a poToken.
This commit is contained in:
Stypox 2025-02-04 11:22:50 +01:00
parent 3fc487310b
commit 21df24abfd
No known key found for this signature in database
GPG Key ID: 4BDF1B40A49FDD23
3 changed files with 48 additions and 4 deletions

View File

@ -1,3 +1,13 @@
package org.schabi.newpipe.util.potoken package org.schabi.newpipe.util.potoken
class PoTokenException(message: String) : Exception(message) class PoTokenException(message: String) : Exception(message)
// to be thrown if the WebView provided by the system is broken
class BadWebViewException(message: String) : Exception(message)
fun buildExceptionForJsError(error: String): Exception {
return if (error.contains("SyntaxError"))
BadWebViewException(error)
else
PoTokenException(error)
}

View File

@ -15,6 +15,7 @@ import org.schabi.newpipe.util.DeviceUtils
object PoTokenProviderImpl : PoTokenProvider { object PoTokenProviderImpl : PoTokenProvider {
val TAG = PoTokenProviderImpl::class.simpleName val TAG = PoTokenProviderImpl::class.simpleName
private val webViewSupported by lazy { DeviceUtils.supportsWebView() } private val webViewSupported by lazy { DeviceUtils.supportsWebView() }
private var webViewBadImpl = false // whether the system has a bad WebView implementation
private object WebPoTokenGenLock private object WebPoTokenGenLock
private var webPoTokenVisitorData: String? = null private var webPoTokenVisitorData: String? = null
@ -22,11 +23,24 @@ object PoTokenProviderImpl : PoTokenProvider {
private var webPoTokenGenerator: PoTokenGenerator? = null private var webPoTokenGenerator: PoTokenGenerator? = null
override fun getWebClientPoToken(videoId: String): PoTokenResult? { override fun getWebClientPoToken(videoId: String): PoTokenResult? {
if (!webViewSupported) { if (!webViewSupported || webViewBadImpl) {
return null return null
} }
return getWebClientPoToken(videoId = videoId, forceRecreate = false) try {
return getWebClientPoToken(videoId = videoId, forceRecreate = false)
} catch (e: RuntimeException) {
// RxJava's Single wraps exceptions into RuntimeErrors, so we need to unwrap them here
when (val cause = e.cause) {
is BadWebViewException -> {
Log.e(TAG, "Could not obtain poToken because WebView is broken", e)
webViewBadImpl = true
return null
}
null -> throw e
else -> throw cause // includes PoTokenException
}
}
} }
/** /**

View File

@ -5,7 +5,9 @@ import android.os.Build
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import android.util.Log import android.util.Log
import android.webkit.ConsoleMessage
import android.webkit.JavascriptInterface import android.webkit.JavascriptInterface
import android.webkit.WebChromeClient
import android.webkit.WebView import android.webkit.WebView
import androidx.annotation.MainThread import androidx.annotation.MainThread
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
@ -40,6 +42,24 @@ class PoTokenWebView private constructor(
// so that we can run async functions and get back the result // so that we can run async functions and get back the result
webView.addJavascriptInterface(this, JS_INTERFACE) webView.addJavascriptInterface(this, JS_INTERFACE)
webView.webChromeClient = object : WebChromeClient() {
override fun onConsoleMessage(m: ConsoleMessage): Boolean {
if (m.message().contains("Uncaught")) {
// There should not be any uncaught errors while executing the code, because
// everything that can fail is guarded by try-catch. Therefore, this likely
// indicates that there was a syntax error in the code, i.e. the WebView only
// supports a really old version of JS.
val fmt = "\"${m.message()}\", source: ${m.sourceId()} (${m.lineNumber()})"
Log.e(TAG, "This WebView implementation is broken: $fmt")
// This can only happen during initialization, where there is no try-catch
onInitializationErrorCloseAndCancel(BadWebViewException(fmt))
}
return super.onConsoleMessage(m)
}
}
} }
/** /**
@ -117,7 +137,7 @@ class PoTokenWebView private constructor(
if (BuildConfig.DEBUG) { if (BuildConfig.DEBUG) {
Log.e(TAG, "Initialization error from JavaScript: $error") Log.e(TAG, "Initialization error from JavaScript: $error")
} }
onInitializationErrorCloseAndCancel(PoTokenException(error)) onInitializationErrorCloseAndCancel(buildExceptionForJsError(error))
} }
/** /**
@ -223,7 +243,7 @@ class PoTokenWebView private constructor(
if (BuildConfig.DEBUG) { if (BuildConfig.DEBUG) {
Log.e(TAG, "obtainPoToken error from JavaScript: $error") Log.e(TAG, "obtainPoToken error from JavaScript: $error")
} }
popPoTokenEmitter(identifier)?.onError(PoTokenException(error)) popPoTokenEmitter(identifier)?.onError(buildExceptionForJsError(error))
} }
/** /**