From 1ecd1f5e04f8413847164349b38dcb04abc9f3f3 Mon Sep 17 00:00:00 2001 From: Koen J Date: Thu, 22 May 2025 13:45:57 +0200 Subject: [PATCH] Fix for throttled networks (airplane wifi) freezing app opening downloaded content. --- .../api/media/PlatformClientPool.kt | 6 ++++-- .../api/media/PlatformMultiClientPool.kt | 6 ++++-- .../api/media/platforms/js/DevJSClient.kt | 7 +++++-- .../api/media/platforms/js/JSClient.kt | 9 ++++++-- .../platformplayer/states/StatePlatform.kt | 21 ++++++++++--------- 5 files changed, 31 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/com/futo/platformplayer/api/media/PlatformClientPool.kt b/app/src/main/java/com/futo/platformplayer/api/media/PlatformClientPool.kt index 0119bf38..211f83a6 100644 --- a/app/src/main/java/com/futo/platformplayer/api/media/PlatformClientPool.kt +++ b/app/src/main/java/com/futo/platformplayer/api/media/PlatformClientPool.kt @@ -14,14 +14,16 @@ class PlatformClientPool { private var _poolCounter = 0; private val _poolName: String?; private val _privatePool: Boolean; + private val _isolatedInitialization: Boolean var isDead: Boolean = false private set; val onDead = Event2(); - constructor(parentClient: IPlatformClient, name: String? = null, privatePool: Boolean = false) { + constructor(parentClient: IPlatformClient, name: String? = null, privatePool: Boolean = false, isolatedInitialization: Boolean = false) { _poolName = name; _privatePool = privatePool; + _isolatedInitialization = isolatedInitialization if(parentClient !is JSClient) throw IllegalArgumentException("Pooling only supported for JSClients right now"); Logger.i(TAG, "Pool for ${parentClient.name} was started"); @@ -53,7 +55,7 @@ class PlatformClientPool { reserved = _pool.keys.find { !it.isBusy }; if(reserved == null && _pool.size < capacity) { Logger.i(TAG, "Started additional [${_parent.name}] client in pool [${_poolName}] (${_pool.size + 1}/${capacity})"); - reserved = _parent.getCopy(_privatePool); + reserved = _parent.getCopy(_privatePool, _isolatedInitialization); reserved?.onCaptchaException?.subscribe { client, ex -> StateApp.instance.handleCaptchaException(client, ex); diff --git a/app/src/main/java/com/futo/platformplayer/api/media/PlatformMultiClientPool.kt b/app/src/main/java/com/futo/platformplayer/api/media/PlatformMultiClientPool.kt index a9fc3819..fcc85371 100644 --- a/app/src/main/java/com/futo/platformplayer/api/media/PlatformMultiClientPool.kt +++ b/app/src/main/java/com/futo/platformplayer/api/media/PlatformMultiClientPool.kt @@ -7,13 +7,15 @@ class PlatformMultiClientPool { private var _isFake = false; private var _privatePool = false; + private val _isolatedInitialization: Boolean - constructor(name: String, maxCap: Int = -1, isPrivatePool: Boolean = false) { + constructor(name: String, maxCap: Int = -1, isPrivatePool: Boolean = false, isolatedInitialization: Boolean = false) { _name = name; _maxCap = if(maxCap > 0) maxCap else 99; _privatePool = isPrivatePool; + _isolatedInitialization = isolatedInitialization } fun getClientPooled(parentClient: IPlatformClient, capacity: Int = _maxCap): IPlatformClient { @@ -21,7 +23,7 @@ class PlatformMultiClientPool { return parentClient; val pool = synchronized(_clientPools) { if(!_clientPools.containsKey(parentClient)) - _clientPools[parentClient] = PlatformClientPool(parentClient, _name, _privatePool).apply { + _clientPools[parentClient] = PlatformClientPool(parentClient, _name, _privatePool, _isolatedInitialization).apply { this.onDead.subscribe { _, pool -> synchronized(_clientPools) { if(_clientPools[parentClient] == pool) diff --git a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/DevJSClient.kt b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/DevJSClient.kt index 1d726dd5..b26abe45 100644 --- a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/DevJSClient.kt +++ b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/DevJSClient.kt @@ -54,8 +54,11 @@ class DevJSClient : JSClient { return DevJSClient(context, config, _devScript, _auth, _captcha, devID, descriptor.settings); } - override fun getCopy(privateCopy: Boolean): JSClient { - return DevJSClient(_context, descriptor, _script, if(!privateCopy) _auth else null, _captcha, saveState(), devID); + override fun getCopy(privateCopy: Boolean, noSaveState: Boolean): JSClient { + val client = DevJSClient(_context, descriptor, _script, if(!privateCopy) _auth else null, _captcha, if (noSaveState) null else saveState(), devID); + if (noSaveState) + client.initialize() + return client } override fun initialize() { diff --git a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/JSClient.kt b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/JSClient.kt index 371d846b..476bad8a 100644 --- a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/JSClient.kt +++ b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/JSClient.kt @@ -195,8 +195,11 @@ open class JSClient : IPlatformClient { _plugin.changeAllowDevSubmit(descriptor.appSettings.allowDeveloperSubmit); } - open fun getCopy(withoutCredentials: Boolean = false): JSClient { - return JSClient(_context, descriptor, saveState(), _script, withoutCredentials); + open fun getCopy(withoutCredentials: Boolean = false, noSaveState: Boolean = false): JSClient { + val client = JSClient(_context, descriptor, if (noSaveState) null else saveState(), _script, withoutCredentials); + if (noSaveState) + client.initialize() + return client } fun getUnderlyingPlugin(): V8Plugin { @@ -211,6 +214,8 @@ open class JSClient : IPlatformClient { } override fun initialize() { + if (_initialized) return + Logger.i(TAG, "Plugin [${config.name}] initializing"); plugin.start(); plugin.execute("plugin.config = ${Json.encodeToString(config)}"); diff --git a/app/src/main/java/com/futo/platformplayer/states/StatePlatform.kt b/app/src/main/java/com/futo/platformplayer/states/StatePlatform.kt index be364967..2f33538d 100644 --- a/app/src/main/java/com/futo/platformplayer/states/StatePlatform.kt +++ b/app/src/main/java/com/futo/platformplayer/states/StatePlatform.kt @@ -94,6 +94,7 @@ class StatePlatform { private val _trackerClientPool = PlatformMultiClientPool("Trackers", 1); //Used exclusively for playback trackers private val _liveEventClientPool = PlatformMultiClientPool("LiveEvents", 1); //Used exclusively for live events private val _privateClientPool = PlatformMultiClientPool("Private", 2, true); //Used primarily for calls if in incognito mode + private val _instantClientPool = PlatformMultiClientPool("Instant", 1, false, true); //Used for all instant calls private val _icons : HashMap = HashMap(); @@ -114,14 +115,14 @@ class StatePlatform { Logger.i(StatePlatform::class.java.name, "Fetching video details [${url}]"); if(!StateApp.instance.privateMode) { - _enabledClients.find { it.isContentDetailsUrl(url) }?.let { + _enabledClients.find { _instantClientPool.getClientPooled(it).isContentDetailsUrl(url) }?.let { _mainClientPool.getClientPooled(it).getContentDetails(url) } ?: throw NoPlatformClientException("No client enabled that supports this url ($url)"); } else { Logger.i(TAG, "Fetching details with private client"); - _enabledClients.find { it.isContentDetailsUrl(url) }?.let { + _enabledClients.find { _instantClientPool.getClientPooled(it).isContentDetailsUrl(url) }?.let { _privateClientPool.getClientPooled(it).getContentDetails(url) } ?: throw NoPlatformClientException("No client enabled that supports this url ($url)"); @@ -668,10 +669,10 @@ class StatePlatform { //Video - fun hasEnabledVideoClient(url: String) : Boolean = getEnabledClients().any { it.isContentDetailsUrl(url) }; + fun hasEnabledVideoClient(url: String) : Boolean = getEnabledClients().any { _instantClientPool.getClientPooled(it).isContentDetailsUrl(url) }; fun getContentClient(url: String) : IPlatformClient = getContentClientOrNull(url) ?: throw NoPlatformClientException("No client enabled that supports this content url (${url})"); - fun getContentClientOrNull(url: String) : IPlatformClient? = getEnabledClients().find { it.isContentDetailsUrl(url) }; + fun getContentClientOrNull(url: String) : IPlatformClient? = getEnabledClients().find { _instantClientPool.getClientPooled(it).isContentDetailsUrl(url) }; fun getContentDetails(url: String, forceRefetch: Boolean = false): Deferred { Logger.i(TAG, "Platform - getContentDetails (${url})"); if(forceRefetch) @@ -712,14 +713,14 @@ class StatePlatform { return client.getContentRecommendations(url); } - fun hasEnabledChannelClient(url : String) : Boolean = getEnabledClients().any { it.isChannelUrl(url) }; + fun hasEnabledChannelClient(url : String) : Boolean = getEnabledClients().any { _instantClientPool.getClientPooled(it).isChannelUrl(url) }; fun getChannelClient(url : String, exclude: List? = null) : IPlatformClient = getChannelClientOrNull(url, exclude) ?: throw NoPlatformClientException("No client enabled that supports this channel url (${url})"); fun getChannelClientOrNull(url : String, exclude: List? = null) : IPlatformClient? = if(exclude == null) - getEnabledClients().find { it.isChannelUrl(url) } + getEnabledClients().find { _instantClientPool.getClientPooled(it).isChannelUrl(url) } else - getEnabledClients().find { !exclude.contains(it.id) && it.isChannelUrl(url) }; + getEnabledClients().find { !exclude.contains(it.id) && _instantClientPool.getClientPooled(it).isChannelUrl(url) }; fun getChannel(url: String, updateSubscriptions: Boolean = true): Deferred { Logger.i(TAG, "Platform - getChannel"); @@ -906,9 +907,9 @@ class StatePlatform { return urls; } - fun hasEnabledPlaylistClient(url: String) : Boolean = getEnabledClients().any { it.isPlaylistUrl(url) }; - fun getPlaylistClientOrNull(url: String): IPlatformClient? = getEnabledClients().find { it.isPlaylistUrl(url) } - fun getPlaylistClient(url: String): IPlatformClient = getEnabledClients().find { it.isPlaylistUrl(url) } + fun hasEnabledPlaylistClient(url: String) : Boolean = getEnabledClients().any { _instantClientPool.getClientPooled(it).isPlaylistUrl(url) }; + fun getPlaylistClientOrNull(url: String): IPlatformClient? = getEnabledClients().find { _instantClientPool.getClientPooled(it).isPlaylistUrl(url) } + fun getPlaylistClient(url: String): IPlatformClient = getEnabledClients().find { _instantClientPool.getClientPooled(it).isPlaylistUrl(url) } ?: throw NoPlatformClientException("No client enabled that supports this playlist url (${url})"); fun getPlaylist(url: String): IPlatformPlaylistDetails { return getPlaylistClient(url).getPlaylist(url);