finish po token generation
This commit is contained in:
parent
90e16d203d
commit
1d560a98ca
20 changed files with 301 additions and 107 deletions
|
|
@ -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" />
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
)
|
)
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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}")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
Loading…
Reference in a new issue