11package org.schabi.newpipe.util.potoken
22
3- import android.os.Handler
4- import android.os.Looper
53import android.util.Log
4+ import kotlinx.coroutines.Dispatchers
5+ import kotlinx.coroutines.runBlocking
6+ import kotlinx.coroutines.sync.Mutex
7+ import kotlinx.coroutines.sync.withLock
8+ import kotlinx.coroutines.withContext
69import org.schabi.newpipe.App
710import org.schabi.newpipe.BuildConfig
811import org.schabi.newpipe.extractor.NewPipe
@@ -17,7 +20,7 @@ object PoTokenProviderImpl : PoTokenProvider {
1720 private val webViewSupported by lazy { DeviceUtils .supportsWebView() }
1821 private var webViewBadImpl = false // whether the system has a bad WebView implementation
1922
20- private object WebPoTokenGenLock
23+ private val webPoTokenGenLock = Mutex ()
2124 private var webPoTokenVisitorData: String? = null
2225 private var webPoTokenStreamingPot: String? = null
2326 private var webPoTokenGenerator: PoTokenGenerator ? = null
@@ -27,18 +30,16 @@ object PoTokenProviderImpl : PoTokenProvider {
2730 return null
2831 }
2932
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) {
33+ return try {
34+ runBlocking { getWebClientPoToken(videoId, forceRecreate = false ) }
35+ } catch (e: Exception ) {
36+ when (e) {
3537 is BadWebViewException -> {
3638 Log .e(TAG , " Could not obtain poToken because WebView is broken" , e)
3739 webViewBadImpl = true
38- return null
40+ null
3941 }
40- null -> throw e
41- else -> throw cause // includes PoTokenException
42+ else -> throw e // includes PoTokenException
4243 }
4344 }
4445 }
@@ -48,56 +49,52 @@ object PoTokenProviderImpl : PoTokenProvider {
4849 * case the current [webPoTokenGenerator] threw an error last time
4950 * [PoTokenGenerator.generatePoToken] was called
5051 */
51- private fun getWebClientPoToken (videoId : String , forceRecreate : Boolean ): PoTokenResult {
52+ private suspend fun getWebClientPoToken (videoId : String , forceRecreate : Boolean ): PoTokenResult {
5253 // just a helper class since Kotlin does not have builtin support for 4-tuples
5354 data class Quadruple <T1 , T2 , T3 , T4 >(val t1 : T1 , val t2 : T2 , val t3 : T3 , val t4 : T4 )
5455
5556 val (poTokenGenerator, visitorData, streamingPot, hasBeenRecreated) =
56- synchronized( WebPoTokenGenLock ) {
57- val shouldRecreate = webPoTokenGenerator == null || forceRecreate ||
58- webPoTokenGenerator !! .isExpired()
57+ webPoTokenGenLock.withLock {
58+ val gen = webPoTokenGenerator
59+ val shouldRecreate = forceRecreate || gen == null || gen .isExpired
5960
6061 if (shouldRecreate) {
61-
62- val innertubeClientRequestInfo = InnertubeClientRequestInfo .ofWebClient()
63- innertubeClientRequestInfo.clientInfo.clientVersion =
64- YoutubeParsingHelper .getClientVersion()
65-
66- webPoTokenVisitorData = YoutubeParsingHelper .getVisitorDataFromInnertube(
67- innertubeClientRequestInfo,
68- NewPipe .getPreferredLocalization(),
69- NewPipe .getPreferredContentCountry(),
70- YoutubeParsingHelper .getYouTubeHeaders(),
71- YoutubeParsingHelper .YOUTUBEI_V1_URL ,
72- null ,
73- false
74- )
75- // close the current webPoTokenGenerator on the main thread
76- webPoTokenGenerator?.let { Handler (Looper .getMainLooper()).post { it.close() } }
62+ webPoTokenVisitorData = withContext(Dispatchers .IO ) {
63+ val innertubeClientRequestInfo = InnertubeClientRequestInfo .ofWebClient()
64+ innertubeClientRequestInfo.clientInfo.clientVersion =
65+ YoutubeParsingHelper .getClientVersion()
66+
67+ YoutubeParsingHelper .getVisitorDataFromInnertube(
68+ innertubeClientRequestInfo,
69+ NewPipe .getPreferredLocalization(),
70+ NewPipe .getPreferredContentCountry(),
71+ YoutubeParsingHelper .getYouTubeHeaders(),
72+ YoutubeParsingHelper .YOUTUBEI_V1_URL ,
73+ null ,
74+ false
75+ )
76+ }
77+
78+ withContext(Dispatchers .Main ) {
79+ webPoTokenGenerator?.close()
80+ }
7781
7882 // create a new webPoTokenGenerator
79- webPoTokenGenerator = PoTokenWebView
80- .newPoTokenGenerator(App .instance).blockingGet()
83+ webPoTokenGenerator = PoTokenWebView .getNewPoTokenGenerator(App .instance)
8184
8285 // The streaming poToken needs to be generated exactly once before generating
8386 // any other (player) tokens.
84- webPoTokenStreamingPot = webPoTokenGenerator!!
85- .generatePoToken(webPoTokenVisitorData!! ).blockingGet()
87+ webPoTokenStreamingPot = webPoTokenGenerator!! .generatePoToken(webPoTokenVisitorData!! )
8688 }
8789
88- return @synchronized Quadruple (
89- webPoTokenGenerator!! ,
90- webPoTokenVisitorData!! ,
91- webPoTokenStreamingPot!! ,
92- shouldRecreate
93- )
90+ Quadruple (webPoTokenGenerator!! , webPoTokenVisitorData!! , webPoTokenStreamingPot!! , shouldRecreate)
9491 }
9592
9693 val playerPot = try {
9794 // Not using synchronized here, since poTokenGenerator would be able to generate
9895 // multiple poTokens in parallel if needed. The only important thing is for exactly one
9996 // visitorData/streaming poToken to be generated before anything else.
100- poTokenGenerator.generatePoToken(videoId).blockingGet()
97+ poTokenGenerator.generatePoToken(videoId)
10198 } catch (throwable: Throwable ) {
10299 if (hasBeenRecreated) {
103100 // the poTokenGenerator has just been recreated (and possibly this is already the
@@ -108,7 +105,7 @@ object PoTokenProviderImpl : PoTokenProvider {
108105 // this might happen for example if NewPipe goes in the background and the WebView
109106 // content is lost
110107 Log .e(TAG , " Failed to obtain poToken, retrying" , throwable)
111- return getWebClientPoToken(videoId = videoId , forceRecreate = true )
108+ return getWebClientPoToken(videoId, forceRecreate = true )
112109 }
113110 }
114111
0 commit comments