Merge branch 'master' of gitlab.futo.org:videostreaming/grayjay

This commit is contained in:
Koen 2024-01-10 13:07:33 +01:00
commit 48b2c68e72
5 changed files with 54 additions and 8 deletions

View file

@ -5,8 +5,11 @@ import com.caoccao.javet.annotations.V8Function
import com.caoccao.javet.annotations.V8Property
import com.caoccao.javet.enums.V8ConversionMode
import com.caoccao.javet.enums.V8ProxyMode
import com.caoccao.javet.values.reference.V8ValueObject
import com.futo.platformplayer.engine.V8Plugin
import com.futo.platformplayer.engine.internal.V8BindObject
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import org.jsoup.Jsoup
import org.jsoup.nodes.Element
@ -65,7 +68,7 @@ class PackageDOMParser : V8Package {
return result;
}
@V8Property
fun attributes(): Map<String, String> = _element.attributes().dataset();
fun attributes(): Map<String, String> = _element.attributes().associate { Pair(it.key, it.value) }
@V8Property
fun innerHTML(): String = _element.html();
@V8Property
@ -138,10 +141,32 @@ class PackageDOMParser : V8Package {
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 {
fun parse(parser: PackageDOMParser, str: String): DOMNode {
return DOMNode(parser, Jsoup.parse(str));
}
}
@Serializable
class SerializedNode(
val children: List<SerializedNode>,
val name: String,
val value: String,
val attributes: Map<String, String>
);
}
}

View file

@ -27,6 +27,7 @@ import com.futo.platformplayer.constructs.Event2
import com.futo.platformplayer.constructs.TaskHandler
import com.futo.platformplayer.engine.exceptions.PluginException
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.PolycentricProfile
import com.futo.platformplayer.logging.Logger
@ -336,8 +337,11 @@ class ChannelContentsFragment : Fragment(), IChannelTabFragment {
context?.let {
lifecycleScope.launch(Dispatchers.Main) {
try {
val channel = if(kv.value is ChannelException) (kv.value as ChannelException).channelNameOrUrl else 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
UIDialogs.toast(it, kv.value.message ?: "", false);
} catch (e: Throwable) {

View file

@ -31,6 +31,7 @@ import com.futo.platformplayer.stores.FragmentedStorage
import com.futo.platformplayer.stores.FragmentedStorageFileJson
import com.futo.platformplayer.views.FeedStyle
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.InsertedViewAdapterWithLoader
import com.futo.platformplayer.views.adapters.InsertedViewHolder
@ -44,6 +45,7 @@ import kotlinx.coroutines.withContext
import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import java.nio.channels.Channel
import java.time.OffsetDateTime
import kotlin.system.measureTimeMillis
@ -440,14 +442,17 @@ class SubscriptionsFeedFragment : MainFragment() {
}
Logger.e(TAG, "Channel [${channel}] failed", ex);
if (toShow is PluginException)
UIDialogs.appToast(
context.getString(R.string.plugin_pluginname_failed_message).replace("{pluginName}", toShow.config.name).replace("{message}", toShow.message ?: "")
UIDialogs.appToast(ToastView.Toast(
toShow.message +
(if(channel != null) "\nChannel: " + channel else ""), false, null,
"Plugin ${toShow.config.name} failed")
);
else
UIDialogs.appToast(ex.message ?: "");
}
}
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) }
.map { if(it is ChannelException) (it.cause as PluginException) else if(it is PluginException) it else null }
.filter { it != null }
@ -456,6 +461,9 @@ class SubscriptionsFeedFragment : MainFragment() {
.toList();
for(distinctPluginFail in failedPlugins)
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) {
Logger.e(TAG, "Failed to handle exceptions", e)

View file

@ -16,6 +16,7 @@ import com.futo.platformplayer.exceptions.ReconstructionException
import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.models.Playlist
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.ReconstructStore
import kotlinx.serialization.encodeToString
@ -35,6 +36,8 @@ class StatePlaylists {
= SerializedPlatformVideo.fromVideo(StatePlatform.instance.getContentDetails(backup).await() as IPlatformVideoDetails);
})
.load();
private val _watchlistOrderStore = FragmentedStorage.get<StringArrayStorage>("watchListOrder"); //Temporary workaround to add order..
val playlistStore = FragmentedStorage.storeJson<Playlist>("playlists")
.withRestore(PlaylistBackup())
.load();
@ -48,26 +51,32 @@ class StatePlaylists {
}
fun getWatchLater() : List<SerializedPlatformVideo> {
synchronized(_watchlistStore) {
return _watchlistStore.getItems();
val order = _watchlistOrderStore.getAllValues();
return _watchlistStore.getItems().sortedBy { order.indexOf(it.url) };
}
}
fun updateWatchLater(updated: List<SerializedPlatformVideo>) {
synchronized(_watchlistStore) {
_watchlistStore.deleteAll();
_watchlistStore.saveAllAsync(updated);
_watchlistOrderStore.set(*updated.map { it.url }.toTypedArray());
_watchlistOrderStore.save();
}
onWatchLaterChanged.emit();
}
fun removeFromWatchLater(video: SerializedPlatformVideo) {
synchronized(_watchlistStore) {
_watchlistStore.delete(video);
_watchlistOrderStore.set(*_watchlistOrderStore.values.filter { it != video.url }.toTypedArray());
_watchlistOrderStore.save();
}
onWatchLaterChanged.emit();
}
fun addToWatchLater(video: SerializedPlatformVideo) {
synchronized(_watchlistStore) {
_watchlistStore.saveAsync(video);
_watchlistOrderStore.set(*(listOf(video.url) + _watchlistOrderStore.values) .toTypedArray());
_watchlistOrderStore.save();
}
onWatchLaterChanged.emit();
}

View file

@ -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.ScriptCaptchaRequiredException
import com.futo.platformplayer.engine.exceptions.ScriptCriticalException
import com.futo.platformplayer.engine.exceptions.ScriptException
import com.futo.platformplayer.exceptions.ChannelException
import com.futo.platformplayer.findNonRuntimeException
import com.futo.platformplayer.fragment.mainactivity.main.SubscriptionsFeedFragment
@ -69,7 +70,6 @@ abstract class SubscriptionsTaskFetchAlgorithm(
val cachedChannels = mutableListOf<String>()
val forkTasks = executeSubscriptionTasks(tasks, failedPlugins, cachedChannels);
val taskResults = arrayListOf<SubscriptionTaskResult>();
val timeTotal = measureTimeMillis {
for(task in forkTasks) {
@ -200,7 +200,7 @@ abstract class SubscriptionsTaskFetchAlgorithm(
else {
Logger.i(StateSubscriptions.TAG, "Channel ${task.sub.channel.name} failed, substituting with cache");
pager = StateCache.instance.getChannelCachePager(task.sub.channel.url);
taskEx = ex;
taskEx = channelEx;
return@submit SubscriptionTaskResult(task, pager, taskEx);
}
}