finish po token generation

This commit is contained in:
deniscerri 2025-03-16 15:53:41 +01:00
parent 90e16d203d
commit 1d560a98ca
No known key found for this signature in database
GPG key ID: 95C43D517D830350
20 changed files with 301 additions and 107 deletions

View file

@ -449,6 +449,20 @@
</intent-filter> </intent-filter>
</activity> </activity>
<activity
android:name=".ui.more.settings.advanced.generateyoutubepotokens.webview.PoTokenWebViewLoginActivity"
android:configChanges="locale"
android:exported="true"
android:launchMode="singleTask"
android:noHistory="true"
android:parentActivityName=".ui.more.settings.SettingsActivity"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="ytdlnis.PoTokenWebViewLoginActivity" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<receiver android:name=".receiver.CancelDownloadNotificationReceiver" /> <receiver android:name=".receiver.CancelDownloadNotificationReceiver" />
<receiver android:name=".receiver.CancelWorkReceiver" /> <receiver android:name=".receiver.CancelWorkReceiver" />
<receiver android:name=".receiver.PauseDownloadNotificationReceiver" /> <receiver android:name=".receiver.PauseDownloadNotificationReceiver" />

View file

@ -4,5 +4,6 @@ data class YoutubeGeneratePoTokenItem(
var enabled: Boolean, var enabled: Boolean,
var clients: MutableList<String>, var clients: MutableList<String>,
var poTokens: MutableList<YoutubePoTokenItem>, var poTokens: MutableList<YoutubePoTokenItem>,
var visitorData: String var visitorData: String,
var useVisitorData: Boolean
) )

View file

@ -6,7 +6,6 @@ import android.content.ClipboardManager
import android.content.Context import android.content.Context
import android.database.sqlite.SQLiteDatabase import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteDatabase.OPEN_READONLY import android.database.sqlite.SQLiteDatabase.OPEN_READONLY
import android.os.Environment
import android.util.Log import android.util.Log
import android.webkit.CookieManager import android.webkit.CookieManager
import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.AndroidViewModel
@ -19,13 +18,10 @@ import com.deniscerri.ytdl.database.models.CookieItem
import com.deniscerri.ytdl.database.repository.CookieRepository import com.deniscerri.ytdl.database.repository.CookieRepository
import com.deniscerri.ytdl.ui.more.WebViewActivity import com.deniscerri.ytdl.ui.more.WebViewActivity
import com.deniscerri.ytdl.util.FileUtil import com.deniscerri.ytdl.util.FileUtil
import com.google.gson.GsonBuilder
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import java.io.File import java.io.File
import java.util.Calendar
import java.util.Date import java.util.Date

View file

@ -45,7 +45,6 @@ import com.deniscerri.ytdl.ui.adapter.SearchSuggestionsAdapter
import com.deniscerri.ytdl.ui.more.WebViewActivity import com.deniscerri.ytdl.ui.more.WebViewActivity
import com.deniscerri.ytdl.util.Extensions.enableFastScroll import com.deniscerri.ytdl.util.Extensions.enableFastScroll
import com.deniscerri.ytdl.util.Extensions.isURL import com.deniscerri.ytdl.util.Extensions.isURL
import com.deniscerri.ytdl.util.FileUtil
import com.deniscerri.ytdl.util.NotificationUtil import com.deniscerri.ytdl.util.NotificationUtil
import com.deniscerri.ytdl.util.ThemeUtil import com.deniscerri.ytdl.util.ThemeUtil
import com.deniscerri.ytdl.util.UiUtil import com.deniscerri.ytdl.util.UiUtil
@ -67,7 +66,6 @@ import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import java.io.File
import java.net.URL import java.net.URL
import kotlin.collections.ArrayList import kotlin.collections.ArrayList

View file

@ -60,7 +60,6 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import java.net.URL import java.net.URL

View file

@ -17,7 +17,6 @@ import android.view.inputmethod.InputMethodManager
import android.widget.EditText import android.widget.EditText
import android.widget.RelativeLayout import android.widget.RelativeLayout
import android.widget.TextView import android.widget.TextView
import androidx.appcompat.app.AlertDialog
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.core.widget.doOnTextChanged import androidx.core.widget.doOnTextChanged
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
@ -45,7 +44,6 @@ import com.google.android.material.chip.Chip
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.materialswitch.MaterialSwitch import com.google.android.material.materialswitch.MaterialSwitch
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import com.google.android.material.textfield.TextInputLayout
import it.xabaras.android.recyclerview.swipedecorator.RecyclerViewSwipeDecorator import it.xabaras.android.recyclerview.swipedecorator.RecyclerViewSwipeDecorator
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch

View file

@ -77,6 +77,7 @@ class WebViewActivity : BaseActivity() {
generateBtn = toolbar.findViewById(R.id.generate) generateBtn = toolbar.findViewById(R.id.generate)
webViewCompose = findViewById(R.id.webview_compose) webViewCompose = findViewById(R.id.webview_compose)
cookieManager = CookieManager.getInstance() cookieManager = CookieManager.getInstance()
cookieManager.removeAllCookies(null)
preferences = PreferenceManager.getDefaultSharedPreferences(this@WebViewActivity) preferences = PreferenceManager.getDefaultSharedPreferences(this@WebViewActivity)
@ -92,7 +93,6 @@ class WebViewActivity : BaseActivity() {
} }
toolbar.setNavigationOnClickListener { toolbar.setNavigationOnClickListener {
cookieManager.flush()
onBackPressedDispatcher.onBackPressed() onBackPressedDispatcher.onBackPressed()
} }
@ -119,7 +119,6 @@ class WebViewActivity : BaseActivity() {
} }
} }
} }
cookieManager.removeAllCookies(null)
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
this@WebViewActivity.setResult(RESULT_OK) this@WebViewActivity.setResult(RESULT_OK)
this@WebViewActivity.finish() this@WebViewActivity.finish()

View file

@ -45,8 +45,7 @@ class AdvancedSettingsFragment : BaseSettingsFragment() {
} }
findPreference<Preference>("youtube_other_extractor_args")?.apply { findPreference<Preference>("youtube_other_extractor_args")?.apply {
fun setValue() { fun setValue(pf: String) {
val pf = prefs.getString("youtube_other_extractor_args", "")!!
if (pf.length > 50) { if (pf.length > 50) {
this.summary = pf.take(50) + "..." this.summary = pf.take(50) + "..."
}else { }else {
@ -54,14 +53,11 @@ class AdvancedSettingsFragment : BaseSettingsFragment() {
} }
} }
setOnPreferenceChangeListener { preference, newValue -> setOnPreferenceChangeListener { _, newValue ->
setValue() setValue(newValue as String)
true true
} }
setValue(prefs.getString("youtube_other_extractor_args", "")!!)
setValue()
} }
val formatImportanceAudio: Preference? = findPreference("format_importance_audio") val formatImportanceAudio: Preference? = findPreference("format_importance_audio")

View file

@ -1,36 +1,37 @@
package com.deniscerri.ytdl.ui.more.settings.advanced package com.deniscerri.ytdl.ui.more.settings.advanced.generateyoutubepotokens
import android.app.Activity
import android.app.ActivityManager
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences import android.content.SharedPreferences
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.TextView import android.widget.TextView
import androidx.activity.result.contract.ActivityResultContracts
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import androidx.work.WorkManager
import com.afollestad.materialdialogs.utils.MDUtil.getStringArray import com.afollestad.materialdialogs.utils.MDUtil.getStringArray
import com.deniscerri.ytdl.R import com.deniscerri.ytdl.R
import com.deniscerri.ytdl.database.models.YoutubeGeneratePoTokenItem import com.deniscerri.ytdl.database.models.YoutubeGeneratePoTokenItem
import com.deniscerri.ytdl.database.models.YoutubePoTokenItem import com.deniscerri.ytdl.database.models.YoutubePoTokenItem
import com.deniscerri.ytdl.ui.more.settings.SettingsActivity import com.deniscerri.ytdl.ui.more.settings.SettingsActivity
import com.deniscerri.ytdl.util.Extensions.getIDFromYoutubeURL import com.deniscerri.ytdl.ui.more.settings.advanced.generateyoutubepotokens.webview.PoTokenWebViewLoginActivity
import com.deniscerri.ytdl.util.UiUtil import com.deniscerri.ytdl.util.UiUtil
import com.deniscerri.ytdl.util.extractors.potoken.PoTokenGenerator
import com.google.android.material.button.MaterialButton import com.google.android.material.button.MaterialButton
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.materialswitch.MaterialSwitch import com.google.android.material.materialswitch.MaterialSwitch
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import com.google.android.material.textfield.TextInputLayout
import com.google.gson.Gson import com.google.gson.Gson
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class GenerateYoutubePoTokensFragment : Fragment() { class GenerateYoutubePoTokensFragment : Fragment() {
private lateinit var settingsActivity: SettingsActivity private lateinit var settingsActivity: SettingsActivity
private lateinit var preferences: SharedPreferences private lateinit var preferences: SharedPreferences
private lateinit var configuration : MutableList<YoutubeGeneratePoTokenItem> private lateinit var configuration : MutableList<YoutubeGeneratePoTokenItem>
private lateinit var workManager : WorkManager
private lateinit var poTokenGenerator: PoTokenGenerator private lateinit var poTokenGenerator: PoTokenGenerator
private val sampleURL = "https://www.youtube.com/watch?v=aqz-KE-bpKQ" // Big Buck Bunny private val sampleURL = "https://www.youtube.com/watch?v=aqz-KE-bpKQ" // Big Buck Bunny
@ -44,6 +45,7 @@ class GenerateYoutubePoTokensFragment : Fragment() {
settingsActivity.changeTopAppbarTitle(getString(R.string.generate_potokens)) settingsActivity.changeTopAppbarTitle(getString(R.string.generate_potokens))
preferences = PreferenceManager.getDefaultSharedPreferences(requireContext()) preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
poTokenGenerator = PoTokenGenerator() poTokenGenerator = PoTokenGenerator()
workManager = WorkManager.getInstance(requireContext())
return inflater.inflate(R.layout.fragment_generate_youtube_po_token, container, false) return inflater.inflate(R.layout.fragment_generate_youtube_po_token, container, false)
} }
@ -59,7 +61,7 @@ class GenerateYoutubePoTokensFragment : Fragment() {
private fun initWeb() { private fun initWeb() {
val conf = configuration.find { it.clients.any { it2 -> it2.contains("web") } } val conf = configuration.find { it.clients.any { it2 -> it2.contains("web") } }
?: YoutubeGeneratePoTokenItem(false, mutableListOf("mweb"), mutableListOf(), "") ?: YoutubeGeneratePoTokenItem(false, mutableListOf("mweb"), mutableListOf(), "", false)
val switch = requireView().findViewById<MaterialSwitch>(R.id.web_client_switch) val switch = requireView().findViewById<MaterialSwitch>(R.id.web_client_switch)
@ -71,8 +73,10 @@ class GenerateYoutubePoTokensFragment : Fragment() {
val playerClientText = requireView().findViewById<TextView>(R.id.content_playerclient) val playerClientText = requireView().findViewById<TextView>(R.id.content_playerclient)
val regenerate = requireView().findViewById<MaterialButton>(R.id.regenerate_webview_potokens) val regenerate = requireView().findViewById<MaterialButton>(R.id.regenerate_webview_potokens)
val useVisitorData = requireView().findViewById<MaterialSwitch>(R.id.use_visitor_data)
switch.isChecked = conf.enabled switch.isChecked = conf.enabled
useVisitorData.isEnabled = conf.enabled
fun setValues(conf: YoutubeGeneratePoTokenItem) { fun setValues(conf: YoutubeGeneratePoTokenItem) {
gvs.text = conf.poTokens.find { it.context == "gvs" }?.token ?: "" gvs.text = conf.poTokens.find { it.context == "gvs" }?.token ?: ""
@ -121,36 +125,53 @@ class GenerateYoutubePoTokensFragment : Fragment() {
.show() .show()
} }
regenerate.setOnClickListener { val webPoTokenResultLauncher = registerForActivityResult(
lifecycleScope.launch { ActivityResultContracts.StartActivityForResult()
val res = withContext(Dispatchers.IO) { ) { result ->
poTokenGenerator.getWebClientPoToken(sampleURL.getIDFromYoutubeURL()) if (result.resultCode == Activity.RESULT_OK) {
} val streamingDataPoTokenResult = result.data!!.getStringExtra("streaming_potoken") ?: ""
val playerRequestPoTokenResult = result.data!!.getStringExtra("player_potoken") ?: ""
val visitorDataResult = result.data!!.getStringExtra("visitor_data") ?: ""
if (res == null) {
Snackbar.make(requireView(), getString(R.string.network_error), Snackbar.LENGTH_LONG).show()
}else{
configuration.remove(conf)
conf.poTokens.clear()
conf.poTokens.add(YoutubePoTokenItem("gvs", res.streamingDataPoToken ?: ""))
conf.poTokens.add(YoutubePoTokenItem("player", res.playerRequestPoToken))
conf.visitorData = res.visitorData
configuration.add(conf) configuration.remove(conf)
setValues(conf) conf.poTokens.clear()
preferences.edit().putString("youtube_generated_po_tokens", Gson().toJson(configuration).toString()).apply() conf.poTokens.add(YoutubePoTokenItem("gvs", streamingDataPoTokenResult))
} conf.poTokens.add(YoutubePoTokenItem("player", playerRequestPoTokenResult))
conf.visitorData = visitorDataResult
configuration.add(conf)
setValues(conf)
preferences.edit().putString("youtube_generated_po_tokens", Gson().toJson(configuration).toString()).apply()
}else {
Snackbar.make(requireView(), R.string.network_error, Snackbar.LENGTH_SHORT).show()
} }
} }
regenerate.setOnClickListener {
webPoTokenResultLauncher.launch(Intent(requireContext(), PoTokenWebViewLoginActivity::class.java))
}
switch.setOnClickListener { switch.setOnClickListener {
configuration.remove(conf) configuration.remove(conf)
conf.enabled = switch.isChecked conf.enabled = switch.isChecked
useVisitorData.isEnabled = switch.isChecked
configuration.add(conf) configuration.add(conf)
preferences.edit().putString("youtube_generated_po_tokens", Gson().toJson(configuration).toString()).apply() preferences.edit().putString("youtube_generated_po_tokens", Gson().toJson(configuration).toString()).apply()
if (conf.poTokens.isEmpty()) { if (conf.poTokens.isEmpty()) {
regenerate.performClick() regenerate.performClick()
} }
} }
useVisitorData?.apply {
this.isChecked = conf.useVisitorData
setOnCheckedChangeListener { _, b ->
configuration.remove(conf)
conf.useVisitorData = b
configuration.add(conf)
preferences.edit().putString("youtube_generated_po_tokens", Gson().toJson(configuration).toString()).apply()
}
}
} }
} }

View file

@ -1,13 +1,12 @@
package com.deniscerri.ytdl.util.extractors.potoken package com.deniscerri.ytdl.ui.more.settings.advanced.generateyoutubepotokens
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import android.util.Log import android.util.Log
import android.webkit.CookieManager import android.webkit.CookieManager
import androidx.preference.PreferenceManager
import com.deniscerri.ytdl.App import com.deniscerri.ytdl.App
import com.deniscerri.ytdl.BuildConfig import com.deniscerri.ytdl.BuildConfig
import com.deniscerri.ytdl.util.extractors.potoken.webview.PoTokenWebView import com.deniscerri.ytdl.ui.more.settings.advanced.generateyoutubepotokens.webview.PoTokenWebView
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import org.schabi.newpipe.extractor.NewPipe import org.schabi.newpipe.extractor.NewPipe
import org.schabi.newpipe.extractor.services.youtube.InnertubeClientRequestInfo import org.schabi.newpipe.extractor.services.youtube.InnertubeClientRequestInfo

View file

@ -1,6 +1,5 @@
package com.deniscerri.ytdl.util.extractors.potoken.webview package com.deniscerri.ytdl.ui.more.settings.advanced.generateyoutubepotokens.webview
import com.deniscerri.ytdl.util.extractors.potoken.PoTokenException
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonNull import kotlinx.serialization.json.JsonNull
import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonObject

View file

@ -1,4 +1,4 @@
package com.deniscerri.ytdl.util.extractors.potoken package com.deniscerri.ytdl.ui.more.settings.advanced.generateyoutubepotokens.webview
class PoTokenException(message: String) : Exception(message) class PoTokenException(message: String) : Exception(message)

View file

@ -1,4 +1,4 @@
package com.deniscerri.ytdl.util.extractors.potoken.webview package com.deniscerri.ytdl.ui.more.settings.advanced.generateyoutubepotokens.webview
import android.content.Context import android.content.Context
import android.os.Build import android.os.Build
@ -9,7 +9,6 @@ import android.webkit.WebChromeClient
import android.webkit.WebView import android.webkit.WebView
import androidx.annotation.MainThread import androidx.annotation.MainThread
import androidx.collection.ArrayMap import androidx.collection.ArrayMap
import androidx.preference.PreferenceManager
import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.MainScope import kotlinx.coroutines.MainScope
@ -18,13 +17,10 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import com.deniscerri.ytdl.BuildConfig import com.deniscerri.ytdl.BuildConfig
import com.deniscerri.ytdl.util.extractors.potoken.BadWebViewException import com.deniscerri.ytdl.ui.more.settings.advanced.generateyoutubepotokens.webview.JavascriptUtil.parseChallengeData
import com.deniscerri.ytdl.util.extractors.potoken.PoTokenException import com.deniscerri.ytdl.ui.more.settings.advanced.generateyoutubepotokens.webview.JavascriptUtil.parseIntegrityTokenData
import com.deniscerri.ytdl.util.extractors.potoken.buildExceptionForJsError import com.deniscerri.ytdl.ui.more.settings.advanced.generateyoutubepotokens.webview.JavascriptUtil.stringToU8
import com.deniscerri.ytdl.util.extractors.potoken.webview.JavascriptUtil.parseChallengeData import com.deniscerri.ytdl.ui.more.settings.advanced.generateyoutubepotokens.webview.JavascriptUtil.u8ToBase64
import com.deniscerri.ytdl.util.extractors.potoken.webview.JavascriptUtil.parseIntegrityTokenData
import com.deniscerri.ytdl.util.extractors.potoken.webview.JavascriptUtil.stringToU8
import com.deniscerri.ytdl.util.extractors.potoken.webview.JavascriptUtil.u8ToBase64
import okhttp3.Headers.Companion.toHeaders import okhttp3.Headers.Companion.toHeaders
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.RequestBody.Companion.toRequestBody

View file

@ -0,0 +1,141 @@
package com.deniscerri.ytdl.ui.more.settings.advanced.generateyoutubepotokens.webview
import android.annotation.SuppressLint
import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.webkit.CookieManager
import android.webkit.WebView
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.ComposeView
import androidx.core.view.forEach
import androidx.lifecycle.lifecycleScope
import com.deniscerri.ytdl.R
import com.deniscerri.ytdl.ui.BaseActivity
import com.deniscerri.ytdl.ui.more.settings.advanced.generateyoutubepotokens.PoTokenGenerator
import com.google.accompanist.web.AccompanistWebChromeClient
import com.google.accompanist.web.AccompanistWebViewClient
import com.google.accompanist.web.WebView
import com.google.accompanist.web.rememberWebViewState
import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.appbar.MaterialToolbar
import com.google.android.material.button.MaterialButton
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class PoTokenWebViewLoginActivity : BaseActivity() {
private lateinit var webView: WebView
private lateinit var webViewCompose: ComposeView
private lateinit var toolbar: MaterialToolbar
private lateinit var generateBtn: MaterialButton
private lateinit var cookieManager: CookieManager
private lateinit var webViewClient: AccompanistWebViewClient
private val sampleVideoID = "aqz-KE-bpKQ" //Big Buck Bunny
@SuppressLint("SetJavaScriptEnabled")
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.webview_activity)
lifecycleScope.launch {
val appbar = findViewById<AppBarLayout>(R.id.webview_appbarlayout)
toolbar = appbar.findViewById(R.id.webviewToolbar)
toolbar.menu.forEach { it.isVisible = false }
generateBtn = toolbar.findViewById(R.id.generate)
webViewCompose = findViewById(R.id.webview_compose)
cookieManager = CookieManager.getInstance()
webViewClient = object : AccompanistWebViewClient() {
override fun onPageFinished(view: WebView?, url: String?) {
super.onPageFinished(view, url)
kotlin.runCatching {
toolbar.title = view?.title ?: ""
}
}
}
toolbar.setNavigationOnClickListener {
finishAndRemoveTask()
}
generateBtn.setOnClickListener {
generateBtn.isEnabled = false
lifecycleScope.launch {
val generator = PoTokenGenerator()
val res = withContext(Dispatchers.IO) {
generator.getWebClientPoToken(sampleVideoID)
}
if (res == null) {
setResult(RESULT_CANCELED)
}else {
val intent = Intent()
intent.putExtra("visitor_data", res.visitorData)
intent.putExtra("player_potoken", res.playerRequestPoToken)
intent.putExtra("streaming_potoken", res.streamingDataPoToken)
setResult(RESULT_OK, intent)
}
webView.clearCache(true)
// ensures that the WebView isn't doing anything when destroying it
webView.loadUrl("about:blank")
webView.onPause()
webView.removeAllViews()
webView.destroy()
finish()
}
}
webViewCompose.apply {
setContent { WebViewView() }
}
}
}
@SuppressLint("SetJavaScriptEnabled", "JavascriptInterface")
@Composable
fun WebViewView() {
val webViewChromeClient = remember {
object : AccompanistWebChromeClient() {
}
}
Scaffold(modifier = Modifier.fillMaxSize()) { paddingValues ->
WebView(
state = rememberWebViewState("https://youtube.com/account"), client = webViewClient, chromeClient = webViewChromeClient,
modifier = Modifier
.padding(paddingValues)
.fillMaxSize(),
captureBackPresses = false, factory = { context ->
WebView(context).apply {
webView = this
settings.run {
javaScriptEnabled = true
domStorageEnabled = true
javaScriptCanOpenWindowsAutomatically = true
if (Build.VERSION.SDK_INT >= 26) {
safeBrowsingEnabled = true
}
}
cookieManager.setAcceptThirdPartyCookies(this, true)
}
}
)
}
}
companion object {
const val TAG = "PoTokenWebViewActivity"
}
}

View file

@ -1321,7 +1321,7 @@ class YTDLPUtil(private val context: Context, private val commandTemplateDao: Co
} }
} }
if (dataSyncID.isBlank()) { if (dataSyncID.isBlank() && value.useVisitorData) {
extractorArgs.add("player_skip=webpage,configs") extractorArgs.add("player_skip=webpage,configs")
extractorArgs.add("visitor_data=${value.visitorData}") extractorArgs.add("visitor_data=${value.visitorData}")
} }

View file

@ -10,7 +10,7 @@ import com.deniscerri.ytdl.database.models.ResultItem
import com.deniscerri.ytdl.database.viewmodel.ResultViewModel import com.deniscerri.ytdl.database.viewmodel.ResultViewModel
import com.deniscerri.ytdl.util.Extensions.getIDFromYoutubeURL import com.deniscerri.ytdl.util.Extensions.getIDFromYoutubeURL
import com.deniscerri.ytdl.util.Extensions.toStringDuration import com.deniscerri.ytdl.util.Extensions.toStringDuration
import com.deniscerri.ytdl.util.extractors.potoken.PoTokenGenerator import com.deniscerri.ytdl.ui.more.settings.advanced.generateyoutubepotokens.PoTokenGenerator
import com.google.gson.Gson import com.google.gson.Gson
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import org.json.JSONException import org.json.JSONException
@ -24,7 +24,6 @@ import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler
import org.schabi.newpipe.extractor.localization.Localization import org.schabi.newpipe.extractor.localization.Localization
import org.schabi.newpipe.extractor.playlist.PlaylistInfo import org.schabi.newpipe.extractor.playlist.PlaylistInfo
import org.schabi.newpipe.extractor.search.SearchInfo import org.schabi.newpipe.extractor.search.SearchInfo
import org.schabi.newpipe.extractor.services.youtube.PoTokenResult
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamExtractor import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamExtractor
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeSearchQueryHandlerFactory import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeSearchQueryHandlerFactory
import org.schabi.newpipe.extractor.stream.StreamInfo import org.schabi.newpipe.extractor.stream.StreamInfo

View file

@ -0,0 +1,37 @@
package com.deniscerri.ytdl.work
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE
import android.os.Build
import android.os.Environment
import android.os.Handler
import android.os.Looper
import android.widget.Toast
import androidx.work.ForegroundInfo
import androidx.work.Worker
import androidx.work.WorkerParameters
import com.deniscerri.ytdl.App
import com.deniscerri.ytdl.MainActivity
import com.deniscerri.ytdl.R
import com.deniscerri.ytdl.util.FileUtil
import com.deniscerri.ytdl.util.NotificationUtil
import java.io.File
import java.nio.file.Files
import java.nio.file.StandardCopyOption
class AutoGenerateWebPoTokenWorker(
private val context: Context,
workerParams: WorkerParameters
) : Worker(context, workerParams) {
override fun doWork(): Result {
return Result.success()
}
companion object {
const val TAG = "AutoGenerateWebPoTokenWorker"
}
}

View file

@ -222,6 +222,16 @@
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.materialswitch.MaterialSwitch
android:id="@+id/use_visitor_data"
android:layout_width="match_parent"
android:paddingHorizontal="20dp"
android:layout_height="70dp"
android:checked="true"
android:textSize="16sp"
android:textStyle="bold"
android:text="Use Visitor Data"
tools:ignore="HardcodedText" />
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"

View file

@ -6,65 +6,56 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<androidx.coordinatorlayout.widget.CoordinatorLayout <com.google.android.material.appbar.AppBarLayout
android:id="@+id/coordinatorLayout2" android:id="@+id/webview_appbarlayout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent" android:background="@android:color/transparent"
android:elevation="0dp"
android:fitsSystemWindows="true"
app:elevation="0dp"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"> app:layout_constraintTop_toTopOf="parent"
app:liftOnScroll="false">
<com.google.android.material.appbar.AppBarLayout <com.google.android.material.appbar.MaterialToolbar
android:id="@+id/webview_appbarlayout" android:id="@+id/webviewToolbar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="?attr/actionBarSize"
android:background="@android:color/transparent" app:layout_scrollFlags="scroll"
android:elevation="0dp" app:menu="@menu/webview_menu"
android:fitsSystemWindows="true" app:navigationContentDescription="@string/back"
app:elevation="0dp" app:navigationIcon="?attr/homeAsUpIndicator">
app:liftOnScroll="true">
<com.google.android.material.appbar.MaterialToolbar <Button
android:id="@+id/webviewToolbar" android:id="@+id/generate"
android:layout_width="match_parent" style="@style/Widget.Material3.Button.ElevatedButton.Icon"
android:layout_height="?attr/actionBarSize" android:layout_width="wrap_content"
app:layout_scrollFlags="scroll" android:layout_height="wrap_content"
app:menu="@menu/webview_menu" android:layout_gravity="end"
app:navigationContentDescription="@string/back" android:layout_marginHorizontal="10dp"
app:navigationIcon="?attr/homeAsUpIndicator"> android:autoLink="all"
android:text="@string/ok"
app:icon="@drawable/ic_check"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="PrivateResource" />
<Button </com.google.android.material.appbar.MaterialToolbar>
android:id="@+id/generate"
style="@style/Widget.Material3.Button.ElevatedButton.Icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_marginHorizontal="10dp"
android:autoLink="all"
android:text="@string/ok"
app:icon="@drawable/ic_check"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="PrivateResource" />
</com.google.android.material.appbar.MaterialToolbar> </com.google.android.material.appbar.AppBarLayout>
</com.google.android.material.appbar.AppBarLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<androidx.compose.ui.platform.ComposeView <androidx.compose.ui.platform.ComposeView
android:id="@+id/webview_compose" android:id="@+id/webview_compose"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/coordinatorLayout2" app:layout_constraintTop_toBottomOf="@+id/webview_appbarlayout"
tools:composableName="com.deniscerri.ytdl.ui.more.WebViewActivity.WebViewView" /> tools:composableName="com.deniscerri.ytdl.ui.more.settings.advanced.generateyoutubepotokens.webview.WebViewActivity.WebViewView" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -70,6 +70,6 @@
android:label="ChangeLogFragment" /> android:label="ChangeLogFragment" />
<fragment <fragment
android:id="@+id/generateYoutubePoTokensFragment" android:id="@+id/generateYoutubePoTokensFragment"
android:name="com.deniscerri.ytdl.ui.more.settings.advanced.GenerateYoutubePoTokensFragment" android:name="com.deniscerri.ytdl.ui.more.settings.advanced.generateyoutubepotokens.GenerateYoutubePoTokensFragment"
android:label="GenerateYoutubePoTokensFragment" /> android:label="GenerateYoutubePoTokensFragment" />
</navigation> </navigation>