mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2025-08-27 12:46:12 +00:00
Locking of most known v8 interactions, fix returning previously returned jvm objects, Related fixes
This commit is contained in:
parent
58c9aeb1a2
commit
2fca7e9a01
12 changed files with 274 additions and 143 deletions
|
@ -99,10 +99,8 @@ open class JSClient : IPlatformClient {
|
||||||
override val icon: ImageVariable;
|
override val icon: ImageVariable;
|
||||||
override var capabilities: PlatformClientCapabilities = PlatformClientCapabilities();
|
override var capabilities: PlatformClientCapabilities = PlatformClientCapabilities();
|
||||||
|
|
||||||
private val _busyLock = Object();
|
|
||||||
private var _busyCounter = 0;
|
|
||||||
private var _busyAction = "";
|
private var _busyAction = "";
|
||||||
val isBusy: Boolean get() = _busyCounter > 0;
|
val isBusy: Boolean get() = _plugin.isBusy;
|
||||||
val isBusyAction: String get() {
|
val isBusyAction: String get() {
|
||||||
return _busyAction;
|
return _busyAction;
|
||||||
}
|
}
|
||||||
|
@ -225,9 +223,12 @@ open class JSClient : IPlatformClient {
|
||||||
|
|
||||||
Logger.i(TAG, "Plugin [${config.name}] initializing");
|
Logger.i(TAG, "Plugin [${config.name}] initializing");
|
||||||
plugin.start();
|
plugin.start();
|
||||||
|
Logger.i(TAG, "Plugin [${config.name}] started");
|
||||||
plugin.execute("plugin.config = ${Json.encodeToString(config)}");
|
plugin.execute("plugin.config = ${Json.encodeToString(config)}");
|
||||||
plugin.execute("plugin.settings = parseSettings(${Json.encodeToString(descriptor.getSettingsWithDefaults())})");
|
plugin.execute("plugin.settings = parseSettings(${Json.encodeToString(descriptor.getSettingsWithDefaults())})");
|
||||||
|
|
||||||
|
Logger.i(TAG, "Plugin [${config.name}] configs set");
|
||||||
|
|
||||||
descriptor.appSettings.loadDefaults(descriptor.config);
|
descriptor.appSettings.loadDefaults(descriptor.config);
|
||||||
|
|
||||||
_initialized = true;
|
_initialized = true;
|
||||||
|
@ -254,6 +255,7 @@ open class JSClient : IPlatformClient {
|
||||||
hasGetChannelPlaylists = plugin.executeBoolean("!!source.getChannelPlaylists") ?: false,
|
hasGetChannelPlaylists = plugin.executeBoolean("!!source.getChannelPlaylists") ?: false,
|
||||||
hasGetContentRecommendations = plugin.executeBoolean("!!source.getContentRecommendations") ?: false
|
hasGetContentRecommendations = plugin.executeBoolean("!!source.getContentRecommendations") ?: false
|
||||||
);
|
);
|
||||||
|
Logger.i(TAG, "Plugin [${config.name}] capabilities retrieved");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (capabilities.hasGetChannelTemplateByClaimMap)
|
if (capabilities.hasGetChannelTemplateByClaimMap)
|
||||||
|
@ -565,7 +567,7 @@ open class JSClient : IPlatformClient {
|
||||||
Logger.i(TAG, "JSClient.getPlaybackTracker(${url})");
|
Logger.i(TAG, "JSClient.getPlaybackTracker(${url})");
|
||||||
val tracker = plugin.executeTyped<V8Value>("source.getPlaybackTracker(${Json.encodeToString(url)})");
|
val tracker = plugin.executeTyped<V8Value>("source.getPlaybackTracker(${Json.encodeToString(url)})");
|
||||||
if(tracker is V8ValueObject)
|
if(tracker is V8ValueObject)
|
||||||
return@isBusyWith JSPlaybackTracker(config, tracker);
|
return@isBusyWith JSPlaybackTracker(this, tracker);
|
||||||
else
|
else
|
||||||
return@isBusyWith null;
|
return@isBusyWith null;
|
||||||
}
|
}
|
||||||
|
@ -747,25 +749,23 @@ open class JSClient : IPlatformClient {
|
||||||
return urls;
|
return urls;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun <T> busy(handle: ()->T): T {
|
||||||
|
return _plugin.busy {
|
||||||
|
return@busy handle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun <T> isBusyWith(actionName: String, handle: ()->T): T {
|
fun <T> isBusyWith(actionName: String, handle: ()->T): T {
|
||||||
val busyId = kotlin.random.Random.nextInt(9999);
|
//val busyId = kotlin.random.Random.nextInt(9999);
|
||||||
try {
|
return busy {
|
||||||
|
try {
|
||||||
|
_busyAction = actionName;
|
||||||
|
return@busy handle();
|
||||||
|
|
||||||
Logger.v(TAG, "Busy with [${actionName}] (${busyId})")
|
|
||||||
synchronized(_busyLock) {
|
|
||||||
_busyCounter++;
|
|
||||||
}
|
}
|
||||||
_busyAction = actionName;
|
finally {
|
||||||
return handle();
|
_busyAction = "";
|
||||||
}
|
|
||||||
finally {
|
|
||||||
_busyAction = "";
|
|
||||||
synchronized(_busyLock) {
|
|
||||||
_busyCounter--;
|
|
||||||
}
|
}
|
||||||
Logger.v(TAG, "Busy done [${actionName}] (${busyId})")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private fun <T> isBusyWith(handle: ()->T): T {
|
private fun <T> isBusyWith(handle: ()->T): T {
|
||||||
|
|
|
@ -29,7 +29,9 @@ abstract class JSPager<T> : IPager<T> {
|
||||||
this.pager = pager;
|
this.pager = pager;
|
||||||
this.config = config;
|
this.config = config;
|
||||||
|
|
||||||
_hasMorePages = pager.getOrDefault(config, "hasMore", "Pager", false) ?: false;
|
plugin.busy {
|
||||||
|
_hasMorePages = pager.getOrDefault(config, "hasMore", "Pager", false) ?: false;
|
||||||
|
}
|
||||||
getResults();
|
getResults();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,11 +46,14 @@ abstract class JSPager<T> : IPager<T> {
|
||||||
override fun nextPage() {
|
override fun nextPage() {
|
||||||
warnIfMainThread("JSPager.nextPage");
|
warnIfMainThread("JSPager.nextPage");
|
||||||
|
|
||||||
pager = plugin.getUnderlyingPlugin().catchScriptErrors("[${plugin.config.name}] JSPager", "pager.nextPage()") {
|
val pluginV8 = plugin.getUnderlyingPlugin();
|
||||||
pager.invoke("nextPage", arrayOf<Any>());
|
pluginV8.busy {
|
||||||
};
|
pager = pluginV8.catchScriptErrors("[${plugin.config.name}] JSPager", "pager.nextPage()") {
|
||||||
_hasMorePages = pager.getOrDefault(config, "hasMore", "Pager", false) ?: false;
|
pager.invoke("nextPage", arrayOf<Any>());
|
||||||
_resultChanged = true;
|
};
|
||||||
|
_hasMorePages = pager.getOrDefault(config, "hasMore", "Pager", false) ?: false;
|
||||||
|
_resultChanged = true;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
try {
|
try {
|
||||||
}
|
}
|
||||||
|
@ -70,15 +75,18 @@ abstract class JSPager<T> : IPager<T> {
|
||||||
return previousResults;
|
return previousResults;
|
||||||
|
|
||||||
warnIfMainThread("JSPager.getResults");
|
warnIfMainThread("JSPager.getResults");
|
||||||
val items = pager.getOrThrow<V8ValueArray>(config, "results", "JSPager");
|
|
||||||
if(items.v8Runtime.isDead || items.v8Runtime.isClosed)
|
return plugin.getUnderlyingPlugin().busy {
|
||||||
throw IllegalStateException("Runtime closed");
|
val items = pager.getOrThrow<V8ValueArray>(config, "results", "JSPager");
|
||||||
val newResults = items.toArray()
|
if (items.v8Runtime.isDead || items.v8Runtime.isClosed)
|
||||||
.map { convertResult(it as V8ValueObject) }
|
throw IllegalStateException("Runtime closed");
|
||||||
.toList();
|
val newResults = items.toArray()
|
||||||
_lastResults = newResults;
|
.map { convertResult(it as V8ValueObject) }
|
||||||
_resultChanged = false;
|
.toList();
|
||||||
return newResults;
|
_lastResults = newResults;
|
||||||
|
_resultChanged = false;
|
||||||
|
return@busy newResults;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract fun convertResult(obj: V8ValueObject): T;
|
abstract fun convertResult(obj: V8ValueObject): T;
|
||||||
|
|
|
@ -2,37 +2,50 @@ package com.futo.platformplayer.api.media.platforms.js.models
|
||||||
|
|
||||||
import com.caoccao.javet.values.reference.V8ValueObject
|
import com.caoccao.javet.values.reference.V8ValueObject
|
||||||
import com.futo.platformplayer.api.media.models.playback.IPlaybackTracker
|
import com.futo.platformplayer.api.media.models.playback.IPlaybackTracker
|
||||||
|
import com.futo.platformplayer.api.media.platforms.js.JSClient
|
||||||
import com.futo.platformplayer.engine.IV8PluginConfig
|
import com.futo.platformplayer.engine.IV8PluginConfig
|
||||||
import com.futo.platformplayer.engine.exceptions.ScriptImplementationException
|
import com.futo.platformplayer.engine.exceptions.ScriptImplementationException
|
||||||
import com.futo.platformplayer.getOrThrow
|
import com.futo.platformplayer.getOrThrow
|
||||||
import com.futo.platformplayer.logging.Logger
|
import com.futo.platformplayer.logging.Logger
|
||||||
|
import com.futo.platformplayer.states.StatePlatform
|
||||||
import com.futo.platformplayer.warnIfMainThread
|
import com.futo.platformplayer.warnIfMainThread
|
||||||
|
|
||||||
class JSPlaybackTracker: IPlaybackTracker {
|
class JSPlaybackTracker: IPlaybackTracker {
|
||||||
private val _config: IV8PluginConfig;
|
private lateinit var _client: JSClient;
|
||||||
private val _obj: V8ValueObject;
|
private lateinit var _config: IV8PluginConfig;
|
||||||
|
private lateinit var _obj: V8ValueObject;
|
||||||
|
|
||||||
private var _hasCalledInit: Boolean = false;
|
private var _hasCalledInit: Boolean = false;
|
||||||
private val _hasInit: Boolean;
|
private var _hasInit: Boolean = false;
|
||||||
|
|
||||||
private var _lastRequest: Long = Long.MIN_VALUE;
|
private var _lastRequest: Long = Long.MIN_VALUE;
|
||||||
|
|
||||||
private val _hasOnConcluded: Boolean;
|
private var _hasOnConcluded: Boolean = false;
|
||||||
|
|
||||||
override var nextRequest: Int = 1000
|
override var nextRequest: Int = 1000
|
||||||
private set;
|
private set;
|
||||||
|
|
||||||
constructor(config: IV8PluginConfig, obj: V8ValueObject) {
|
constructor(client: JSClient, obj: V8ValueObject) {
|
||||||
warnIfMainThread("JSPlaybackTracker.constructor");
|
warnIfMainThread("JSPlaybackTracker.constructor");
|
||||||
if(!obj.has("onProgress"))
|
|
||||||
throw ScriptImplementationException(config, "Missing onProgress on PlaybackTracker");
|
|
||||||
if(!obj.has("nextRequest"))
|
|
||||||
throw ScriptImplementationException(config, "Missing nextRequest on PlaybackTracker");
|
|
||||||
_hasOnConcluded = obj.has("onConcluded");
|
|
||||||
|
|
||||||
this._config = config;
|
client.busy {
|
||||||
this._obj = obj;
|
if (!obj.has("onProgress"))
|
||||||
this._hasInit = obj.has("onInit");
|
throw ScriptImplementationException(
|
||||||
|
client.config,
|
||||||
|
"Missing onProgress on PlaybackTracker"
|
||||||
|
);
|
||||||
|
if (!obj.has("nextRequest"))
|
||||||
|
throw ScriptImplementationException(
|
||||||
|
client.config,
|
||||||
|
"Missing nextRequest on PlaybackTracker"
|
||||||
|
);
|
||||||
|
_hasOnConcluded = obj.has("onConcluded");
|
||||||
|
|
||||||
|
this._client = client;
|
||||||
|
this._config = client.config;
|
||||||
|
this._obj = obj;
|
||||||
|
this._hasInit = obj.has("onInit");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onInit(seconds: Double) {
|
override fun onInit(seconds: Double) {
|
||||||
|
@ -40,12 +53,15 @@ class JSPlaybackTracker: IPlaybackTracker {
|
||||||
synchronized(_obj) {
|
synchronized(_obj) {
|
||||||
if(_hasCalledInit)
|
if(_hasCalledInit)
|
||||||
return;
|
return;
|
||||||
if (_hasInit) {
|
|
||||||
Logger.i("JSPlaybackTracker", "onInit (${seconds})");
|
_client.busy {
|
||||||
_obj.invokeVoid("onInit", seconds);
|
if (_hasInit) {
|
||||||
|
Logger.i("JSPlaybackTracker", "onInit (${seconds})");
|
||||||
|
_obj.invokeVoid("onInit", seconds);
|
||||||
|
}
|
||||||
|
nextRequest = Math.max(100, _obj.getOrThrow(_config, "nextRequest", "PlaybackTracker", false));
|
||||||
|
_hasCalledInit = true;
|
||||||
}
|
}
|
||||||
nextRequest = Math.max(100, _obj.getOrThrow(_config, "nextRequest", "PlaybackTracker", false));
|
|
||||||
_hasCalledInit = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,10 +71,12 @@ class JSPlaybackTracker: IPlaybackTracker {
|
||||||
if(!_hasCalledInit && _hasInit)
|
if(!_hasCalledInit && _hasInit)
|
||||||
onInit(seconds);
|
onInit(seconds);
|
||||||
else {
|
else {
|
||||||
Logger.i("JSPlaybackTracker", "onProgress (${seconds}, ${isPlaying})");
|
_client.busy {
|
||||||
_obj.invokeVoid("onProgress", Math.floor(seconds), isPlaying);
|
Logger.i("JSPlaybackTracker", "onProgress (${seconds}, ${isPlaying})");
|
||||||
nextRequest = Math.max(100, _obj.getOrThrow(_config, "nextRequest", "PlaybackTracker", false));
|
_obj.invokeVoid("onProgress", Math.floor(seconds), isPlaying);
|
||||||
_lastRequest = System.currentTimeMillis();
|
nextRequest = Math.max(100, _obj.getOrThrow(_config, "nextRequest", "PlaybackTracker", false));
|
||||||
|
_lastRequest = System.currentTimeMillis();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,7 +85,9 @@ class JSPlaybackTracker: IPlaybackTracker {
|
||||||
if(_hasOnConcluded) {
|
if(_hasOnConcluded) {
|
||||||
synchronized(_obj) {
|
synchronized(_obj) {
|
||||||
Logger.i("JSPlaybackTracker", "onConcluded");
|
Logger.i("JSPlaybackTracker", "onConcluded");
|
||||||
_obj.invokeVoid("onConcluded", -1);
|
_client.busy {
|
||||||
|
_obj.invokeVoid("onConcluded", -1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,16 +46,18 @@ class JSRequestExecutor {
|
||||||
if (_executor.isClosed)
|
if (_executor.isClosed)
|
||||||
throw IllegalStateException("Executor object is closed");
|
throw IllegalStateException("Executor object is closed");
|
||||||
|
|
||||||
val result = if(_plugin is DevJSClient)
|
return _plugin.getUnderlyingPlugin().busy {
|
||||||
StateDeveloper.instance.handleDevCall(_plugin.devID, "requestExecutor.executeRequest()") {
|
|
||||||
V8Plugin.catchScriptErrors<Any>(
|
val result = if(_plugin is DevJSClient)
|
||||||
_config,
|
StateDeveloper.instance.handleDevCall(_plugin.devID, "requestExecutor.executeRequest()") {
|
||||||
"[${_config.name}] JSRequestExecutor",
|
V8Plugin.catchScriptErrors<Any>(
|
||||||
"builder.modifyRequest()"
|
_config,
|
||||||
) {
|
"[${_config.name}] JSRequestExecutor",
|
||||||
_executor.invoke("executeRequest", url, headers, method, body);
|
"builder.modifyRequest()"
|
||||||
} as V8Value;
|
) {
|
||||||
}
|
_executor.invoke("executeRequest", url, headers, method, body);
|
||||||
|
} as V8Value;
|
||||||
|
}
|
||||||
else V8Plugin.catchScriptErrors<Any>(
|
else V8Plugin.catchScriptErrors<Any>(
|
||||||
_config,
|
_config,
|
||||||
"[${_config.name}] JSRequestExecutor",
|
"[${_config.name}] JSRequestExecutor",
|
||||||
|
@ -64,34 +66,35 @@ class JSRequestExecutor {
|
||||||
_executor.invoke("executeRequest", url, headers, method, body);
|
_executor.invoke("executeRequest", url, headers, method, body);
|
||||||
} as V8Value;
|
} as V8Value;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if(result is V8ValueString) {
|
if(result is V8ValueString) {
|
||||||
val base64Result = Base64.getDecoder().decode(result.value);
|
val base64Result = Base64.getDecoder().decode(result.value);
|
||||||
return base64Result;
|
return@busy base64Result;
|
||||||
}
|
|
||||||
if(result is V8ValueTypedArray) {
|
|
||||||
val buffer = result.buffer;
|
|
||||||
val byteBuffer = buffer.byteBuffer;
|
|
||||||
val bytesResult = ByteArray(result.byteLength);
|
|
||||||
byteBuffer.get(bytesResult, 0, result.byteLength);
|
|
||||||
buffer.close();
|
|
||||||
return bytesResult;
|
|
||||||
}
|
|
||||||
if(result is V8ValueObject && result.has("type")) {
|
|
||||||
val type = result.getOrThrow<Int>(_config, "type", "JSRequestModifier");
|
|
||||||
when(type) {
|
|
||||||
//TODO: Buffer type?
|
|
||||||
}
|
}
|
||||||
|
if(result is V8ValueTypedArray) {
|
||||||
|
val buffer = result.buffer;
|
||||||
|
val byteBuffer = buffer.byteBuffer;
|
||||||
|
val bytesResult = ByteArray(result.byteLength);
|
||||||
|
byteBuffer.get(bytesResult, 0, result.byteLength);
|
||||||
|
buffer.close();
|
||||||
|
return@busy bytesResult;
|
||||||
|
}
|
||||||
|
if(result is V8ValueObject && result.has("type")) {
|
||||||
|
val type = result.getOrThrow<Int>(_config, "type", "JSRequestModifier");
|
||||||
|
when(type) {
|
||||||
|
//TODO: Buffer type?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(result is V8ValueUndefined) {
|
||||||
|
if(_plugin is DevJSClient)
|
||||||
|
StateDeveloper.instance.logDevException(_plugin.devID, "JSRequestExecutor.executeRequest returned illegal undefined");
|
||||||
|
throw ScriptImplementationException(_config, "JSRequestExecutor.executeRequest returned illegal undefined", null);
|
||||||
|
}
|
||||||
|
throw NotImplementedError("Executor result type not implemented? " + result.javaClass.name);
|
||||||
}
|
}
|
||||||
if(result is V8ValueUndefined) {
|
finally {
|
||||||
if(_plugin is DevJSClient)
|
result.close();
|
||||||
StateDeveloper.instance.logDevException(_plugin.devID, "JSRequestExecutor.executeRequest returned illegal undefined");
|
|
||||||
throw ScriptImplementationException(_config, "JSRequestExecutor.executeRequest returned illegal undefined", null);
|
|
||||||
}
|
}
|
||||||
throw NotImplementedError("Executor result type not implemented? " + result.javaClass.name);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
result.close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,24 +102,25 @@ class JSRequestExecutor {
|
||||||
open fun cleanup() {
|
open fun cleanup() {
|
||||||
if (!hasCleanup || _executor.isClosed)
|
if (!hasCleanup || _executor.isClosed)
|
||||||
return;
|
return;
|
||||||
|
_plugin.busy {
|
||||||
if(_plugin is DevJSClient)
|
if(_plugin is DevJSClient)
|
||||||
StateDeveloper.instance.handleDevCall(_plugin.devID, "requestExecutor.executeRequest()") {
|
StateDeveloper.instance.handleDevCall(_plugin.devID, "requestExecutor.executeRequest()") {
|
||||||
V8Plugin.catchScriptErrors<Any>(
|
V8Plugin.catchScriptErrors<Any>(
|
||||||
_config,
|
_config,
|
||||||
"[${_config.name}] JSRequestExecutor",
|
"[${_config.name}] JSRequestExecutor",
|
||||||
"builder.modifyRequest()"
|
"builder.modifyRequest()"
|
||||||
) {
|
) {
|
||||||
_executor.invokeVoid("cleanup", null);
|
_executor.invokeVoid("cleanup", null);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else V8Plugin.catchScriptErrors<Any>(
|
else V8Plugin.catchScriptErrors<Any>(
|
||||||
_config,
|
_config,
|
||||||
"[${_config.name}] JSRequestExecutor",
|
"[${_config.name}] JSRequestExecutor",
|
||||||
"builder.modifyRequest()"
|
"builder.modifyRequest()"
|
||||||
) {
|
) {
|
||||||
_executor.invokeVoid("cleanup", null);
|
_executor.invokeVoid("cleanup", null);
|
||||||
};
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun finalize() {
|
protected fun finalize() {
|
||||||
|
|
|
@ -27,6 +27,7 @@ import com.futo.platformplayer.getOrThrowNullable
|
||||||
import com.futo.platformplayer.states.StateDeveloper
|
import com.futo.platformplayer.states.StateDeveloper
|
||||||
|
|
||||||
class JSVideoDetails : JSVideo, IPlatformVideoDetails {
|
class JSVideoDetails : JSVideo, IPlatformVideoDetails {
|
||||||
|
private val _plugin: JSClient;
|
||||||
private val _hasGetComments: Boolean;
|
private val _hasGetComments: Boolean;
|
||||||
private val _hasGetContentRecommendations: Boolean;
|
private val _hasGetContentRecommendations: Boolean;
|
||||||
private val _hasGetPlaybackTracker: Boolean;
|
private val _hasGetPlaybackTracker: Boolean;
|
||||||
|
@ -48,6 +49,7 @@ class JSVideoDetails : JSVideo, IPlatformVideoDetails {
|
||||||
|
|
||||||
constructor(plugin: JSClient, obj: V8ValueObject) : super(plugin.config, obj) {
|
constructor(plugin: JSClient, obj: V8ValueObject) : super(plugin.config, obj) {
|
||||||
val contextName = "VideoDetails";
|
val contextName = "VideoDetails";
|
||||||
|
_plugin = plugin;
|
||||||
val config = plugin.config;
|
val config = plugin.config;
|
||||||
description = _content.getOrThrow(config, "description", contextName);
|
description = _content.getOrThrow(config, "description", contextName);
|
||||||
video = JSVideoSourceDescriptor.fromV8(plugin, _content.getOrThrow(config, "video", contextName));
|
video = JSVideoSourceDescriptor.fromV8(plugin, _content.getOrThrow(config, "video", contextName));
|
||||||
|
@ -86,7 +88,7 @@ class JSVideoDetails : JSVideo, IPlatformVideoDetails {
|
||||||
val tracker = _content.invoke<V8Value>("getPlaybackTracker", arrayOf<Any>())
|
val tracker = _content.invoke<V8Value>("getPlaybackTracker", arrayOf<Any>())
|
||||||
?: return@catchScriptErrors null;
|
?: return@catchScriptErrors null;
|
||||||
if(tracker is V8ValueObject)
|
if(tracker is V8ValueObject)
|
||||||
return@catchScriptErrors JSPlaybackTracker(_pluginConfig, tracker);
|
return@catchScriptErrors JSPlaybackTracker(_plugin, tracker);
|
||||||
else
|
else
|
||||||
return@catchScriptErrors null;
|
return@catchScriptErrors null;
|
||||||
};
|
};
|
||||||
|
|
|
@ -77,7 +77,11 @@ abstract class JSSource {
|
||||||
|
|
||||||
Logger.v("JSSource", "Request executor for [${type}] requesting");
|
Logger.v("JSSource", "Request executor for [${type}] requesting");
|
||||||
val result = V8Plugin.catchScriptErrors<Any>(_config, "[${_config.name}] JSSource", "obj.getRequestExecutor()") {
|
val result = V8Plugin.catchScriptErrors<Any>(_config, "[${_config.name}] JSSource", "obj.getRequestExecutor()") {
|
||||||
_obj.invoke("getRequestExecutor", arrayOf<Any>());
|
_plugin.isBusyWith("getRequestExecutor") {
|
||||||
|
_plugin.getUnderlyingPlugin().busy {
|
||||||
|
_obj.invoke("getRequestExecutor", arrayOf<Any>());
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
Logger.v("JSSource", "Request executor for [${type}] received");
|
Logger.v("JSSource", "Request executor for [${type}] received");
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
package com.futo.platformplayer.engine
|
package com.futo.platformplayer.engine
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import com.caoccao.javet.entities.JavetEntityError
|
||||||
import com.caoccao.javet.exceptions.JavetCompilationException
|
import com.caoccao.javet.exceptions.JavetCompilationException
|
||||||
import com.caoccao.javet.exceptions.JavetException
|
import com.caoccao.javet.exceptions.JavetException
|
||||||
import com.caoccao.javet.exceptions.JavetExecutionException
|
import com.caoccao.javet.exceptions.JavetExecutionException
|
||||||
|
import com.caoccao.javet.interfaces.IJavetEntityError
|
||||||
import com.caoccao.javet.interop.V8Host
|
import com.caoccao.javet.interop.V8Host
|
||||||
import com.caoccao.javet.interop.V8Runtime
|
import com.caoccao.javet.interop.V8Runtime
|
||||||
import com.caoccao.javet.interop.options.V8Flags
|
import com.caoccao.javet.interop.options.V8Flags
|
||||||
|
@ -42,6 +44,9 @@ import com.futo.platformplayer.logging.Logger
|
||||||
import com.futo.platformplayer.states.StateAssets
|
import com.futo.platformplayer.states.StateAssets
|
||||||
import com.futo.platformplayer.warnIfMainThread
|
import com.futo.platformplayer.warnIfMainThread
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
import java.util.concurrent.Semaphore
|
||||||
|
import java.util.concurrent.locks.ReentrantLock
|
||||||
|
import kotlin.concurrent.withLock
|
||||||
|
|
||||||
class V8Plugin {
|
class V8Plugin {
|
||||||
val config: IV8PluginConfig;
|
val config: IV8PluginConfig;
|
||||||
|
@ -70,9 +75,10 @@ class V8Plugin {
|
||||||
val onStopped = Event1<V8Plugin>();
|
val onStopped = Event1<V8Plugin>();
|
||||||
|
|
||||||
//TODO: Implement a more universal isBusy system for plugins + JSClient + pooling? TBD if propagation would be beneficial
|
//TODO: Implement a more universal isBusy system for plugins + JSClient + pooling? TBD if propagation would be beneficial
|
||||||
private val _busyCounterLock = Object();
|
//private val _busyCounterLock = Object();
|
||||||
private var _busyCounter = 0;
|
//private var _busyCounter = 0;
|
||||||
val isBusy get() = synchronized(_busyCounterLock) { _busyCounter > 0 };
|
private val _busyLock = ReentrantLock()//Semaphore(1);
|
||||||
|
val isBusy get() = _busyLock.isLocked;//synchronized(_busyCounterLock) { _busyCounter > 0 };
|
||||||
|
|
||||||
var allowDevSubmit: Boolean = false
|
var allowDevSubmit: Boolean = false
|
||||||
private set(value) {
|
private set(value) {
|
||||||
|
@ -146,14 +152,19 @@ class V8Plugin {
|
||||||
val host = V8Host.getV8Instance();
|
val host = V8Host.getV8Instance();
|
||||||
val options = host.jsRuntimeType.getRuntimeOptions();
|
val options = host.jsRuntimeType.getRuntimeOptions();
|
||||||
|
|
||||||
|
Logger.i(TAG, "Plugin [${config.name}] start: Creating runtime")
|
||||||
|
|
||||||
_runtime = host.createV8Runtime(options);
|
_runtime = host.createV8Runtime(options);
|
||||||
if (!host.isIsolateCreated)
|
if (!host.isIsolateCreated)
|
||||||
throw IllegalStateException("Isolate not created");
|
throw IllegalStateException("Isolate not created");
|
||||||
|
|
||||||
|
Logger.i(TAG, "Plugin [${config.name}] start: Created runtime")
|
||||||
|
|
||||||
//Setup bridge
|
//Setup bridge
|
||||||
_runtime?.let {
|
_runtime?.let {
|
||||||
it.converter = V8Converter();
|
it.converter = V8Converter();
|
||||||
|
|
||||||
|
Logger.i(TAG, "Plugin [${config.name}] start: Loading packages")
|
||||||
for (pack in _depsPackages) {
|
for (pack in _depsPackages) {
|
||||||
if (pack.variableName != null)
|
if (pack.variableName != null)
|
||||||
it.createV8ValueObject().use { v8valueObject ->
|
it.createV8ValueObject().use { v8valueObject ->
|
||||||
|
@ -166,6 +177,8 @@ class V8Plugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logger.i(TAG, "Plugin [${config.name}] start: Loading deps")
|
||||||
|
|
||||||
//Load deps
|
//Load deps
|
||||||
for (dep in _deps)
|
for (dep in _deps)
|
||||||
catchScriptErrors("Dep[${dep.key}]") {
|
catchScriptErrors("Dep[${dep.key}]") {
|
||||||
|
@ -176,20 +189,23 @@ class V8Plugin {
|
||||||
if (config.allowEval)
|
if (config.allowEval)
|
||||||
it.allowEval(true);
|
it.allowEval(true);
|
||||||
|
|
||||||
|
Logger.i(TAG, "Plugin [${config.name}] start: Loading script")
|
||||||
//Load plugin
|
//Load plugin
|
||||||
catchScriptErrors("Plugin[${config.name}]") {
|
catchScriptErrors("Plugin[${config.name}]") {
|
||||||
it.getExecutor(script).executeVoid()
|
it.getExecutor(script).executeVoid()
|
||||||
};
|
};
|
||||||
isStopped = false;
|
isStopped = false;
|
||||||
|
Logger.i(TAG, "Plugin [${config.name}] start: Script loaded")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fun stop(){
|
fun stop(){
|
||||||
Logger.i(TAG, "Stopping plugin [${config.name}]");
|
Logger.i(TAG, "Stopping plugin [${config.name}]");
|
||||||
isStopped = true;
|
busy {
|
||||||
whenNotBusy {
|
|
||||||
Logger.i(TAG, "Plugin stopping");
|
Logger.i(TAG, "Plugin stopping");
|
||||||
synchronized(_runtimeLock) {
|
synchronized(_runtimeLock) {
|
||||||
|
if(isStopped)
|
||||||
|
return@busy;
|
||||||
isStopped = true;
|
isStopped = true;
|
||||||
|
|
||||||
//Cleanup http
|
//Cleanup http
|
||||||
|
@ -203,7 +219,7 @@ class V8Plugin {
|
||||||
_runtime = null;
|
_runtime = null;
|
||||||
if(!it.isClosed && !it.isDead) {
|
if(!it.isClosed && !it.isDead) {
|
||||||
try {
|
try {
|
||||||
it.close(true);
|
it.close();
|
||||||
}
|
}
|
||||||
catch(ex: JavetException) {
|
catch(ex: JavetException) {
|
||||||
//In case race conditions are going on, already closed runtimes are fine.
|
//In case race conditions are going on, already closed runtimes are fine.
|
||||||
|
@ -219,6 +235,12 @@ class V8Plugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun <T> busy(handle: ()->T): T {
|
||||||
|
_busyLock.withLock {
|
||||||
|
//Logger.i(TAG, "Entered busy: " + Thread.currentThread().stackTrace.drop(3)?.firstOrNull()?.toString() + ", " + Thread.currentThread().stackTrace.drop(4)?.firstOrNull()?.toString());
|
||||||
|
return handle();
|
||||||
|
}
|
||||||
|
}
|
||||||
fun execute(js: String) : V8Value {
|
fun execute(js: String) : V8Value {
|
||||||
return executeTyped<V8Value>(js);
|
return executeTyped<V8Value>(js);
|
||||||
}
|
}
|
||||||
|
@ -227,6 +249,14 @@ class V8Plugin {
|
||||||
if(isStopped)
|
if(isStopped)
|
||||||
throw PluginEngineStoppedException(config, "Instance is stopped", js);
|
throw PluginEngineStoppedException(config, "Instance is stopped", js);
|
||||||
|
|
||||||
|
return busy {
|
||||||
|
|
||||||
|
val runtime = _runtime ?: throw IllegalStateException("JSPlugin not started yet");
|
||||||
|
return@busy catchScriptErrors("Plugin[${config.name}]", js) {
|
||||||
|
runtime.getExecutor(js).execute()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
/*
|
||||||
synchronized(_busyCounterLock) {
|
synchronized(_busyCounterLock) {
|
||||||
_busyCounter++;
|
_busyCounter++;
|
||||||
}
|
}
|
||||||
|
@ -249,11 +279,26 @@ class V8Plugin {
|
||||||
_busyCounter--;
|
_busyCounter--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
fun executeBoolean(js: String) : Boolean? = catchScriptErrors("Plugin[${config.name}]") { executeTyped<V8ValueBoolean>(js).value };
|
fun executeBoolean(js: String) : Boolean? = busy { catchScriptErrors("Plugin[${config.name}]") { executeTyped<V8ValueBoolean>(js).value } }
|
||||||
fun executeString(js: String) : String? = catchScriptErrors("Plugin[${config.name}]") { executeTyped<V8ValueString>(js).value };
|
fun executeString(js: String) : String? = busy { catchScriptErrors("Plugin[${config.name}]") { executeTyped<V8ValueString>(js).value } }
|
||||||
fun executeInteger(js: String) : Int? = catchScriptErrors("Plugin[${config.name}]") { executeTyped<V8ValueInteger>(js).value };
|
fun executeInteger(js: String) : Int? = busy { catchScriptErrors("Plugin[${config.name}]") { executeTyped<V8ValueInteger>(js).value } }
|
||||||
|
|
||||||
|
/*
|
||||||
|
fun <T> whenNotBusyBlocking(handler: (V8Plugin)->T): T {
|
||||||
|
while(true) {
|
||||||
|
synchronized(_busyCounterLock) {
|
||||||
|
if(_busyCounter == 0)
|
||||||
|
{
|
||||||
|
return handler(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Thread.sleep(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
/*
|
||||||
fun whenNotBusy(handler: (V8Plugin)->Unit) {
|
fun whenNotBusy(handler: (V8Plugin)->Unit) {
|
||||||
synchronized(_busyCounterLock) {
|
synchronized(_busyCounterLock) {
|
||||||
if(_busyCounter == 0)
|
if(_busyCounter == 0)
|
||||||
|
@ -264,12 +309,25 @@ class V8Plugin {
|
||||||
if(it == 0) {
|
if(it == 0) {
|
||||||
Logger.w(TAG, "V8Plugin afterBusy handled");
|
Logger.w(TAG, "V8Plugin afterBusy handled");
|
||||||
afterBusy.remove(tag);
|
afterBusy.remove(tag);
|
||||||
handler(this);
|
|
||||||
|
var failed = false;
|
||||||
|
synchronized(_busyCounterLock) {
|
||||||
|
if(_busyCounter > 0) {
|
||||||
|
failed = true;
|
||||||
|
return@synchronized
|
||||||
|
}
|
||||||
|
handler(this);
|
||||||
|
}
|
||||||
|
if(failed)
|
||||||
|
busy {
|
||||||
|
handler(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
private fun getPackage(packageName: String, allowNull: Boolean = false): V8Package? {
|
private fun getPackage(packageName: String, allowNull: Boolean = false): V8Package? {
|
||||||
//TODO: Auto get all package types?
|
//TODO: Auto get all package types?
|
||||||
|
@ -331,24 +389,29 @@ class V8Plugin {
|
||||||
throw ScriptCompilationException(config, "Compilation: [${context}]: ${scriptEx.message}\n(${scriptEx.scriptingError.lineNumber})[${scriptEx.scriptingError.startColumn}-${scriptEx.scriptingError.endColumn}]: ${scriptEx.scriptingError.sourceLine}", null, codeStripped);
|
throw ScriptCompilationException(config, "Compilation: [${context}]: ${scriptEx.message}\n(${scriptEx.scriptingError.lineNumber})[${scriptEx.scriptingError.startColumn}-${scriptEx.scriptingError.endColumn}]: ${scriptEx.scriptingError.sourceLine}", null, codeStripped);
|
||||||
}
|
}
|
||||||
catch(executeEx: JavetExecutionException) {
|
catch(executeEx: JavetExecutionException) {
|
||||||
if(executeEx.scriptingError?.context is V8ValueObject) {
|
if(executeEx.scriptingError?.context is IJavetEntityError) {
|
||||||
val obj = executeEx.scriptingError?.context as V8ValueObject
|
val obj = executeEx.scriptingError?.context as IJavetEntityError
|
||||||
if(obj.has("plugin_type") == true) {
|
if(obj.context.containsKey("plugin_type") == true) {
|
||||||
val pluginType = obj.get<V8ValueString>("plugin_type").toString();
|
val pluginType = obj.context["plugin_type"].toString();
|
||||||
|
//val pluginType = obj.get<V8ValueString>("plugin_type").toString();
|
||||||
|
|
||||||
//Captcha
|
//Captcha
|
||||||
if (pluginType == "CaptchaRequiredException") {
|
if (pluginType == "CaptchaRequiredException") {
|
||||||
throw ScriptCaptchaRequiredException(config,
|
throw ScriptCaptchaRequiredException(config,
|
||||||
obj.get<V8ValueString>("url")?.toString(),
|
obj.context["url"]?.toString(),
|
||||||
obj.get<V8ValueString>("body")?.toString(),
|
obj.context["body"]?.toString(),
|
||||||
|
//obj.get<V8ValueString>("url")?.toString(),
|
||||||
|
//obj.get<V8ValueString>("body")?.toString(),
|
||||||
executeEx, executeEx.scriptingError?.stack, codeStripped);
|
executeEx, executeEx.scriptingError?.stack, codeStripped);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Reload Required
|
//Reload Required
|
||||||
if (pluginType == "ReloadRequiredException") {
|
if (pluginType == "ReloadRequiredException") {
|
||||||
throw ScriptReloadRequiredException(config,
|
throw ScriptReloadRequiredException(config,
|
||||||
obj.get<V8ValueString>("message")?.toString(),
|
obj.context["msg"]?.toString(),
|
||||||
obj.get<V8ValueString>("reloadData")?.toString(),
|
obj.context["reloadData"]?.toString(),
|
||||||
|
//obj.get<V8ValueString>("message")?.toString(),
|
||||||
|
//obj.get<V8ValueString>("reloadData")?.toString(),
|
||||||
executeEx, executeEx.scriptingError?.stack, codeStripped);
|
executeEx, executeEx.scriptingError?.stack, codeStripped);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,8 +13,8 @@ open class V8BindObject : IV8Convertable {
|
||||||
|
|
||||||
override fun toV8(runtime: V8Runtime): V8Value? {
|
override fun toV8(runtime: V8Runtime): V8Value? {
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
if(_runtimeObj != null)
|
//if(_runtimeObj != null)
|
||||||
return _runtimeObj;
|
// return _runtimeObj;
|
||||||
|
|
||||||
val v8Obj = runtime.createV8ValueObject();
|
val v8Obj = runtime.createV8ValueObject();
|
||||||
v8Obj.bind(this);
|
v8Obj.bind(this);
|
||||||
|
|
|
@ -4,6 +4,7 @@ import android.media.MediaCodec
|
||||||
import android.media.MediaCodecList
|
import android.media.MediaCodecList
|
||||||
import com.caoccao.javet.annotations.V8Function
|
import com.caoccao.javet.annotations.V8Function
|
||||||
import com.caoccao.javet.annotations.V8Property
|
import com.caoccao.javet.annotations.V8Property
|
||||||
|
import com.caoccao.javet.interop.callback.JavetCallbackContext
|
||||||
import com.caoccao.javet.utils.JavetResourceUtils
|
import com.caoccao.javet.utils.JavetResourceUtils
|
||||||
import com.caoccao.javet.values.V8Value
|
import com.caoccao.javet.values.V8Value
|
||||||
import com.caoccao.javet.values.reference.V8ValueFunction
|
import com.caoccao.javet.values.reference.V8ValueFunction
|
||||||
|
@ -112,28 +113,42 @@ class PackageBridge : V8Package {
|
||||||
@V8Function
|
@V8Function
|
||||||
fun setTimeout(func: V8ValueFunction, timeout: Long): Int {
|
fun setTimeout(func: V8ValueFunction, timeout: Long): Int {
|
||||||
val id = timeoutCounter++;
|
val id = timeoutCounter++;
|
||||||
|
|
||||||
val funcClone = func.toClone<V8ValueFunction>()
|
val funcClone = func.toClone<V8ValueFunction>()
|
||||||
|
|
||||||
StateApp.instance.scopeOrNull?.launch(Dispatchers.IO) {
|
StateApp.instance.scopeOrNull?.launch(Dispatchers.IO) {
|
||||||
delay(timeout);
|
delay(timeout);
|
||||||
|
if(_plugin.isStopped)
|
||||||
|
return@launch;
|
||||||
synchronized(timeoutMap) {
|
synchronized(timeoutMap) {
|
||||||
if(!timeoutMap.contains(id)) {
|
if(!timeoutMap.contains(id)) {
|
||||||
JavetResourceUtils.safeClose(funcClone);
|
_plugin.busy {
|
||||||
|
if(!_plugin.isStopped)
|
||||||
|
JavetResourceUtils.safeClose(funcClone);
|
||||||
|
}
|
||||||
return@launch;
|
return@launch;
|
||||||
}
|
}
|
||||||
timeoutMap.remove(id);
|
timeoutMap.remove(id);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
_plugin.whenNotBusy {
|
Logger.v(TAG, "Timeout started [${id}]");
|
||||||
funcClone.callVoid(null, arrayOf<Any>());
|
_plugin.busy {
|
||||||
|
Logger.v(TAG, "Timeout call started [${id}]");
|
||||||
|
if(!_plugin.isStopped)
|
||||||
|
funcClone.callVoid(null, arrayOf<Any>());
|
||||||
|
Logger.v(TAG, "Timeout call ended [${id}]");
|
||||||
}
|
}
|
||||||
|
Logger.v(TAG, "Timeout resolved [${id}]");
|
||||||
}
|
}
|
||||||
catch(ex: Throwable) {
|
catch(ex: Throwable) {
|
||||||
Logger.e(TAG, "Failed timeout callback", ex);
|
Logger.e(TAG, "Failed timeout callback", ex);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
JavetResourceUtils.safeClose(funcClone);
|
_plugin.busy {
|
||||||
|
if(!_plugin.isStopped)
|
||||||
|
JavetResourceUtils.safeClose(funcClone);
|
||||||
|
}
|
||||||
|
//_plugin.whenNotBusy {
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
synchronized(timeoutMap) {
|
synchronized(timeoutMap) {
|
||||||
|
|
|
@ -656,7 +656,9 @@ class PackageHttp: V8Package {
|
||||||
_isOpen = true;
|
_isOpen = true;
|
||||||
if(hasOpen && _listeners?.isClosed != true) {
|
if(hasOpen && _listeners?.isClosed != true) {
|
||||||
try {
|
try {
|
||||||
_listeners?.invokeVoid("open", arrayOf<Any>());
|
_package._plugin.busy {
|
||||||
|
_listeners?.invokeVoid("open", arrayOf<Any>());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch(ex: Throwable){
|
catch(ex: Throwable){
|
||||||
Logger.e(TAG, "Socket for [${_packageClient.parentConfig.name}] open failed: " + ex.message, ex);
|
Logger.e(TAG, "Socket for [${_packageClient.parentConfig.name}] open failed: " + ex.message, ex);
|
||||||
|
@ -666,7 +668,9 @@ class PackageHttp: V8Package {
|
||||||
override fun message(msg: String) {
|
override fun message(msg: String) {
|
||||||
if(hasMessage && _listeners?.isClosed != true) {
|
if(hasMessage && _listeners?.isClosed != true) {
|
||||||
try {
|
try {
|
||||||
_listeners?.invokeVoid("message", msg);
|
_package._plugin.busy {
|
||||||
|
_listeners?.invokeVoid("message", msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch(ex: Throwable) {}
|
catch(ex: Throwable) {}
|
||||||
}
|
}
|
||||||
|
@ -675,7 +679,9 @@ class PackageHttp: V8Package {
|
||||||
if(hasClosing && _listeners?.isClosed != true)
|
if(hasClosing && _listeners?.isClosed != true)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
_listeners?.invokeVoid("closing", code, reason);
|
_package._plugin.busy {
|
||||||
|
_listeners?.invokeVoid("closing", code, reason);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch(ex: Throwable){
|
catch(ex: Throwable){
|
||||||
Logger.e(TAG, "Socket for [${_packageClient.parentConfig.name}] closing failed: " + ex.message, ex);
|
Logger.e(TAG, "Socket for [${_packageClient.parentConfig.name}] closing failed: " + ex.message, ex);
|
||||||
|
@ -686,7 +692,9 @@ class PackageHttp: V8Package {
|
||||||
_isOpen = false;
|
_isOpen = false;
|
||||||
if(hasClosed && _listeners?.isClosed != true) {
|
if(hasClosed && _listeners?.isClosed != true) {
|
||||||
try {
|
try {
|
||||||
_listeners?.invokeVoid("closed", code, reason);
|
_package._plugin.busy {
|
||||||
|
_listeners?.invokeVoid("closed", code, reason);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch(ex: Throwable){
|
catch(ex: Throwable){
|
||||||
Logger.e(TAG, "Socket for [${_packageClient.parentConfig.name}] closed failed: " + ex.message, ex);
|
Logger.e(TAG, "Socket for [${_packageClient.parentConfig.name}] closed failed: " + ex.message, ex);
|
||||||
|
@ -702,7 +710,9 @@ class PackageHttp: V8Package {
|
||||||
Logger.e(TAG, "Websocket failure: ${exception.message} (${_url})", exception);
|
Logger.e(TAG, "Websocket failure: ${exception.message} (${_url})", exception);
|
||||||
if(hasFailure && _listeners?.isClosed != true) {
|
if(hasFailure && _listeners?.isClosed != true) {
|
||||||
try {
|
try {
|
||||||
_listeners?.invokeVoid("failure", exception.message);
|
_package._plugin.busy {
|
||||||
|
_listeners?.invokeVoid("failure", exception.message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch(ex: Throwable){
|
catch(ex: Throwable){
|
||||||
Logger.e(TAG, "Socket for [${_packageClient.parentConfig.name}] closed failed: " + ex.message, ex);
|
Logger.e(TAG, "Socket for [${_packageClient.parentConfig.name}] closed failed: " + ex.message, ex);
|
||||||
|
|
|
@ -2497,7 +2497,9 @@ class VideoDetailView : ConstraintLayout {
|
||||||
|
|
||||||
val url = _url;
|
val url = _url;
|
||||||
if (!url.isNullOrBlank()) {
|
if (!url.isNullOrBlank()) {
|
||||||
setLoading(true);
|
fragment.lifecycleScope.launch(Dispatchers.Main) {
|
||||||
|
setLoading(true);
|
||||||
|
}
|
||||||
_taskLoadVideo.run(url);
|
_taskLoadVideo.run(url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -570,7 +570,7 @@ abstract class FutoVideoPlayerBase : RelativeLayout {
|
||||||
if (generated != null) {
|
if (generated != null) {
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
val dataSource = if(videoSource is JSSource && (videoSource.requiresCustomDatasource))
|
val dataSource = if(videoSource is JSSource && (videoSource.requiresCustomDatasource))
|
||||||
videoSource.getHttpDataSourceFactory()
|
withContext(Dispatchers.IO) { videoSource.getHttpDataSourceFactory() }
|
||||||
else
|
else
|
||||||
DefaultHttpDataSource.Factory().setUserAgent(DEFAULT_USER_AGENT);
|
DefaultHttpDataSource.Factory().setUserAgent(DEFAULT_USER_AGENT);
|
||||||
|
|
||||||
|
@ -593,6 +593,7 @@ abstract class FutoVideoPlayerBase : RelativeLayout {
|
||||||
catch(reloadRequired: ScriptReloadRequiredException) {
|
catch(reloadRequired: ScriptReloadRequiredException) {
|
||||||
Logger.i(TAG, "Reload required detected");
|
Logger.i(TAG, "Reload required detected");
|
||||||
StatePlatform.instance.handleReloadRequired(reloadRequired, {
|
StatePlatform.instance.handleReloadRequired(reloadRequired, {
|
||||||
|
Logger.i(TAG, "ReloadRequired started reloading video");
|
||||||
onReloadRequired.emit();
|
onReloadRequired.emit();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -704,9 +705,11 @@ abstract class FutoVideoPlayerBase : RelativeLayout {
|
||||||
val plugin = audioSource.getUnderlyingPlugin();
|
val plugin = audioSource.getUnderlyingPlugin();
|
||||||
if(plugin == null)
|
if(plugin == null)
|
||||||
return@launch;
|
return@launch;
|
||||||
|
/*
|
||||||
StatePlatform.instance.reEnableClient(plugin.id, {
|
StatePlatform.instance.reEnableClient(plugin.id, {
|
||||||
onReloadRequired.emit();
|
onReloadRequired.emit();
|
||||||
});
|
});
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
catch(ex: Throwable) {
|
catch(ex: Throwable) {
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue