Skip to content

Commit 21df24a

Browse files
committed
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.
1 parent 3fc4873 commit 21df24a

File tree

3 files changed

+48
-4
lines changed

3 files changed

+48
-4
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
11
package org.schabi.newpipe.util.potoken
22

33
class PoTokenException(message: String) : Exception(message)
4+
5+
// to be thrown if the WebView provided by the system is broken
6+
class BadWebViewException(message: String) : Exception(message)
7+
8+
fun buildExceptionForJsError(error: String): Exception {
9+
return if (error.contains("SyntaxError"))
10+
BadWebViewException(error)
11+
else
12+
PoTokenException(error)
13+
}

app/src/main/java/org/schabi/newpipe/util/potoken/PoTokenProviderImpl.kt

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,32 @@ import org.schabi.newpipe.util.DeviceUtils
1515
object PoTokenProviderImpl : PoTokenProvider {
1616
val TAG = PoTokenProviderImpl::class.simpleName
1717
private val webViewSupported by lazy { DeviceUtils.supportsWebView() }
18+
private var webViewBadImpl = false // whether the system has a bad WebView implementation
1819

1920
private object WebPoTokenGenLock
2021
private var webPoTokenVisitorData: String? = null
2122
private var webPoTokenStreamingPot: String? = null
2223
private var webPoTokenGenerator: PoTokenGenerator? = null
2324

2425
override fun getWebClientPoToken(videoId: String): PoTokenResult? {
25-
if (!webViewSupported) {
26+
if (!webViewSupported || webViewBadImpl) {
2627
return null
2728
}
2829

29-
return getWebClientPoToken(videoId = videoId, forceRecreate = false)
30+
try {
31+
return getWebClientPoToken(videoId = videoId, forceRecreate = false)
32+
} catch (e: RuntimeException) {
33+
// RxJava's Single wraps exceptions into RuntimeErrors, so we need to unwrap them here
34+
when (val cause = e.cause) {
35+
is BadWebViewException -> {
36+
Log.e(TAG, "Could not obtain poToken because WebView is broken", e)
37+
webViewBadImpl = true
38+
return null
39+
}
40+
null -> throw e
41+
else -> throw cause // includes PoTokenException
42+
}
43+
}
3044
}
3145

3246
/**

app/src/main/java/org/schabi/newpipe/util/potoken/PoTokenWebView.kt

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ import android.os.Build
55
import android.os.Handler
66
import android.os.Looper
77
import android.util.Log
8+
import android.webkit.ConsoleMessage
89
import android.webkit.JavascriptInterface
10+
import android.webkit.WebChromeClient
911
import android.webkit.WebView
1012
import androidx.annotation.MainThread
1113
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
@@ -40,6 +42,24 @@ class PoTokenWebView private constructor(
4042

4143
// so that we can run async functions and get back the result
4244
webView.addJavascriptInterface(this, JS_INTERFACE)
45+
46+
webView.webChromeClient = object : WebChromeClient() {
47+
override fun onConsoleMessage(m: ConsoleMessage): Boolean {
48+
if (m.message().contains("Uncaught")) {
49+
// There should not be any uncaught errors while executing the code, because
50+
// everything that can fail is guarded by try-catch. Therefore, this likely
51+
// indicates that there was a syntax error in the code, i.e. the WebView only
52+
// supports a really old version of JS.
53+
54+
val fmt = "\"${m.message()}\", source: ${m.sourceId()} (${m.lineNumber()})"
55+
Log.e(TAG, "This WebView implementation is broken: $fmt")
56+
57+
// This can only happen during initialization, where there is no try-catch
58+
onInitializationErrorCloseAndCancel(BadWebViewException(fmt))
59+
}
60+
return super.onConsoleMessage(m)
61+
}
62+
}
4363
}
4464

4565
/**
@@ -117,7 +137,7 @@ class PoTokenWebView private constructor(
117137
if (BuildConfig.DEBUG) {
118138
Log.e(TAG, "Initialization error from JavaScript: $error")
119139
}
120-
onInitializationErrorCloseAndCancel(PoTokenException(error))
140+
onInitializationErrorCloseAndCancel(buildExceptionForJsError(error))
121141
}
122142

123143
/**
@@ -223,7 +243,7 @@ class PoTokenWebView private constructor(
223243
if (BuildConfig.DEBUG) {
224244
Log.e(TAG, "obtainPoToken error from JavaScript: $error")
225245
}
226-
popPoTokenEmitter(identifier)?.onError(PoTokenException(error))
246+
popPoTokenEmitter(identifier)?.onError(buildExceptionForJsError(error))
227247
}
228248

229249
/**

0 commit comments

Comments
 (0)