From 349437c06b19c943c8457cc252aa2936d2b09496 Mon Sep 17 00:00:00 2001 From: Kelvin Date: Thu, 14 Nov 2024 23:15:15 +0100 Subject: [PATCH] Refs, History/subgroup import/export, broadcast sub change to synced devices --- .../futo/platformplayer/states/StateBackup.kt | 95 ++++++++++++++++--- .../platformplayer/states/StateHistory.kt | 1 - .../states/StateSubscriptions.kt | 22 ++++- app/src/stable/assets/sources/patreon | 2 +- app/src/stable/assets/sources/spotify | 2 +- app/src/stable/assets/sources/youtube | 2 +- app/src/unstable/assets/sources/patreon | 2 +- app/src/unstable/assets/sources/spotify | 2 +- app/src/unstable/assets/sources/youtube | 2 +- 9 files changed, 106 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/com/futo/platformplayer/states/StateBackup.kt b/app/src/main/java/com/futo/platformplayer/states/StateBackup.kt index dcebaf95..7cf3d976 100644 --- a/app/src/main/java/com/futo/platformplayer/states/StateBackup.kt +++ b/app/src/main/java/com/futo/platformplayer/states/StateBackup.kt @@ -11,6 +11,7 @@ import com.futo.platformplayer.activities.IWithResultLauncher import com.futo.platformplayer.activities.MainActivity import com.futo.platformplayer.activities.SettingsActivity import com.futo.platformplayer.api.media.models.channels.SerializedChannel +import com.futo.platformplayer.api.media.models.video.IPlatformVideo import com.futo.platformplayer.api.media.models.video.SerializedPlatformVideo import com.futo.platformplayer.copyTo import com.futo.platformplayer.encryption.GPasswordEncryptionProvider @@ -18,7 +19,9 @@ import com.futo.platformplayer.encryption.GPasswordEncryptionProviderV0 import com.futo.platformplayer.fragment.mainactivity.main.ImportSubscriptionsFragment import com.futo.platformplayer.getNowDiffHours import com.futo.platformplayer.logging.Logger +import com.futo.platformplayer.models.HistoryVideo import com.futo.platformplayer.models.ImportCache +import com.futo.platformplayer.models.SubscriptionGroup import com.futo.platformplayer.readBytes import com.futo.platformplayer.stores.FragmentedStorage import com.futo.platformplayer.stores.v2.ManagedStore @@ -61,9 +64,9 @@ class StateBackup { StatePlaylists.instance.toMigrateCheck() ).flatten(); - fun getCache(): ImportCache { + fun getCache(additionalVideos: List = listOf()): ImportCache { val allPlaylists = StatePlaylists.instance.getPlaylists(); - val videos = allPlaylists.flatMap { it.videos }.distinctBy { it.url }; + val videos = allPlaylists.flatMap { it.videos }.plus(additionalVideos).distinctBy { it.url }; val allSubscriptions = StateSubscriptions.instance.getSubscriptions(); val channels = allSubscriptions.map { it.channel }; @@ -240,6 +243,23 @@ class StateBackup { .associateBy { it.name } .mapValues { it.value.getAllReconstructionStrings() } .toMutableMap(); + + var historyVideos: List? = null; + try { + storesToSave.set("subscription_groups", StateSubscriptionGroups.instance.getSubscriptionGroups().map { Json.encodeToString(it) }); + } + catch(ex: Throwable) { + Logger.e(TAG, "Failed to serialize subscription groups"); + } + try { + val history = StateHistory.instance.getRecentHistory(OffsetDateTime.MIN, 2000); + historyVideos = history.map { it.video }; + storesToSave.set("history", history.map { it.toReconString() }); + } + catch(ex: Throwable) { + Logger.e(TAG, "Failed to serialize history"); + } + val settings = Settings.instance.encode(); val pluginSettings = StatePlugins.instance.getPlugins() .associateBy { it.config.id } @@ -249,7 +269,7 @@ class StateBackup { .associateBy { it.config.id } .mapValues { it.value.config.sourceUrl!! }; - val cache = getCache(); + val cache = getCache(historyVideos ?: listOf()); val export = ExportStructure(exportInfo, settings, storesToSave, pluginUrls, pluginSettings, cache); @@ -333,19 +353,64 @@ class StateBackup { if(doImportStores) { for(store in export.stores) { Logger.i(TAG, "Importing store [${store.key}]"); - val relevantStore = availableStores.find { it.name == store.key }; - if(relevantStore == null) { - Logger.w(TAG, "Unknown store [${store.key}] import"); - continue; + if(store.key == "history") { + withContext(Dispatchers.Main) { + UIDialogs.showDialog(context, R.drawable.ic_move_up, "Import History", "Would you like to import history?", null, 0, + UIDialogs.Action("No", { + }, UIDialogs.ActionStyle.NONE), + UIDialogs.Action("Yes", { + for(historyStr in store.value) { + try { + val histObj = HistoryVideo.fromReconString(historyStr) { url -> + return@fromReconString export.cache?.videos?.firstOrNull { it.url == url }; + } + val hist = StateHistory.instance.getHistoryByVideo(histObj.video, true, histObj.date); + if(hist != null) + StateHistory.instance.updateHistoryPosition(histObj.video, hist, true, histObj.position, histObj.date, false); + } + catch(ex: Throwable) { + Logger.e(TAG, "Failed to import subscription group", ex); + } + } + }, UIDialogs.ActionStyle.PRIMARY)) + } } - withContext(Dispatchers.Main) { - UIDialogs.showImportDialog(context, relevantStore, store.key, store.value, export.cache) { - synchronized(toAwait) { - toAwait.remove(store.key); - if(toAwait.isEmpty()) - onConclusion(); - } - }; + else if(store.key == "subscription_groups") { + withContext(Dispatchers.Main) { + UIDialogs.showDialog(context, R.drawable.ic_move_up, "Import Subscription Groups", "Would you like to import subscription groups?\nExisting groups with the same id will be overridden!", null, 0, + UIDialogs.Action("No", { + }, UIDialogs.ActionStyle.NONE), + UIDialogs.Action("Yes", { + for(groupStr in store.value) { + try { + val group = Json.decodeFromString(groupStr); + val existing = StateSubscriptionGroups.instance.getSubscriptionGroup(group.id); + if(existing != null) + StateSubscriptionGroups.instance.deleteSubscriptionGroup(existing.id, false); + StateSubscriptionGroups.instance.updateSubscriptionGroup(group); + } + catch(ex: Throwable) { + Logger.e(TAG, "Failed to import subscription group", ex); + } + } + }, UIDialogs.ActionStyle.PRIMARY)) + } + } + else { + val relevantStore = availableStores.find { it.name == store.key }; + if (relevantStore == null) { + Logger.w(TAG, "Unknown store [${store.key}] import"); + continue; + } + withContext(Dispatchers.Main) { + UIDialogs.showImportDialog(context, relevantStore, store.key, store.value, export.cache) { + synchronized(toAwait) { + toAwait.remove(store.key); + if(toAwait.isEmpty()) + onConclusion(); + } + }; + } } } } diff --git a/app/src/main/java/com/futo/platformplayer/states/StateHistory.kt b/app/src/main/java/com/futo/platformplayer/states/StateHistory.kt index d5da7880..acd92a67 100644 --- a/app/src/main/java/com/futo/platformplayer/states/StateHistory.kt +++ b/app/src/main/java/com/futo/platformplayer/states/StateHistory.kt @@ -59,7 +59,6 @@ class StateHistory { return getHistoryPosition(url) > duration * 0.7; } - fun updateHistoryPosition(liveObj: IPlatformVideo, index: DBHistory.Index, updateExisting: Boolean, position: Long = -1L, date: OffsetDateTime? = null, isUserAction: Boolean = false): Long { val pos = if(position < 0) 0 else position; val historyVideo = index.obj; 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 5bdc2d8e..df680fed 100644 --- a/app/src/main/java/com/futo/platformplayer/states/StateSubscriptions.kt +++ b/app/src/main/java/com/futo/platformplayer/states/StateSubscriptions.kt @@ -293,8 +293,26 @@ class StateSubscriptions { if(sub != null) { _subscriptions.delete(sub); onSubscriptionsChanged.emit(getSubscriptions(), false); - if(isUserAction) - _subscriptionsRemoved.setAndSave(sub.channel.url, OffsetDateTime.now()); + if(isUserAction) { + val removalTime = OffsetDateTime.now(); + _subscriptionsRemoved.setAndSave(sub.channel.url, removalTime); + + StateApp.instance.scopeOrNull?.launch(Dispatchers.IO) { + try { + StateSync.instance.broadcast( + GJSyncOpcodes.syncSubscriptions, Json.encodeToString( + SyncSubscriptionsPackage( + listOf(), + mapOf(Pair(sub.channel.url, removalTime.toEpochSecond())) + ) + ) + ); + } + catch(ex: Exception) { + Logger.w(TAG, "Failed to send subs changes to sync clients", ex); + } + } + } if(StateSubscriptionGroups.instance.hasSubscriptionGroup(sub.channel.url)) getSubscriptionOtherOrCreate(sub.channel.url, sub.channel.name, sub.channel.thumbnail); diff --git a/app/src/stable/assets/sources/patreon b/app/src/stable/assets/sources/patreon index 5b191993..7b66aea9 160000 --- a/app/src/stable/assets/sources/patreon +++ b/app/src/stable/assets/sources/patreon @@ -1 +1 @@ -Subproject commit 5b1919934d20f8c53de9959b04bdb66e0c6af3e9 +Subproject commit 7b66aea99f08303eedea879b236c49132669d2b8 diff --git a/app/src/stable/assets/sources/spotify b/app/src/stable/assets/sources/spotify index 1ccd471c..75ca0c0f 160000 --- a/app/src/stable/assets/sources/spotify +++ b/app/src/stable/assets/sources/spotify @@ -1 +1 @@ -Subproject commit 1ccd471cf4a6ef505983bc6ff4dd300624933fdd +Subproject commit 75ca0c0f1e31394ec4c82d5320fa9330df849f6f diff --git a/app/src/stable/assets/sources/youtube b/app/src/stable/assets/sources/youtube index 41e91634..80c9b4d3 160000 --- a/app/src/stable/assets/sources/youtube +++ b/app/src/stable/assets/sources/youtube @@ -1 +1 @@ -Subproject commit 41e91634965b0236c4e5ed9044da301dd3fd8c97 +Subproject commit 80c9b4d3b48739170b40b313be930329dcc59fe4 diff --git a/app/src/unstable/assets/sources/patreon b/app/src/unstable/assets/sources/patreon index 5b191993..7b66aea9 160000 --- a/app/src/unstable/assets/sources/patreon +++ b/app/src/unstable/assets/sources/patreon @@ -1 +1 @@ -Subproject commit 5b1919934d20f8c53de9959b04bdb66e0c6af3e9 +Subproject commit 7b66aea99f08303eedea879b236c49132669d2b8 diff --git a/app/src/unstable/assets/sources/spotify b/app/src/unstable/assets/sources/spotify index 1ccd471c..75ca0c0f 160000 --- a/app/src/unstable/assets/sources/spotify +++ b/app/src/unstable/assets/sources/spotify @@ -1 +1 @@ -Subproject commit 1ccd471cf4a6ef505983bc6ff4dd300624933fdd +Subproject commit 75ca0c0f1e31394ec4c82d5320fa9330df849f6f diff --git a/app/src/unstable/assets/sources/youtube b/app/src/unstable/assets/sources/youtube index 41e91634..80c9b4d3 160000 --- a/app/src/unstable/assets/sources/youtube +++ b/app/src/unstable/assets/sources/youtube @@ -1 +1 @@ -Subproject commit 41e91634965b0236c4e5ed9044da301dd3fd8c97 +Subproject commit 80c9b4d3b48739170b40b313be930329dcc59fe4