1
0
mirror of https://github.com/TeamNewPipe/NewPipe synced 2025-03-12 14:38:15 +00:00

Recreate poToken generator if current is broken

This will be tried only once, and afterwards an error will be thrown
This commit is contained in:
Stypox 2025-01-27 12:06:19 +01:00 committed by AudricV
parent 0066b322e1
commit f856bd9306
No known key found for this signature in database
GPG Key ID: DA92EC7905614198
2 changed files with 61 additions and 22 deletions

View File

@ -1,5 +1,7 @@
package org.schabi.newpipe.util.potoken
import android.os.Handler
import android.os.Looper
import android.util.Log
import org.schabi.newpipe.App
import org.schabi.newpipe.extractor.NewPipe
@ -22,33 +24,68 @@ object PoTokenProviderImpl : PoTokenProvider {
return null
}
val (poTokenGenerator, visitorData, streamingPot) = synchronized(WebPoTokenGenLock) {
if (webPoTokenGenerator == null || webPoTokenGenerator!!.isExpired()) {
webPoTokenGenerator = PoTokenWebView.newPoTokenGenerator(App.getApp()).blockingGet()
webPoTokenVisitorData = YoutubeParsingHelper
.randomVisitorData(NewPipe.getPreferredContentCountry())
return getWebClientPoToken(videoId = videoId, forceRecreate = false)
}
// The streaming poToken needs to be generated exactly once before generating any
// other (player) tokens.
webPoTokenStreamingPot = webPoTokenGenerator!!
.generatePoToken(webPoTokenVisitorData!!).blockingGet()
/**
* @param forceRecreate whether to force the recreation of [webPoTokenGenerator], to be used in
* case the current [webPoTokenGenerator] threw an error last time
* [PoTokenGenerator.generatePoToken] was called
*/
private fun getWebClientPoToken(videoId: String, forceRecreate: Boolean): PoTokenResult {
// just a helper class since Kotlin does not have builtin support for 4-tuples
data class Quadruple<T1, T2, T3, T4>(val t1: T1, val t2: T2, val t3: T3, val t4: T4)
val (poTokenGenerator, visitorData, streamingPot, hasBeenRecreated) =
synchronized(WebPoTokenGenLock) {
val shouldRecreate = webPoTokenGenerator == null || forceRecreate ||
webPoTokenGenerator!!.isExpired()
if (shouldRecreate) {
// close the current webPoTokenGenerator on the main thread
webPoTokenGenerator?.let { Handler(Looper.getMainLooper()).post { it.close() } }
// create a new webPoTokenGenerator
webPoTokenGenerator = PoTokenWebView
.newPoTokenGenerator(App.getApp()).blockingGet()
webPoTokenVisitorData = YoutubeParsingHelper
.randomVisitorData(NewPipe.getPreferredContentCountry())
// The streaming poToken needs to be generated exactly once before generating
// any other (player) tokens.
webPoTokenStreamingPot = webPoTokenGenerator!!
.generatePoToken(webPoTokenVisitorData!!).blockingGet()
}
return@synchronized Quadruple(
webPoTokenGenerator!!,
webPoTokenVisitorData!!,
webPoTokenStreamingPot!!,
shouldRecreate
)
}
val playerPot = try {
// Not using synchronized here, since poTokenGenerator would be able to generate
// multiple poTokens in parallel if needed. The only important thing is for exactly one
// visitorData/streaming poToken to be generated before anything else.
poTokenGenerator.generatePoToken(videoId).blockingGet()
} catch (throwable: Throwable) {
if (hasBeenRecreated) {
// the poTokenGenerator has just been recreated (and possibly this is already the
// second time we try), so there is likely nothing we can do
throw throwable
} else {
// retry, this time recreating the [webPoTokenGenerator] from scratch;
// this might happen for example if NewPipe goes in the background and the WebView
// content is lost
Log.e(TAG, "Failed to obtain poToken, retrying", throwable)
return getWebClientPoToken(videoId = videoId, forceRecreate = true)
}
return@synchronized Triple(
webPoTokenGenerator!!, webPoTokenVisitorData!!, webPoTokenStreamingPot!!
)
}
// Not using synchronized here, since poTokenGenerator would be able to generate multiple
// poTokens in parallel if needed. The only important thing is for exactly one
// visitorData/streaming poToken to be generated before anything else.
val playerPot = poTokenGenerator.generatePoToken(videoId).blockingGet()
Log.e(TAG, "success($videoId) $playerPot,web.gvs+$streamingPot;visitor_data=$visitorData")
return PoTokenResult(
webPoTokenVisitorData!!,
playerPot,
webPoTokenStreamingPot!!,
)
return PoTokenResult(visitorData, playerPot, streamingPot)
}
override fun getWebEmbedClientPoToken(videoId: String): PoTokenResult? = null

View File

@ -7,6 +7,7 @@ import android.os.Looper
import android.util.Log
import android.webkit.JavascriptInterface
import android.webkit.WebView
import androidx.annotation.MainThread
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Single
import io.reactivex.rxjava3.core.SingleEmitter
@ -275,6 +276,7 @@ class PoTokenWebView private constructor(
/**
* Releases all [webView] and [disposables] resources.
*/
@MainThread
override fun close() {
disposables.dispose()