mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2026-05-16 21:12:39 +02:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6a8ac0bfaa | |||
| 772bff6bc0 | |||
| b6b04054b9 | |||
| 1ea794459c | |||
| c27f5e4096 | |||
| 8469f17b4c |
@@ -1047,8 +1047,12 @@ class Settings : FragmentedStorageFileJson() {
|
||||
|
||||
@FormField(R.string.polycentric_local_cache, FieldForm.TOGGLE, R.string.polycentric_local_cache_description, 7)
|
||||
var polycentricLocalCache: Boolean = true;
|
||||
|
||||
var showPrivacyModeDialog: Boolean = true;
|
||||
|
||||
|
||||
fun shouldClearWebviewCookies(): Boolean {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@FormField(R.string.gesture_controls, FieldForm.GROUP, -1, 19)
|
||||
|
||||
+2
-1
@@ -235,7 +235,8 @@ class SourcePluginConfig(
|
||||
val variable: String? = null,
|
||||
val dependency: String? = null,
|
||||
val warningDialog: String? = null,
|
||||
val options: List<String>? = null
|
||||
val options: List<String>? = null,
|
||||
val isAdvanced: Boolean? = null
|
||||
) {
|
||||
val variableOrName: String get() = variable ?: name;
|
||||
}
|
||||
|
||||
@@ -5,10 +5,12 @@ import android.webkit.ConsoleMessage
|
||||
import android.webkit.JavascriptInterface
|
||||
import android.webkit.ValueCallback
|
||||
import android.webkit.WebChromeClient
|
||||
import android.webkit.WebResourceRequest
|
||||
import android.webkit.WebView
|
||||
import android.webkit.WebViewClient
|
||||
import androidx.collection.emptyLongSet
|
||||
import com.caoccao.javet.annotations.V8Function
|
||||
import com.caoccao.javet.utils.JavetResourceUtils
|
||||
import com.caoccao.javet.values.reference.V8ValueFunction
|
||||
import com.futo.platformplayer.api.media.platforms.js.JSClient
|
||||
import com.futo.platformplayer.api.media.platforms.js.SourcePluginConfig
|
||||
@@ -23,11 +25,14 @@ import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.sync.Semaphore
|
||||
import kotlinx.coroutines.withTimeout
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
class PackageBrowser: V8Package {
|
||||
override val name: String get() = "Browser";
|
||||
override val variableName: String = "browser";
|
||||
|
||||
private val _json = Json { };
|
||||
|
||||
@Transient
|
||||
private var _readySemaphore: Semaphore? = null;
|
||||
@Transient
|
||||
@@ -64,6 +69,10 @@ class PackageBrowser: V8Package {
|
||||
_readySemaphore = null;
|
||||
Logger.i("PackageBrowser", "Browser loaded");
|
||||
}
|
||||
|
||||
override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
_browser?.webChromeClient = object : WebChromeClient() {
|
||||
override fun onConsoleMessage(consoleMessage: ConsoleMessage?): Boolean {
|
||||
@@ -89,7 +98,9 @@ class PackageBrowser: V8Package {
|
||||
}
|
||||
@V8Function
|
||||
fun deinitialize() {
|
||||
_browser?.destroy();
|
||||
StateApp.instance.scopeOrNull?.launch(Dispatchers.Main) {
|
||||
_browser?.destroy();
|
||||
}
|
||||
_browser = null;
|
||||
}
|
||||
|
||||
@@ -129,7 +140,9 @@ class PackageBrowser: V8Package {
|
||||
Logger.i("PackageBrowser", "Browser loading url [${url}]");
|
||||
_readySemaphore = Semaphore(1, 1);
|
||||
StateApp.instance.scope.launch(Dispatchers.Main) {
|
||||
browser.loadUrl(url);
|
||||
try {
|
||||
browser.loadUrl(url);
|
||||
} catch(ex: Throwable) {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,18 +153,27 @@ class PackageBrowser: V8Package {
|
||||
if(callbackId != null && callback != null) {
|
||||
synchronized(_callbacks) {
|
||||
_callbacks.put(callbackId, {
|
||||
funcClone?.callVoid(null, arrayOf(it));
|
||||
_plugin.busy {
|
||||
funcClone?.callVoid(null, arrayOf(it));
|
||||
}
|
||||
if (!_plugin.isStopped)
|
||||
JavetResourceUtils.safeClose(funcClone);
|
||||
});
|
||||
}
|
||||
}
|
||||
StateApp.instance.scope.launch(Dispatchers.Main) {
|
||||
try {
|
||||
Logger.i("PackageBrowser", "Browser running JS with callback [${callbackId}]\n${(if(js.length > 200) (js.substring(0, 200) + "...") else js)})");
|
||||
browser.evaluateJavascript(js, object : ValueCallback<String> {
|
||||
override fun onReceiveValue(value: String?) {
|
||||
Logger.i("PackageBrowser", "Browser run finished");
|
||||
}
|
||||
})
|
||||
try {
|
||||
Logger.i("PackageBrowser", "Browser running JS with callback [${callbackId}]\n${(if(js.length > 200) (js.substring(0, 200) + "...") else js)})");
|
||||
browser.evaluateJavascript(js, object : ValueCallback<String> {
|
||||
override fun onReceiveValue(value: String?) {
|
||||
Logger.i("PackageBrowser", "Browser run finished");
|
||||
}
|
||||
})
|
||||
}
|
||||
catch(ex: Throwable) {
|
||||
Logger.e("PackageBrowser", "Browser running failed: " + ex.message, ex);
|
||||
}
|
||||
}
|
||||
catch(ex: Throwable) {
|
||||
Logger.e("PackageBrowser", "Failed to invoke browser", ex);
|
||||
@@ -168,12 +190,29 @@ class PackageBrowser: V8Package {
|
||||
browser.evaluateJavascript(js, object : ValueCallback<String> {
|
||||
override fun onReceiveValue(value: String?) {
|
||||
Logger.i("PackageBrowser", "Browser run returned: " + (value ?: ""));
|
||||
funcClone?.callVoid(null, arrayOf(value));
|
||||
StateApp.instance.scopeOrNull?.launch(Dispatchers.IO) {
|
||||
Logger.i("PackageBrowser", "Invoking V8 with result (${funcClone != null})");
|
||||
try {
|
||||
_plugin.busy {
|
||||
if (value != null) {
|
||||
val json = _json.decodeFromString<String>(value);
|
||||
funcClone?.callVoid(null, arrayOf(json));
|
||||
} else
|
||||
funcClone?.callVoid(null, arrayOf((null as String?)));
|
||||
}
|
||||
if (!_plugin.isStopped)
|
||||
JavetResourceUtils.safeClose(funcClone);
|
||||
}
|
||||
catch(ex: Throwable) {
|
||||
Logger.e("PackageBrowser", "Browser Failed to callback: " + ex.message, ex);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
catch(ex: Throwable) {
|
||||
Logger.e("PackageBrowser", "Failed to invoke browser", ex);
|
||||
Logger.e("PackageBrowser", "Browser Failed to invoke browser", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -184,8 +223,11 @@ class PackageBrowser: V8Package {
|
||||
fun callback(id: String, result: String) {
|
||||
Logger.i("PackageBrowser", "Browser Callback [${id}]: ${result}");
|
||||
val callback = synchronized(pack._callbacks) { pack._callbacks.remove(id); };
|
||||
if(callback != null)
|
||||
callback.invoke(result);
|
||||
if(callback != null) {
|
||||
StateApp.instance.scopeOrNull?.launch(Dispatchers.IO) {
|
||||
callback.invoke(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
|
||||
+13
-1
@@ -309,13 +309,14 @@ class SourceDetailFragment : MainFragment() {
|
||||
BigButton(c, context.getString(R.string.logout), context.getString(R.string.sign_out_of_the_platform), R.drawable.ic_logout) {
|
||||
logoutSource();
|
||||
},
|
||||
if(!Settings.instance.other.shouldClearWebviewCookies())
|
||||
BigButton(c, "Logout without Clear", "Logout but keep the browser cookies.\nThis allows for quick re-logging.", R.drawable.ic_logout) {
|
||||
logoutSource(false);
|
||||
}.apply {
|
||||
this.layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT).apply {
|
||||
setMargins(0, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5f, resources.displayMetrics).toInt(), 0, 0);
|
||||
};
|
||||
}
|
||||
} else null
|
||||
)
|
||||
);
|
||||
|
||||
@@ -518,6 +519,17 @@ class SourceDetailFragment : MainFragment() {
|
||||
}
|
||||
Logger.e(TAG, "Failed to set plugin authentication (loginSource, loginWarning)", e)
|
||||
}
|
||||
finally {
|
||||
if(Settings.instance.other.shouldClearWebviewCookies()) {
|
||||
try {
|
||||
val cookieManager: CookieManager =
|
||||
CookieManager.getInstance();
|
||||
cookieManager.removeAllCookies(null);
|
||||
} catch (ex: Throwable) {
|
||||
Logger.e(TAG, "Failed to clear cookies", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}, UIDialogs.ActionStyle.PRIMARY))
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import android.net.Uri
|
||||
import android.provider.DocumentsContract
|
||||
import android.util.DisplayMetrics
|
||||
import android.util.Log
|
||||
import android.webkit.CookieManager
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
@@ -448,6 +449,16 @@ class StateApp {
|
||||
_cacheDirectory?.let { ApiMethods.initCache(it) };
|
||||
}
|
||||
|
||||
if(Settings.instance.other.shouldClearWebviewCookies()) {
|
||||
try {
|
||||
val cookieManager: CookieManager =
|
||||
CookieManager.getInstance();
|
||||
cookieManager.removeAllCookies(null);
|
||||
} catch (ex: Throwable) {
|
||||
Logger.e(SourceDetailFragment.Companion.TAG, "Failed to clear cookies", ex);
|
||||
}
|
||||
}
|
||||
|
||||
Logger.i(TAG, "MainApp Starting: Initializing [ModerationsManager]");
|
||||
ModerationsManager.initialize(context);
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ class FieldForm : LinearLayout {
|
||||
}
|
||||
}
|
||||
|
||||
fun updateSettingsVisibility(group: GroupField? = null) {
|
||||
fun updateSettingsVisibility(group: GroupField? = null, allowEmptyGroups: Boolean = false) {
|
||||
val settings = group?.getFields() ?: _fields;
|
||||
val query = _editSearch.text.toString().lowercase();
|
||||
|
||||
@@ -58,7 +58,8 @@ class FieldForm : LinearLayout {
|
||||
val isGroupMatch = query.isEmpty() || group?.searchContent?.lowercase()?.contains(query) == true;
|
||||
for(field in settings) {
|
||||
if(field is GroupField) {
|
||||
updateSettingsVisibility(field);
|
||||
if(!allowEmptyGroups)
|
||||
updateSettingsVisibility(field);
|
||||
} else if(field is View && field.descriptor != null) {
|
||||
if(field.isAdvanced && !_showAdvancedSettings)
|
||||
{
|
||||
@@ -73,15 +74,21 @@ class FieldForm : LinearLayout {
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(field is View) {
|
||||
if(field.isAdvanced && !_showAdvancedSettings)
|
||||
field.visibility = View.GONE;
|
||||
else
|
||||
field.visibility = VISIBLE;
|
||||
}
|
||||
}
|
||||
if(group != null) {
|
||||
group.visibility = if (groupVisible) View.VISIBLE else View.GONE;
|
||||
}
|
||||
}
|
||||
|
||||
fun setShowAdvancedSettings(show: Boolean) {
|
||||
fun setShowAdvancedSettings(show: Boolean, allowEmptyGroups: Boolean = false) {
|
||||
_showAdvancedSettings = show;
|
||||
updateSettingsVisibility();
|
||||
updateSettingsVisibility(null, allowEmptyGroups);
|
||||
}
|
||||
fun setSearchQuery(query: String) {
|
||||
_editSearch.setText(query);
|
||||
@@ -141,7 +148,9 @@ class FieldForm : LinearLayout {
|
||||
}
|
||||
fun fromPluginSettings(settings: List<SourcePluginConfig.Setting>, values: HashMap<String, String?>, groupTitle: String? = null, groupDescription: String? = null) {
|
||||
_fieldsContainer.removeAllViews();
|
||||
val newFields = getFieldsFromPluginSettings(context, settings, values);
|
||||
val newFields = getFieldsFromPluginSettings(context, settings, values, {
|
||||
setShowAdvancedSettings(it, true);
|
||||
});
|
||||
if (newFields.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
@@ -157,6 +166,7 @@ class FieldForm : LinearLayout {
|
||||
_fieldsContainer.addView(v);
|
||||
}
|
||||
_fields = newFields.map { it.second };
|
||||
updateSettingsVisibility(null, true);
|
||||
} else {
|
||||
for(field in newFields) {
|
||||
finalizePluginSettingField(field.first, field.second, newFields);
|
||||
@@ -164,6 +174,8 @@ class FieldForm : LinearLayout {
|
||||
val group = GroupField(context, groupTitle, groupDescription)
|
||||
.withFields(newFields.map { it.second });
|
||||
_fieldsContainer.addView(group as View);
|
||||
_fields = newFields.map { it.second };
|
||||
updateSettingsVisibility(null, true);
|
||||
}
|
||||
}
|
||||
private fun finalizePluginSettingField(setting: SourcePluginConfig.Setting, field: IField, others: List<Pair<SourcePluginConfig.Setting, IField>>) {
|
||||
@@ -234,7 +246,7 @@ class FieldForm : LinearLayout {
|
||||
private val _json = Json;
|
||||
|
||||
|
||||
fun getFieldsFromPluginSettings(context: Context, settings: List<SourcePluginConfig.Setting>, values: HashMap<String, String?>): List<Pair<SourcePluginConfig.Setting, IField>> {
|
||||
fun getFieldsFromPluginSettings(context: Context, settings: List<SourcePluginConfig.Setting>, values: HashMap<String, String?>, onAdvancedChanged: ((newVal: Boolean)->Unit)? = null): List<Pair<SourcePluginConfig.Setting, IField>> {
|
||||
val fields = mutableListOf<Pair<SourcePluginConfig.Setting, IField>>()
|
||||
|
||||
for(setting in settings) {
|
||||
@@ -243,6 +255,7 @@ class FieldForm : LinearLayout {
|
||||
val field = when(setting.type.lowercase()) {
|
||||
"header" -> {
|
||||
val groupField = GroupField(context, setting.name, setting.description);
|
||||
groupField.isAdvanced = (setting.isAdvanced ?: false);
|
||||
groupField;
|
||||
}
|
||||
"boolean" -> {
|
||||
@@ -252,6 +265,7 @@ class FieldForm : LinearLayout {
|
||||
field.onChanged.subscribe { _, v, _ ->
|
||||
values[setting.variableOrName] = _json.encodeToString (v == 1 || v == true);
|
||||
}
|
||||
field.isAdvanced = (setting.isAdvanced ?: false);
|
||||
field;
|
||||
}
|
||||
"dropdown" -> {
|
||||
@@ -261,6 +275,7 @@ class FieldForm : LinearLayout {
|
||||
field.onChanged.subscribe { _, v, _ ->
|
||||
values[setting.variableOrName] = v.toString();
|
||||
}
|
||||
field.isAdvanced = (setting.isAdvanced ?: false);
|
||||
field;
|
||||
}
|
||||
else null;
|
||||
@@ -272,6 +287,17 @@ class FieldForm : LinearLayout {
|
||||
fields.add(Pair(setting, field));
|
||||
}
|
||||
}
|
||||
|
||||
if(onAdvancedChanged != null && settings.any { it.isAdvanced == true }) {
|
||||
val setting = SourcePluginConfig.Setting("Show Advanced", "See advanced settings, which may be counter productive to change", "boolean", "false");
|
||||
val field = ToggleField(context).withValue(setting.name, setting.description, false);
|
||||
|
||||
field.onChanged.subscribe { field, new, old ->
|
||||
onAdvancedChanged?.invoke(new as Boolean);
|
||||
}
|
||||
fields.add(Pair(setting, field));
|
||||
}
|
||||
|
||||
return fields;
|
||||
}
|
||||
|
||||
|
||||
Submodule app/src/stable/assets/sources/youtube updated: 781564715c...b9aae557fd
Submodule app/src/unstable/assets/sources/youtube updated: 781564715c...b9aae557fd
Reference in New Issue
Block a user