From cbf27126543f6aa47897d975c72d9bb769631d1e Mon Sep 17 00:00:00 2001 From: Kelvin Date: Mon, 4 Dec 2023 20:06:24 +0100 Subject: [PATCH] ManagedDBSTore delete corrupted items, Fix serialized content serializer, Fix notifications wrong intent --- .../models/video/SerializedPlatformContent.kt | 4 ++++ .../video/SerializedPlatformLockedContent.kt | 2 +- .../video/SerializedPlatformNestedContent.kt | 2 +- .../models/video/SerializedPlatformPost.kt | 3 ++- .../models/video/SerializedPlatformVideo.kt | 2 +- .../background/BackgroundWorker.kt | 2 +- .../engine/packages/PackageHttp.kt | 5 ++++- .../serializers/PlatformContentSerializer.kt | 5 +++-- .../futo/platformplayer/states/StateApp.kt | 6 ++++++ .../futo/platformplayer/states/StateCache.kt | 13 +++++++++++- .../states/StateNotifications.kt | 2 +- .../platformplayer/states/StatePlatform.kt | 3 +++ .../states/StateSubscriptions.kt | 5 ++++- .../stores/db/ManagedDBIndex.kt | 5 +++++ .../stores/db/ManagedDBStore.kt | 21 ++++++++++++++----- 15 files changed, 64 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/futo/platformplayer/api/media/models/video/SerializedPlatformContent.kt b/app/src/main/java/com/futo/platformplayer/api/media/models/video/SerializedPlatformContent.kt index b207f427..92e4a4fc 100644 --- a/app/src/main/java/com/futo/platformplayer/api/media/models/video/SerializedPlatformContent.kt +++ b/app/src/main/java/com/futo/platformplayer/api/media/models/video/SerializedPlatformContent.kt @@ -6,9 +6,13 @@ import com.futo.platformplayer.api.media.models.locked.IPlatformLockedContent import com.futo.platformplayer.api.media.models.nested.IPlatformNestedContent import com.futo.platformplayer.api.media.models.post.IPlatformPost import com.futo.platformplayer.serializers.PlatformContentSerializer +import kotlinx.serialization.EncodeDefault +import kotlinx.serialization.SerialName @kotlinx.serialization.Serializable(with = PlatformContentSerializer::class) interface SerializedPlatformContent: IPlatformContent { + override val contentType: ContentType; + fun toJson() : String; fun fromJson(str : String) : SerializedPlatformContent; fun fromJsonArray(str : String) : Array; diff --git a/app/src/main/java/com/futo/platformplayer/api/media/models/video/SerializedPlatformLockedContent.kt b/app/src/main/java/com/futo/platformplayer/api/media/models/video/SerializedPlatformLockedContent.kt index dfe8771d..f0d815ba 100644 --- a/app/src/main/java/com/futo/platformplayer/api/media/models/video/SerializedPlatformLockedContent.kt +++ b/app/src/main/java/com/futo/platformplayer/api/media/models/video/SerializedPlatformLockedContent.kt @@ -30,7 +30,7 @@ open class SerializedPlatformLockedContent( override val unlockUrl: String? = null, override val contentThumbnails: Thumbnails ) : IPlatformLockedContent, SerializedPlatformContent { - final override val contentType: ContentType get() = ContentType.LOCKED; + override val contentType: ContentType = ContentType.LOCKED; override fun toJson() : String { return Json.encodeToString(this); diff --git a/app/src/main/java/com/futo/platformplayer/api/media/models/video/SerializedPlatformNestedContent.kt b/app/src/main/java/com/futo/platformplayer/api/media/models/video/SerializedPlatformNestedContent.kt index 5c2ad3f4..079bb91e 100644 --- a/app/src/main/java/com/futo/platformplayer/api/media/models/video/SerializedPlatformNestedContent.kt +++ b/app/src/main/java/com/futo/platformplayer/api/media/models/video/SerializedPlatformNestedContent.kt @@ -30,7 +30,7 @@ open class SerializedPlatformNestedContent( override val contentProvider: String?, override val contentThumbnails: Thumbnails ) : IPlatformNestedContent, SerializedPlatformContent { - final override val contentType: ContentType get() = ContentType.NESTED_VIDEO; + final override val contentType: ContentType = ContentType.NESTED_VIDEO; override val contentPlugin: String? = StatePlatform.instance.getContentClientOrNull(contentUrl)?.id; override val contentSupported: Boolean get() = contentPlugin != null; diff --git a/app/src/main/java/com/futo/platformplayer/api/media/models/video/SerializedPlatformPost.kt b/app/src/main/java/com/futo/platformplayer/api/media/models/video/SerializedPlatformPost.kt index 8100fea7..a9d5aceb 100644 --- a/app/src/main/java/com/futo/platformplayer/api/media/models/video/SerializedPlatformPost.kt +++ b/app/src/main/java/com/futo/platformplayer/api/media/models/video/SerializedPlatformPost.kt @@ -8,6 +8,7 @@ import com.futo.platformplayer.api.media.models.contents.ContentType import com.futo.platformplayer.api.media.models.post.IPlatformPost import com.futo.platformplayer.serializers.OffsetDateTimeNullableSerializer import com.futo.polycentric.core.combineHashCodes +import kotlinx.serialization.EncodeDefault import kotlinx.serialization.decodeFromString import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json @@ -26,7 +27,7 @@ open class SerializedPlatformPost( override val thumbnails: List, override val images: List ) : IPlatformPost, SerializedPlatformContent { - final override val contentType: ContentType get() = ContentType.POST; + override val contentType: ContentType = ContentType.POST; override fun toJson() : String { return Json.encodeToString(this); diff --git a/app/src/main/java/com/futo/platformplayer/api/media/models/video/SerializedPlatformVideo.kt b/app/src/main/java/com/futo/platformplayer/api/media/models/video/SerializedPlatformVideo.kt index 12dd9e78..ee49ebca 100644 --- a/app/src/main/java/com/futo/platformplayer/api/media/models/video/SerializedPlatformVideo.kt +++ b/app/src/main/java/com/futo/platformplayer/api/media/models/video/SerializedPlatformVideo.kt @@ -26,7 +26,7 @@ open class SerializedPlatformVideo( override val duration: Long, override val viewCount: Long, ) : IPlatformVideo, SerializedPlatformContent { - final override val contentType: ContentType get() = ContentType.MEDIA; + override val contentType: ContentType = ContentType.MEDIA; override val isLive: Boolean = false; diff --git a/app/src/main/java/com/futo/platformplayer/background/BackgroundWorker.kt b/app/src/main/java/com/futo/platformplayer/background/BackgroundWorker.kt index fbebe2b2..e0ed02b9 100644 --- a/app/src/main/java/com/futo/platformplayer/background/BackgroundWorker.kt +++ b/app/src/main/java/com/futo/platformplayer/background/BackgroundWorker.kt @@ -122,7 +122,7 @@ class BackgroundWorker(private val appContext: Context, private val workerParams //Only for testing notifications val testNotifs = 0; if(contentNotifs.size == 0 && testNotifs > 0) { - results.first.getResults().filter { it is IPlatformVideo && it.datetime?.let { it < now } == true } + results.first.getResults().filter { it is IPlatformVideo } .take(testNotifs).forEach { contentNotifs.add(Pair(StateSubscriptions.instance.getSubscriptions().first(), it)); } diff --git a/app/src/main/java/com/futo/platformplayer/engine/packages/PackageHttp.kt b/app/src/main/java/com/futo/platformplayer/engine/packages/PackageHttp.kt index e35edfa8..eadf68c6 100644 --- a/app/src/main/java/com/futo/platformplayer/engine/packages/PackageHttp.kt +++ b/app/src/main/java/com/futo/platformplayer/engine/packages/PackageHttp.kt @@ -18,6 +18,7 @@ import com.futo.platformplayer.engine.internal.V8BindObject import com.futo.platformplayer.getOrThrow import kotlinx.coroutines.CoroutineScope import java.net.SocketTimeoutException +import kotlin.streams.asSequence import kotlin.streams.toList class PackageHttp: V8Package { @@ -171,7 +172,9 @@ class PackageHttp: V8Package { return@map it.first.requestWithBody(it.second.method, it.second.url, it.second.body!!, it.second.headers); else return@map it.first.request(it.second.method, it.second.url, it.second.headers); - }.toList(); + } + .asSequence() + .toList(); } } diff --git a/app/src/main/java/com/futo/platformplayer/serializers/PlatformContentSerializer.kt b/app/src/main/java/com/futo/platformplayer/serializers/PlatformContentSerializer.kt index f7f839bf..c2766a59 100644 --- a/app/src/main/java/com/futo/platformplayer/serializers/PlatformContentSerializer.kt +++ b/app/src/main/java/com/futo/platformplayer/serializers/PlatformContentSerializer.kt @@ -3,6 +3,7 @@ package com.futo.platformplayer.serializers import com.futo.platformplayer.api.media.models.contents.ContentType import com.futo.platformplayer.api.media.models.video.SerializedPlatformContent import com.futo.platformplayer.api.media.models.video.SerializedPlatformNestedContent +import com.futo.platformplayer.api.media.models.video.SerializedPlatformPost import com.futo.platformplayer.api.media.models.video.SerializedPlatformVideo import kotlinx.serialization.DeserializationStrategy import kotlinx.serialization.json.* @@ -22,7 +23,7 @@ class PlatformContentSerializer() : JsonContentPolymorphicSerializer SerializedPlatformVideo.serializer(); "NESTED_VIDEO" -> SerializedPlatformNestedContent.serializer(); "ARTICLE" -> throw NotImplementedError("Articles not yet implemented"); - "POST" -> throw NotImplementedError("Post not yet implemented"); + "POST" -> SerializedPlatformPost.serializer(); else -> throw NotImplementedError("Unknown Content Type Value: ${obj?.jsonPrimitive?.contentOrNull}") }; else @@ -30,7 +31,7 @@ class PlatformContentSerializer() : JsonContentPolymorphicSerializer SerializedPlatformVideo.serializer(); ContentType.NESTED_VIDEO.value -> SerializedPlatformNestedContent.serializer(); ContentType.ARTICLE.value -> throw NotImplementedError("Articles not yet implemented"); - ContentType.POST.value -> throw NotImplementedError("Post not yet implemented"); + ContentType.POST.value -> SerializedPlatformPost.serializer(); else -> throw NotImplementedError("Unknown Content Type Value: ${obj?.jsonPrimitive?.int}") }; } diff --git a/app/src/main/java/com/futo/platformplayer/states/StateApp.kt b/app/src/main/java/com/futo/platformplayer/states/StateApp.kt index f08e1b4e..6554b4e9 100644 --- a/app/src/main/java/com/futo/platformplayer/states/StateApp.kt +++ b/app/src/main/java/com/futo/platformplayer/states/StateApp.kt @@ -13,6 +13,7 @@ import android.net.NetworkRequest import android.net.Uri import android.provider.DocumentsContract import android.util.DisplayMetrics +import android.util.Xml import androidx.documentfile.provider.DocumentFile import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.lifecycleScope @@ -22,6 +23,7 @@ import com.futo.platformplayer.R import com.futo.platformplayer.activities.CaptchaActivity import com.futo.platformplayer.activities.IWithResultLauncher import com.futo.platformplayer.activities.MainActivity +import com.futo.platformplayer.api.media.models.video.SerializedPlatformContent import com.futo.platformplayer.api.media.models.video.SerializedPlatformVideo import com.futo.platformplayer.api.media.platforms.js.DevJSClient import com.futo.platformplayer.api.media.platforms.js.JSClient @@ -37,9 +39,12 @@ import com.futo.platformplayer.logging.LogLevel import com.futo.platformplayer.logging.Logger import com.futo.platformplayer.models.HistoryVideo import com.futo.platformplayer.receivers.AudioNoisyReceiver +import com.futo.platformplayer.serializers.PlatformContentSerializer import com.futo.platformplayer.services.DownloadService import com.futo.platformplayer.stores.FragmentedStorage +import com.futo.platformplayer.stores.db.ManagedDBStore import com.futo.platformplayer.stores.db.types.DBHistory +import com.futo.platformplayer.stores.v2.JsonStoreSerializer import com.futo.platformplayer.stores.v2.ManagedStore import kotlinx.coroutines.* import kotlinx.serialization.decodeFromString @@ -548,6 +553,7 @@ class StateApp { } */ } + } fun mainAppStartedWithExternalFiles(context: Context) { diff --git a/app/src/main/java/com/futo/platformplayer/states/StateCache.kt b/app/src/main/java/com/futo/platformplayer/states/StateCache.kt index 957a958e..636eb922 100644 --- a/app/src/main/java/com/futo/platformplayer/states/StateCache.kt +++ b/app/src/main/java/com/futo/platformplayer/states/StateCache.kt @@ -1,5 +1,6 @@ package com.futo.platformplayer.states +import com.futo.platformplayer.api.media.models.contents.ContentType import com.futo.platformplayer.api.media.models.contents.IPlatformContent import com.futo.platformplayer.api.media.models.video.SerializedPlatformContent import com.futo.platformplayer.api.media.structures.DedupContentPager @@ -11,10 +12,15 @@ import com.futo.platformplayer.resolveChannelUrl import com.futo.platformplayer.serializers.PlatformContentSerializer import com.futo.platformplayer.stores.db.ManagedDBStore import com.futo.platformplayer.stores.db.types.DBSubscriptionCache +import com.futo.platformplayer.stores.v2.JsonStoreSerializer import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.Json import java.time.OffsetDateTime +import kotlin.streams.asSequence +import kotlin.streams.toList import kotlin.system.measureTimeMillis class StateCache { @@ -34,6 +40,8 @@ class StateCache { fun getChannelCachePager(channelUrl: String): IPager { return _subscriptionCache.queryPager(DBSubscriptionCache.Index::channelUrl, channelUrl, 20) { + if(it.objOrNull?.contentType == ContentType.POST) + Logger.i(TAG, "FOUND CACHED POST\n (${it.objOrNull?.name})"); it.obj; } } @@ -56,7 +64,10 @@ class StateCache { }.flatten().distinct(); Logger.i(TAG, "Subscriptions CachePager get pagers"); - val pagers = allUrls.parallelStream().map { getChannelCachePager(it) }.toList(); + val pagers = allUrls.parallelStream() + .map { getChannelCachePager(it) } + .asSequence() + .toList(); Logger.i(TAG, "Subscriptions CachePager compiling"); val pager = MultiChronoContentPager(pagers, false, 20); diff --git a/app/src/main/java/com/futo/platformplayer/states/StateNotifications.kt b/app/src/main/java/com/futo/platformplayer/states/StateNotifications.kt index 1ce15a20..b1fc2428 100644 --- a/app/src/main/java/com/futo/platformplayer/states/StateNotifications.kt +++ b/app/src/main/java/com/futo/platformplayer/states/StateNotifications.kt @@ -117,7 +117,7 @@ class StateNotifications { .setContentText("${content.name}") .setSubText(content.datetime?.toHumanNowDiffStringMinDay()) .setSilent(true) - .setContentIntent(PendingIntent.getActivity(context, 0, MainActivity.getVideoIntent(context, content.url), + .setContentIntent(PendingIntent.getActivity(context, content.hashCode(), MainActivity.getVideoIntent(context, content.url), PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)) .setChannelId(notificationChannel.id); if(thumbnail != null) { 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 e884573f..71e178fd 100644 --- a/app/src/main/java/com/futo/platformplayer/states/StatePlatform.kt +++ b/app/src/main/java/com/futo/platformplayer/states/StatePlatform.kt @@ -42,6 +42,7 @@ import kotlinx.coroutines.* import okhttp3.internal.concat import java.time.OffsetDateTime import kotlin.reflect.jvm.internal.impl.builtins.jvm.JavaToKotlinClassMap.PlatformMutabilityMapping +import kotlin.streams.asSequence import kotlin.streams.toList /*** @@ -389,6 +390,7 @@ class StatePlatform { } return@map homeResult; } + .asSequence() .toList() .associateWith { 1f }; @@ -709,6 +711,7 @@ class StatePlatform { } return@map results; } + .asSequence() .toList(); val pager = MultiChronoContentPager(pagers.toTypedArray()); diff --git a/app/src/main/java/com/futo/platformplayer/states/StateSubscriptions.kt b/app/src/main/java/com/futo/platformplayer/states/StateSubscriptions.kt index d892cdb6..351b3a60 100644 --- a/app/src/main/java/com/futo/platformplayer/states/StateSubscriptions.kt +++ b/app/src/main/java/com/futo/platformplayer/states/StateSubscriptions.kt @@ -38,6 +38,7 @@ import java.util.concurrent.ForkJoinTask import kotlin.collections.ArrayList import kotlin.coroutines.resumeWithException import kotlin.coroutines.suspendCoroutine +import kotlin.streams.asSequence import kotlin.streams.toList import kotlin.system.measureTimeMillis @@ -258,7 +259,9 @@ class StateSubscriptions { Pair(it, StatePolycentric.instance.getChannelUrls(it.channel.url, it.channel.id)); else Pair(it, listOf(it.channel.url)); - }.toList().associate { it }; + }.asSequence() + .toList() + .associate { it }; val result = algo.getSubscriptions(subUrls); return Pair(result.pager, result.exceptions); diff --git a/app/src/main/java/com/futo/platformplayer/stores/db/ManagedDBIndex.kt b/app/src/main/java/com/futo/platformplayer/stores/db/ManagedDBIndex.kt index 93562aca..c4cf5295 100644 --- a/app/src/main/java/com/futo/platformplayer/stores/db/ManagedDBIndex.kt +++ b/app/src/main/java/com/futo/platformplayer/stores/db/ManagedDBIndex.kt @@ -14,10 +14,15 @@ open class ManagedDBIndex { @Ignore private var _obj: T? = null; + @Ignore + var isCorrupted: Boolean = false; @get:Ignore val obj: T get() = _obj ?: throw IllegalStateException("Attempted to access serialized object on a index-only instance"); + @get:Ignore + val objOrNull: T? get() = _obj; + fun setInstance(obj: T) { this._obj = obj; } diff --git a/app/src/main/java/com/futo/platformplayer/stores/db/ManagedDBStore.kt b/app/src/main/java/com/futo/platformplayer/stores/db/ManagedDBStore.kt index 0a3b7d2a..5e757de7 100644 --- a/app/src/main/java/com/futo/platformplayer/stores/db/ManagedDBStore.kt +++ b/app/src/main/java/com/futo/platformplayer/stores/db/ManagedDBStore.kt @@ -361,22 +361,33 @@ class ManagedDBStore, T, D: ManagedDBDatabase, DA } fun convertObject(index: I): T? { - return index.obj ?: deserializeIndex(index).obj; + return index.objOrNull ?: deserializeIndex(index).obj; } fun convertObjects(indexes: List): List { - return indexes.mapNotNull { it.obj ?: convertObject(it) }; + return indexes.mapNotNull { it.objOrNull ?: convertObject(it) }; } fun deserializeIndex(index: I): I { + if(index.isCorrupted) + return index; if(index.serialized == null) throw IllegalStateException("Cannot deserialize index-only items from [${name}]"); - val obj = _serializer.deserialize(_class, index.serialized!!); - index.setInstance(obj); + try { + val obj = _serializer.deserialize(_class, index.serialized!!); + index.setInstance(obj); + } + catch(ex: Throwable) { + if(index.serialized != null && index.serialized!!.size > 0) { + Logger.w("ManagedDBStore", "Corrupted object in ${name} found [${index.id}], deleting due to ${ex.message}", ex); + index.isCorrupted = true; + delete(index.id!!); + } + } index.serialized = null; return index; } fun deserializeIndexes(indexes: List): List { for(index in indexes) deserializeIndex(index); - return indexes; + return indexes.filter { !it.isCorrupted } } fun serialize(obj: T): ByteArray {