@@ -7,14 +7,13 @@ import android.os.Looper
77import android.util.Log
88import android.webkit.JavascriptInterface
99import android.webkit.WebView
10- import androidx.annotation.MainThread
1110import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
1211import io.reactivex.rxjava3.core.Single
1312import io.reactivex.rxjava3.core.SingleEmitter
1413import io.reactivex.rxjava3.disposables.CompositeDisposable
1514import io.reactivex.rxjava3.schedulers.Schedulers
1615import org.schabi.newpipe.DownloaderImpl
17- import org.schabi.newpipe.extractor.services.youtube.PoTokenResult
16+ import java.time.Instant
1817
1918class PoTokenWebView private constructor(
2019 context : Context ,
@@ -23,7 +22,8 @@ class PoTokenWebView private constructor(
2322) : PoTokenGenerator {
2423 private val webView = WebView (context)
2524 private val disposables = CompositeDisposable () // used only during initialization
26- private val poTokenEmitters = mutableListOf<Pair <String , SingleEmitter <PoTokenResult >>>()
25+ private val poTokenEmitters = mutableListOf<Pair <String , SingleEmitter <String >>>()
26+ private lateinit var expirationInstant: Instant
2727
2828 // region Initialization
2929 init {
@@ -114,11 +114,12 @@ class PoTokenWebView private constructor(
114114 " https://jnn-pa.googleapis.com/\$ rpc/google.internal.waa.v1.Waa/GenerateIT" ,
115115 " [ \" $REQUEST_KEY \" , \" $botguardResponse \" ]" ,
116116 ) { responseBody ->
117+ Log .e(TAG , " GenerateIT response: $responseBody " )
117118 webView.evaluateJavascript(
118119 """ (async function() {
119120 try {
120121 globalThis.integrityToken = JSON.parse(String.raw`$responseBody `)
121- PoTokenWebView.onInitializationFinished()
122+ PoTokenWebView.onInitializationFinished(integrityToken[1] )
122123 } catch (error) {
123124 PoTokenWebView.onJsInitializationError(error.toString())
124125 }
@@ -130,9 +131,14 @@ class PoTokenWebView private constructor(
130131 /* *
131132 * Called during initialization by the JavaScript snippet from [onRunBotguardResult] when the
132133 * `integrityToken` has been received by JavaScript.
134+ *
135+ * @param expirationTimeInSeconds in how many seconds the integrity token expires, can be found
136+ * in `integrityToken[1]`
133137 */
134138 @JavascriptInterface
135- fun onInitializationFinished () {
139+ fun onInitializationFinished (expirationTimeInSeconds : Long ) {
140+ // leave 10 minutes of margin just to be sure
141+ expirationInstant = Instant .now().plusSeconds(expirationTimeInSeconds - 600 )
136142 generatorEmitter.onSuccess(this )
137143 }
138144 // endregion
@@ -143,7 +149,7 @@ class PoTokenWebView private constructor(
143149 * multiple poToken requests can be generated invparallel, and the results will be notified to
144150 * the right emitters.
145151 */
146- private fun addPoTokenEmitter (identifier : String , emitter : SingleEmitter <PoTokenResult >) {
152+ private fun addPoTokenEmitter (identifier : String , emitter : SingleEmitter <String >) {
147153 synchronized(poTokenEmitters) {
148154 poTokenEmitters.add(Pair (identifier, emitter))
149155 }
@@ -154,30 +160,31 @@ class PoTokenWebView private constructor(
154160 * [identifier]. The emitter is supposed to be used immediately after to either signal a success
155161 * or an error.
156162 */
157- private fun popPoTokenEmitter (identifier : String ): SingleEmitter <PoTokenResult >? {
163+ private fun popPoTokenEmitter (identifier : String ): SingleEmitter <String >? {
158164 return synchronized(poTokenEmitters) {
159165 poTokenEmitters.indexOfFirst { it.first == identifier }.takeIf { it >= 0 }?.let {
160166 poTokenEmitters.removeAt(it).second
161167 }
162168 }
163169 }
164170
165- @MainThread
166- override fun generatePoToken (identifier : String ): Single <PoTokenResult > =
171+ override fun generatePoToken (identifier : String ): Single <String > =
167172 Single .create { emitter ->
168173 addPoTokenEmitter(identifier, emitter)
169-
170- webView.evaluateJavascript(
171- """ (async function() {
172- identifier = String.raw`$identifier `
173- try {
174- poToken = await obtainPoToken(webPoSignalOutput, integrityToken, identifier)
175- PoTokenWebView.onObtainPoTokenResult(identifier, poToken)
176- } catch (error) {
177- PoTokenWebView.onObtainPoTokenError(identifier, error.toString())
178- }
179- })();""" ,
180- ) {}
174+ Handler (Looper .getMainLooper()).post {
175+ webView.evaluateJavascript(
176+ """ (async function() {
177+ identifier = String.raw`$identifier `
178+ try {
179+ poToken = await obtainPoToken(webPoSignalOutput, integrityToken,
180+ identifier)
181+ PoTokenWebView.onObtainPoTokenResult(identifier, poToken)
182+ } catch (error) {
183+ PoTokenWebView.onObtainPoTokenError(identifier, error.toString())
184+ }
185+ })();""" ,
186+ ) {}
187+ }
181188 }
182189
183190 /* *
@@ -198,7 +205,11 @@ class PoTokenWebView private constructor(
198205 fun onObtainPoTokenResult (identifier : String , poToken : String ) {
199206 Log .e(TAG , " identifier=$identifier " )
200207 Log .e(TAG , " poToken=$poToken " )
201- popPoTokenEmitter(identifier)?.onSuccess(PoTokenResult (identifier, poToken))
208+ popPoTokenEmitter(identifier)?.onSuccess(poToken)
209+ }
210+
211+ override fun isExpired (): Boolean {
212+ return Instant .now().isAfter(expirationInstant)
202213 }
203214 // endregion
204215
@@ -286,12 +297,13 @@ class PoTokenWebView private constructor(
286297 private const val REQUEST_KEY = " O43z0dpjhgX20SCx4KAo"
287298 private const val USER_AGENT = " Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.3"
288299
289- @MainThread
290300 override fun newPoTokenGenerator (context : Context ): Single <PoTokenGenerator > =
291301 Single .create { emitter ->
292- val potWv = PoTokenWebView (context, emitter)
293- potWv.loadHtmlAndObtainBotguard(context)
294- emitter.setDisposable(potWv.disposables)
302+ Handler (Looper .getMainLooper()).post {
303+ val potWv = PoTokenWebView (context, emitter)
304+ potWv.loadHtmlAndObtainBotguard(context)
305+ emitter.setDisposable(potWv.disposables)
306+ }
295307 }
296308 }
297309}
0 commit comments