mirror of
				https://github.com/TeamNewPipe/NewPipe
				synced 2025-10-31 15:23:00 +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:
		| @@ -1,5 +1,7 @@ | |||||||
| package org.schabi.newpipe.util.potoken | package org.schabi.newpipe.util.potoken | ||||||
|  |  | ||||||
|  | import android.os.Handler | ||||||
|  | import android.os.Looper | ||||||
| import android.util.Log | import android.util.Log | ||||||
| import org.schabi.newpipe.App | import org.schabi.newpipe.App | ||||||
| import org.schabi.newpipe.extractor.NewPipe | import org.schabi.newpipe.extractor.NewPipe | ||||||
| @@ -22,33 +24,68 @@ object PoTokenProviderImpl : PoTokenProvider { | |||||||
|             return null |             return null | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         val (poTokenGenerator, visitorData, streamingPot) = synchronized(WebPoTokenGenLock) { |         return getWebClientPoToken(videoId = videoId, forceRecreate = false) | ||||||
|             if (webPoTokenGenerator == null || webPoTokenGenerator!!.isExpired()) { |     } | ||||||
|                 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. |      * @param forceRecreate whether to force the recreation of [webPoTokenGenerator], to be used in | ||||||
|                 webPoTokenStreamingPot = webPoTokenGenerator!! |      * case the current [webPoTokenGenerator] threw an error last time | ||||||
|                     .generatePoToken(webPoTokenVisitorData!!).blockingGet() |      * [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") |         Log.e(TAG, "success($videoId) $playerPot,web.gvs+$streamingPot;visitor_data=$visitorData") | ||||||
|  |         return PoTokenResult(visitorData, playerPot, streamingPot) | ||||||
|         return PoTokenResult( |  | ||||||
|             webPoTokenVisitorData!!, |  | ||||||
|             playerPot, |  | ||||||
|             webPoTokenStreamingPot!!, |  | ||||||
|         ) |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     override fun getWebEmbedClientPoToken(videoId: String): PoTokenResult? = null |     override fun getWebEmbedClientPoToken(videoId: String): PoTokenResult? = null | ||||||
|   | |||||||
| @@ -7,6 +7,7 @@ import android.os.Looper | |||||||
| import android.util.Log | import android.util.Log | ||||||
| import android.webkit.JavascriptInterface | import android.webkit.JavascriptInterface | ||||||
| import android.webkit.WebView | import android.webkit.WebView | ||||||
|  | import androidx.annotation.MainThread | ||||||
| import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers | import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers | ||||||
| import io.reactivex.rxjava3.core.Single | import io.reactivex.rxjava3.core.Single | ||||||
| import io.reactivex.rxjava3.core.SingleEmitter | import io.reactivex.rxjava3.core.SingleEmitter | ||||||
| @@ -275,6 +276,7 @@ class PoTokenWebView private constructor( | |||||||
|     /** |     /** | ||||||
|      * Releases all [webView] and [disposables] resources. |      * Releases all [webView] and [disposables] resources. | ||||||
|      */ |      */ | ||||||
|  |     @MainThread | ||||||
|     override fun close() { |     override fun close() { | ||||||
|         disposables.dispose() |         disposables.dispose() | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Stypox
					Stypox