Skip to content

Commit f856bd9

Browse files
StypoxAudricV
authored andcommitted
Recreate poToken generator if current is broken
This will be tried only once, and afterwards an error will be thrown
1 parent 0066b32 commit f856bd9

2 files changed

Lines changed: 61 additions & 22 deletions

File tree

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

Lines changed: 59 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package org.schabi.newpipe.util.potoken
22

3+
import android.os.Handler
4+
import android.os.Looper
35
import android.util.Log
46
import org.schabi.newpipe.App
57
import org.schabi.newpipe.extractor.NewPipe
@@ -22,33 +24,68 @@ object PoTokenProviderImpl : PoTokenProvider {
2224
return null
2325
}
2426

25-
val (poTokenGenerator, visitorData, streamingPot) = synchronized(WebPoTokenGenLock) {
26-
if (webPoTokenGenerator == null || webPoTokenGenerator!!.isExpired()) {
27-
webPoTokenGenerator = PoTokenWebView.newPoTokenGenerator(App.getApp()).blockingGet()
28-
webPoTokenVisitorData = YoutubeParsingHelper
29-
.randomVisitorData(NewPipe.getPreferredContentCountry())
27+
return getWebClientPoToken(videoId = videoId, forceRecreate = false)
28+
}
29+
30+
/**
31+
* @param forceRecreate whether to force the recreation of [webPoTokenGenerator], to be used in
32+
* case the current [webPoTokenGenerator] threw an error last time
33+
* [PoTokenGenerator.generatePoToken] was called
34+
*/
35+
private fun getWebClientPoToken(videoId: String, forceRecreate: Boolean): PoTokenResult {
36+
// just a helper class since Kotlin does not have builtin support for 4-tuples
37+
data class Quadruple<T1, T2, T3, T4>(val t1: T1, val t2: T2, val t3: T3, val t4: T4)
38+
39+
val (poTokenGenerator, visitorData, streamingPot, hasBeenRecreated) =
40+
synchronized(WebPoTokenGenLock) {
41+
val shouldRecreate = webPoTokenGenerator == null || forceRecreate ||
42+
webPoTokenGenerator!!.isExpired()
43+
44+
if (shouldRecreate) {
45+
// close the current webPoTokenGenerator on the main thread
46+
webPoTokenGenerator?.let { Handler(Looper.getMainLooper()).post { it.close() } }
47+
48+
// create a new webPoTokenGenerator
49+
webPoTokenGenerator = PoTokenWebView
50+
.newPoTokenGenerator(App.getApp()).blockingGet()
51+
webPoTokenVisitorData = YoutubeParsingHelper
52+
.randomVisitorData(NewPipe.getPreferredContentCountry())
3053

31-
// The streaming poToken needs to be generated exactly once before generating any
32-
// other (player) tokens.
33-
webPoTokenStreamingPot = webPoTokenGenerator!!
34-
.generatePoToken(webPoTokenVisitorData!!).blockingGet()
54+
// The streaming poToken needs to be generated exactly once before generating
55+
// any other (player) tokens.
56+
webPoTokenStreamingPot = webPoTokenGenerator!!
57+
.generatePoToken(webPoTokenVisitorData!!).blockingGet()
58+
}
59+
60+
return@synchronized Quadruple(
61+
webPoTokenGenerator!!,
62+
webPoTokenVisitorData!!,
63+
webPoTokenStreamingPot!!,
64+
shouldRecreate
65+
)
66+
}
67+
68+
val playerPot = try {
69+
// Not using synchronized here, since poTokenGenerator would be able to generate
70+
// multiple poTokens in parallel if needed. The only important thing is for exactly one
71+
// visitorData/streaming poToken to be generated before anything else.
72+
poTokenGenerator.generatePoToken(videoId).blockingGet()
73+
} catch (throwable: Throwable) {
74+
if (hasBeenRecreated) {
75+
// the poTokenGenerator has just been recreated (and possibly this is already the
76+
// second time we try), so there is likely nothing we can do
77+
throw throwable
78+
} else {
79+
// retry, this time recreating the [webPoTokenGenerator] from scratch;
80+
// this might happen for example if NewPipe goes in the background and the WebView
81+
// content is lost
82+
Log.e(TAG, "Failed to obtain poToken, retrying", throwable)
83+
return getWebClientPoToken(videoId = videoId, forceRecreate = true)
3584
}
36-
return@synchronized Triple(
37-
webPoTokenGenerator!!, webPoTokenVisitorData!!, webPoTokenStreamingPot!!
38-
)
3985
}
4086

41-
// Not using synchronized here, since poTokenGenerator would be able to generate multiple
42-
// poTokens in parallel if needed. The only important thing is for exactly one
43-
// visitorData/streaming poToken to be generated before anything else.
44-
val playerPot = poTokenGenerator.generatePoToken(videoId).blockingGet()
4587
Log.e(TAG, "success($videoId) $playerPot,web.gvs+$streamingPot;visitor_data=$visitorData")
46-
47-
return PoTokenResult(
48-
webPoTokenVisitorData!!,
49-
playerPot,
50-
webPoTokenStreamingPot!!,
51-
)
88+
return PoTokenResult(visitorData, playerPot, streamingPot)
5289
}
5390

5491
override fun getWebEmbedClientPoToken(videoId: String): PoTokenResult? = null

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import android.os.Looper
77
import android.util.Log
88
import android.webkit.JavascriptInterface
99
import android.webkit.WebView
10+
import androidx.annotation.MainThread
1011
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
1112
import io.reactivex.rxjava3.core.Single
1213
import io.reactivex.rxjava3.core.SingleEmitter
@@ -275,6 +276,7 @@ class PoTokenWebView private constructor(
275276
/**
276277
* Releases all [webView] and [disposables] resources.
277278
*/
279+
@MainThread
278280
override fun close() {
279281
disposables.dispose()
280282

0 commit comments

Comments
 (0)