mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2025-08-03 14:50:49 +00:00
DOMParser toNodeTree, Better subscription errors, Watch later ordering
This commit is contained in:
parent
f8402676d7
commit
195163840b
5 changed files with 54 additions and 8 deletions
|
@ -5,8 +5,11 @@ import com.caoccao.javet.annotations.V8Function
|
||||||
import com.caoccao.javet.annotations.V8Property
|
import com.caoccao.javet.annotations.V8Property
|
||||||
import com.caoccao.javet.enums.V8ConversionMode
|
import com.caoccao.javet.enums.V8ConversionMode
|
||||||
import com.caoccao.javet.enums.V8ProxyMode
|
import com.caoccao.javet.enums.V8ProxyMode
|
||||||
|
import com.caoccao.javet.values.reference.V8ValueObject
|
||||||
import com.futo.platformplayer.engine.V8Plugin
|
import com.futo.platformplayer.engine.V8Plugin
|
||||||
import com.futo.platformplayer.engine.internal.V8BindObject
|
import com.futo.platformplayer.engine.internal.V8BindObject
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
import org.jsoup.Jsoup
|
import org.jsoup.Jsoup
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
|
|
||||||
|
@ -65,7 +68,7 @@ class PackageDOMParser : V8Package {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@V8Property
|
@V8Property
|
||||||
fun attributes(): Map<String, String> = _element.attributes().dataset();
|
fun attributes(): Map<String, String> = _element.attributes().associate { Pair(it.key, it.value) }
|
||||||
@V8Property
|
@V8Property
|
||||||
fun innerHTML(): String = _element.html();
|
fun innerHTML(): String = _element.html();
|
||||||
@V8Property
|
@V8Property
|
||||||
|
@ -138,10 +141,32 @@ class PackageDOMParser : V8Package {
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@V8Function
|
||||||
|
fun toNodeTree(): SerializedNode {
|
||||||
|
return SerializedNode(
|
||||||
|
childNodes().map { it.toNodeTree() },
|
||||||
|
_element.tagName(),
|
||||||
|
_element.text(),
|
||||||
|
attributes()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@V8Function
|
||||||
|
fun toNodeTreeJson(): String {
|
||||||
|
return Json.encodeToString(SerializedNode.serializer(), toNodeTree());
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun parse(parser: PackageDOMParser, str: String): DOMNode {
|
fun parse(parser: PackageDOMParser, str: String): DOMNode {
|
||||||
return DOMNode(parser, Jsoup.parse(str));
|
return DOMNode(parser, Jsoup.parse(str));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
class SerializedNode(
|
||||||
|
val children: List<SerializedNode>,
|
||||||
|
val name: String,
|
||||||
|
val value: String,
|
||||||
|
val attributes: Map<String, String>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -27,6 +27,7 @@ import com.futo.platformplayer.constructs.Event2
|
||||||
import com.futo.platformplayer.constructs.TaskHandler
|
import com.futo.platformplayer.constructs.TaskHandler
|
||||||
import com.futo.platformplayer.engine.exceptions.PluginException
|
import com.futo.platformplayer.engine.exceptions.PluginException
|
||||||
import com.futo.platformplayer.engine.exceptions.ScriptCaptchaRequiredException
|
import com.futo.platformplayer.engine.exceptions.ScriptCaptchaRequiredException
|
||||||
|
import com.futo.platformplayer.exceptions.ChannelException
|
||||||
import com.futo.platformplayer.fragment.mainactivity.main.FeedView
|
import com.futo.platformplayer.fragment.mainactivity.main.FeedView
|
||||||
import com.futo.platformplayer.fragment.mainactivity.main.PolycentricProfile
|
import com.futo.platformplayer.fragment.mainactivity.main.PolycentricProfile
|
||||||
import com.futo.platformplayer.logging.Logger
|
import com.futo.platformplayer.logging.Logger
|
||||||
|
@ -336,8 +337,11 @@ class ChannelContentsFragment : Fragment(), IChannelTabFragment {
|
||||||
context?.let {
|
context?.let {
|
||||||
lifecycleScope.launch(Dispatchers.Main) {
|
lifecycleScope.launch(Dispatchers.Main) {
|
||||||
try {
|
try {
|
||||||
|
val channel = if(kv.value is ChannelException) (kv.value as ChannelException).channelNameOrUrl else null;
|
||||||
if(jsVideoPager != null)
|
if(jsVideoPager != null)
|
||||||
UIDialogs.toast(it, "Plugin ${jsVideoPager.getPluginConfig().name} failed:\n${kv.value.message}", false);
|
UIDialogs.toast(it, "Plugin ${jsVideoPager.getPluginConfig().name} failed:\n" +
|
||||||
|
(if(!channel.isNullOrEmpty()) "(${channel}) " else "") +
|
||||||
|
"${kv.value.message}", false);
|
||||||
else
|
else
|
||||||
UIDialogs.toast(it, kv.value.message ?: "", false);
|
UIDialogs.toast(it, kv.value.message ?: "", false);
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
|
|
|
@ -31,6 +31,7 @@ import com.futo.platformplayer.stores.FragmentedStorage
|
||||||
import com.futo.platformplayer.stores.FragmentedStorageFileJson
|
import com.futo.platformplayer.stores.FragmentedStorageFileJson
|
||||||
import com.futo.platformplayer.views.FeedStyle
|
import com.futo.platformplayer.views.FeedStyle
|
||||||
import com.futo.platformplayer.views.NoResultsView
|
import com.futo.platformplayer.views.NoResultsView
|
||||||
|
import com.futo.platformplayer.views.ToastView
|
||||||
import com.futo.platformplayer.views.adapters.ContentPreviewViewHolder
|
import com.futo.platformplayer.views.adapters.ContentPreviewViewHolder
|
||||||
import com.futo.platformplayer.views.adapters.InsertedViewAdapterWithLoader
|
import com.futo.platformplayer.views.adapters.InsertedViewAdapterWithLoader
|
||||||
import com.futo.platformplayer.views.adapters.InsertedViewHolder
|
import com.futo.platformplayer.views.adapters.InsertedViewHolder
|
||||||
|
@ -44,6 +45,7 @@ import kotlinx.coroutines.withContext
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
|
import java.nio.channels.Channel
|
||||||
import java.time.OffsetDateTime
|
import java.time.OffsetDateTime
|
||||||
import kotlin.system.measureTimeMillis
|
import kotlin.system.measureTimeMillis
|
||||||
|
|
||||||
|
@ -440,14 +442,17 @@ class SubscriptionsFeedFragment : MainFragment() {
|
||||||
}
|
}
|
||||||
Logger.e(TAG, "Channel [${channel}] failed", ex);
|
Logger.e(TAG, "Channel [${channel}] failed", ex);
|
||||||
if (toShow is PluginException)
|
if (toShow is PluginException)
|
||||||
UIDialogs.appToast(
|
UIDialogs.appToast(ToastView.Toast(
|
||||||
context.getString(R.string.plugin_pluginname_failed_message).replace("{pluginName}", toShow.config.name).replace("{message}", toShow.message ?: "")
|
toShow.message +
|
||||||
|
(if(channel != null) "\nChannel: " + channel else ""), false, null,
|
||||||
|
"Plugin ${toShow.config.name} failed")
|
||||||
);
|
);
|
||||||
else
|
else
|
||||||
UIDialogs.appToast(ex.message ?: "");
|
UIDialogs.appToast(ex.message ?: "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
val failedChannels = exs.filterIsInstance<ChannelException>().map { it.channelNameOrUrl }.distinct().toList();
|
||||||
val failedPlugins = exs.filter { it is PluginException || (it is ChannelException && it.cause is PluginException) }
|
val failedPlugins = exs.filter { it is PluginException || (it is ChannelException && it.cause is PluginException) }
|
||||||
.map { if(it is ChannelException) (it.cause as PluginException) else if(it is PluginException) it else null }
|
.map { if(it is ChannelException) (it.cause as PluginException) else if(it is PluginException) it else null }
|
||||||
.filter { it != null }
|
.filter { it != null }
|
||||||
|
@ -456,6 +461,9 @@ class SubscriptionsFeedFragment : MainFragment() {
|
||||||
.toList();
|
.toList();
|
||||||
for(distinctPluginFail in failedPlugins)
|
for(distinctPluginFail in failedPlugins)
|
||||||
UIDialogs.appToast(context.getString(R.string.plugin_pluginname_failed_message).replace("{pluginName}", distinctPluginFail.config.name).replace("{message}", distinctPluginFail.message ?: ""));
|
UIDialogs.appToast(context.getString(R.string.plugin_pluginname_failed_message).replace("{pluginName}", distinctPluginFail.config.name).replace("{message}", distinctPluginFail.message ?: ""));
|
||||||
|
if(failedChannels.isNotEmpty())
|
||||||
|
UIDialogs.appToast(ToastView.Toast(failedChannels.take(3).map { "- ${it}" }.joinToString("\n") +
|
||||||
|
(if(failedChannels.size >= 3) "\nAnd ${failedChannels.size - 3} more" else ""), false, null, "Failed Channels"));
|
||||||
}
|
}
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
Logger.e(TAG, "Failed to handle exceptions", e)
|
Logger.e(TAG, "Failed to handle exceptions", e)
|
||||||
|
|
|
@ -16,6 +16,7 @@ import com.futo.platformplayer.exceptions.ReconstructionException
|
||||||
import com.futo.platformplayer.logging.Logger
|
import com.futo.platformplayer.logging.Logger
|
||||||
import com.futo.platformplayer.models.Playlist
|
import com.futo.platformplayer.models.Playlist
|
||||||
import com.futo.platformplayer.stores.FragmentedStorage
|
import com.futo.platformplayer.stores.FragmentedStorage
|
||||||
|
import com.futo.platformplayer.stores.StringArrayStorage
|
||||||
import com.futo.platformplayer.stores.v2.ManagedStore
|
import com.futo.platformplayer.stores.v2.ManagedStore
|
||||||
import com.futo.platformplayer.stores.v2.ReconstructStore
|
import com.futo.platformplayer.stores.v2.ReconstructStore
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
|
@ -35,6 +36,8 @@ class StatePlaylists {
|
||||||
= SerializedPlatformVideo.fromVideo(StatePlatform.instance.getContentDetails(backup).await() as IPlatformVideoDetails);
|
= SerializedPlatformVideo.fromVideo(StatePlatform.instance.getContentDetails(backup).await() as IPlatformVideoDetails);
|
||||||
})
|
})
|
||||||
.load();
|
.load();
|
||||||
|
private val _watchlistOrderStore = FragmentedStorage.get<StringArrayStorage>("watchListOrder"); //Temporary workaround to add order..
|
||||||
|
|
||||||
val playlistStore = FragmentedStorage.storeJson<Playlist>("playlists")
|
val playlistStore = FragmentedStorage.storeJson<Playlist>("playlists")
|
||||||
.withRestore(PlaylistBackup())
|
.withRestore(PlaylistBackup())
|
||||||
.load();
|
.load();
|
||||||
|
@ -48,26 +51,32 @@ class StatePlaylists {
|
||||||
}
|
}
|
||||||
fun getWatchLater() : List<SerializedPlatformVideo> {
|
fun getWatchLater() : List<SerializedPlatformVideo> {
|
||||||
synchronized(_watchlistStore) {
|
synchronized(_watchlistStore) {
|
||||||
return _watchlistStore.getItems();
|
val order = _watchlistOrderStore.getAllValues();
|
||||||
|
return _watchlistStore.getItems().sortedBy { order.indexOf(it.url) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fun updateWatchLater(updated: List<SerializedPlatformVideo>) {
|
fun updateWatchLater(updated: List<SerializedPlatformVideo>) {
|
||||||
synchronized(_watchlistStore) {
|
synchronized(_watchlistStore) {
|
||||||
_watchlistStore.deleteAll();
|
_watchlistStore.deleteAll();
|
||||||
_watchlistStore.saveAllAsync(updated);
|
_watchlistStore.saveAllAsync(updated);
|
||||||
|
_watchlistOrderStore.set(*updated.map { it.url }.toTypedArray());
|
||||||
|
_watchlistOrderStore.save();
|
||||||
}
|
}
|
||||||
onWatchLaterChanged.emit();
|
onWatchLaterChanged.emit();
|
||||||
}
|
}
|
||||||
fun removeFromWatchLater(video: SerializedPlatformVideo) {
|
fun removeFromWatchLater(video: SerializedPlatformVideo) {
|
||||||
synchronized(_watchlistStore) {
|
synchronized(_watchlistStore) {
|
||||||
_watchlistStore.delete(video);
|
_watchlistStore.delete(video);
|
||||||
|
_watchlistOrderStore.set(*_watchlistOrderStore.values.filter { it != video.url }.toTypedArray());
|
||||||
|
_watchlistOrderStore.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
onWatchLaterChanged.emit();
|
onWatchLaterChanged.emit();
|
||||||
}
|
}
|
||||||
fun addToWatchLater(video: SerializedPlatformVideo) {
|
fun addToWatchLater(video: SerializedPlatformVideo) {
|
||||||
synchronized(_watchlistStore) {
|
synchronized(_watchlistStore) {
|
||||||
_watchlistStore.saveAsync(video);
|
_watchlistStore.saveAsync(video);
|
||||||
|
_watchlistOrderStore.set(*(listOf(video.url) + _watchlistOrderStore.values) .toTypedArray());
|
||||||
|
_watchlistOrderStore.save();
|
||||||
}
|
}
|
||||||
onWatchLaterChanged.emit();
|
onWatchLaterChanged.emit();
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import com.futo.platformplayer.api.media.structures.MultiChronoContentPager
|
||||||
import com.futo.platformplayer.engine.exceptions.PluginException
|
import com.futo.platformplayer.engine.exceptions.PluginException
|
||||||
import com.futo.platformplayer.engine.exceptions.ScriptCaptchaRequiredException
|
import com.futo.platformplayer.engine.exceptions.ScriptCaptchaRequiredException
|
||||||
import com.futo.platformplayer.engine.exceptions.ScriptCriticalException
|
import com.futo.platformplayer.engine.exceptions.ScriptCriticalException
|
||||||
|
import com.futo.platformplayer.engine.exceptions.ScriptException
|
||||||
import com.futo.platformplayer.exceptions.ChannelException
|
import com.futo.platformplayer.exceptions.ChannelException
|
||||||
import com.futo.platformplayer.findNonRuntimeException
|
import com.futo.platformplayer.findNonRuntimeException
|
||||||
import com.futo.platformplayer.fragment.mainactivity.main.SubscriptionsFeedFragment
|
import com.futo.platformplayer.fragment.mainactivity.main.SubscriptionsFeedFragment
|
||||||
|
@ -69,7 +70,6 @@ abstract class SubscriptionsTaskFetchAlgorithm(
|
||||||
val cachedChannels = mutableListOf<String>()
|
val cachedChannels = mutableListOf<String>()
|
||||||
val forkTasks = executeSubscriptionTasks(tasks, failedPlugins, cachedChannels);
|
val forkTasks = executeSubscriptionTasks(tasks, failedPlugins, cachedChannels);
|
||||||
|
|
||||||
|
|
||||||
val taskResults = arrayListOf<SubscriptionTaskResult>();
|
val taskResults = arrayListOf<SubscriptionTaskResult>();
|
||||||
val timeTotal = measureTimeMillis {
|
val timeTotal = measureTimeMillis {
|
||||||
for(task in forkTasks) {
|
for(task in forkTasks) {
|
||||||
|
@ -200,7 +200,7 @@ abstract class SubscriptionsTaskFetchAlgorithm(
|
||||||
else {
|
else {
|
||||||
Logger.i(StateSubscriptions.TAG, "Channel ${task.sub.channel.name} failed, substituting with cache");
|
Logger.i(StateSubscriptions.TAG, "Channel ${task.sub.channel.name} failed, substituting with cache");
|
||||||
pager = StateCache.instance.getChannelCachePager(task.sub.channel.url);
|
pager = StateCache.instance.getChannelCachePager(task.sub.channel.url);
|
||||||
taskEx = ex;
|
taskEx = channelEx;
|
||||||
return@submit SubscriptionTaskResult(task, pager, taskEx);
|
return@submit SubscriptionTaskResult(task, pager, taskEx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue