11package org.schabi.newpipe.util.potoken
22
3+ import android.os.Handler
4+ import android.os.Looper
35import android.util.Log
46import org.schabi.newpipe.App
57import 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
0 commit comments