diff --git a/app/src/main/java/com/futo/platformplayer/Extensions_Formatting.kt b/app/src/main/java/com/futo/platformplayer/Extensions_Formatting.kt index 5776d3812679a333042557b06dd5c14e34d30e6d..6c316ac5021a08fb6189e7b05ec8f8929d2b803a 100644 --- a/app/src/main/java/com/futo/platformplayer/Extensions_Formatting.kt +++ b/app/src/main/java/com/futo/platformplayer/Extensions_Formatting.kt @@ -13,6 +13,8 @@ import java.text.DecimalFormat import java.time.OffsetDateTime import java.time.temporal.ChronoUnit import kotlin.math.abs +import kotlin.math.roundToInt +import kotlin.math.roundToLong //Long @@ -119,7 +121,8 @@ fun OffsetDateTime.getNowDiffMonths(): Long { return ChronoUnit.MONTHS.between(this, OffsetDateTime.now()); } fun OffsetDateTime.getNowDiffYears(): Long { - return ChronoUnit.YEARS.between(this, OffsetDateTime.now()); + val diff = ChronoUnit.MONTHS.between(this, OffsetDateTime.now()) / 12.0; + return diff.roundToLong(); } fun OffsetDateTime.getDiffDays(otherDate: OffsetDateTime): Long { @@ -150,6 +153,7 @@ fun OffsetDateTime.toHumanNowDiffString(abs: Boolean = false) : String { if(value >= secondsInYear) { value = getNowDiffYears(); if(abs) value = abs(value); + value = Math.max(1, value); unit = "year"; } else if(value >= secondsInMonth) { diff --git a/app/src/main/java/com/futo/platformplayer/UIDialogs.kt b/app/src/main/java/com/futo/platformplayer/UIDialogs.kt index f0b8abeabc14f7efc839afad6cb051693d583845..ec6664622a5f52068d0f95be15d892a5137cffc2 100644 --- a/app/src/main/java/com/futo/platformplayer/UIDialogs.kt +++ b/app/src/main/java/com/futo/platformplayer/UIDialogs.kt @@ -34,6 +34,7 @@ import com.futo.platformplayer.dialogs.MigrateDialog import com.futo.platformplayer.dialogs.ProgressDialog import com.futo.platformplayer.engine.exceptions.PluginException import com.futo.platformplayer.logging.Logger +import com.futo.platformplayer.models.ImportCache import com.futo.platformplayer.states.StateApp import com.futo.platformplayer.states.StateBackup import com.futo.platformplayer.stores.v2.ManagedStore @@ -343,8 +344,8 @@ class UIDialogs { } } - fun showImportDialog(context: Context, store: ManagedStore<*>, name: String, reconstructions: List<String>, onConcluded: () -> Unit) { - val dialog = ImportDialog(context, store, name, reconstructions, onConcluded); + fun showImportDialog(context: Context, store: ManagedStore<*>, name: String, reconstructions: List<String>, cache: ImportCache?, onConcluded: () -> Unit) { + val dialog = ImportDialog(context, store, name, reconstructions, cache, onConcluded); registerDialogOpened(dialog); dialog.setOnDismissListener { registerDialogClosed(dialog) }; dialog.show(); diff --git a/app/src/main/java/com/futo/platformplayer/activities/MainActivity.kt b/app/src/main/java/com/futo/platformplayer/activities/MainActivity.kt index 3ba926767718451147e46cfed392911099f8bd02..9c921982cca0ddd7d0bc0ad629b2f8873896b27b 100644 --- a/app/src/main/java/com/futo/platformplayer/activities/MainActivity.kt +++ b/app/src/main/java/com/futo/platformplayer/activities/MainActivity.kt @@ -41,6 +41,7 @@ import com.futo.platformplayer.fragment.mainactivity.topbar.NavigationTopBarFrag import com.futo.platformplayer.fragment.mainactivity.topbar.SearchTopBarFragment import com.futo.platformplayer.listeners.OrientationManager import com.futo.platformplayer.logging.Logger +import com.futo.platformplayer.models.ImportCache import com.futo.platformplayer.models.UrlVideoWithTime import com.futo.platformplayer.states.* import com.futo.platformplayer.stores.FragmentedStorage @@ -603,7 +604,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher { UIDialogs.showSingleButtonDialog( this, R.drawable.ic_play, - getString(R.string.unknown_content_format) + " [${url}]", + getString(R.string.unknown_content_format) + " [${url}]\n[${intent.type}]", "Ok", { }); } @@ -693,10 +694,22 @@ class MainActivity : AppCompatActivity, IWithResultLauncher { if(!recon.trim().startsWith("[")) return handleUnknownJson(recon); - val reconLines = Json.decodeFromString<List<String>>(recon); + var reconLines = Json.decodeFromString<List<String>>(recon); + val cacheStr = reconLines.find { it.startsWith("__CACHE:") }?.substring("__CACHE:".length); + reconLines = reconLines.filter { !it.startsWith("__CACHE:") }; //TODO: constant prefix + var cache: ImportCache? = null; + try { + if(cacheStr != null) + cache = Json.decodeFromString(cacheStr); + } + catch(ex: Throwable) { + Logger.e(TAG, "Failed to deserialize cache"); + } + + recon = reconLines.joinToString("\n"); Logger.i(TAG, "Opened shared playlist reconstruction\n${recon}"); - handleReconstruction(recon); + handleReconstruction(recon, cache); return true; } else if(file.lowercase().endsWith(".zip") || mime == "application/zip") { @@ -711,12 +724,25 @@ class MainActivity : AppCompatActivity, IWithResultLauncher { fun handleFile(file: String): Boolean { Logger.i(TAG, "handleFile(url=$file)"); if(file.lowercase().endsWith(".json")) { - val recon = String(readSharedFile(file)); + var recon = String(readSharedFile(file)); if(!recon.startsWith("[")) return handleUnknownJson(recon); + var reconLines = Json.decodeFromString<List<String>>(recon); + val cacheStr = reconLines.find { it.startsWith("__CACHE:") }?.substring("__CACHE:".length); + reconLines = reconLines.filter { !it.startsWith("__CACHE:") }; //TODO: constant prefix + var cache: ImportCache? = null; + try { + if(cacheStr != null) + cache = Json.decodeFromString(cacheStr); + } + catch(ex: Throwable) { + Logger.e(TAG, "Failed to deserialize cache"); + } + recon = reconLines.joinToString("\n"); + Logger.i(TAG, "Opened shared playlist reconstruction\n${recon}"); - handleReconstruction(recon); + handleReconstruction(recon, cache); return true; } else if(file.lowercase().endsWith(".zip")) { @@ -728,7 +754,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher { } return false; } - fun handleReconstruction(recon: String) { + fun handleReconstruction(recon: String, cache: ImportCache? = null) { val type = ManagedStore.getReconstructionIdentifier(recon); val store: ManagedStore<*> = when(type) { "Playlist" -> StatePlaylists.instance.playlistStore @@ -745,7 +771,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher { if(!type.isNullOrEmpty()) { - UIDialogs.showImportDialog(this, store, name, listOf(recon)) { + UIDialogs.showImportDialog(this, store, name, listOf(recon), cache) { } } diff --git a/app/src/main/java/com/futo/platformplayer/api/media/models/channels/SerializedChannel.kt b/app/src/main/java/com/futo/platformplayer/api/media/models/channels/SerializedChannel.kt index 7c457a30464c1ddbb70ab40b8ec6c7991cbf01e9..50c53f9c8c40cce62925125bbc7d00dfccd1960d 100644 --- a/app/src/main/java/com/futo/platformplayer/api/media/models/channels/SerializedChannel.kt +++ b/app/src/main/java/com/futo/platformplayer/api/media/models/channels/SerializedChannel.kt @@ -37,6 +37,10 @@ class SerializedChannel( TODO("Not yet implemented") } + fun isSameUrl(url: String): Boolean { + return this.url == url || urlAlternatives.contains(url); + } + companion object { fun fromChannel(channel: IPlatformChannel): SerializedChannel { return SerializedChannel( diff --git a/app/src/main/java/com/futo/platformplayer/dialogs/ImportDialog.kt b/app/src/main/java/com/futo/platformplayer/dialogs/ImportDialog.kt index 76c15ae92f9e446c153fe563b4eff522820c6f70..c7d66ae1f58d2cad5db8a34ad9a5a042b2a315c5 100644 --- a/app/src/main/java/com/futo/platformplayer/dialogs/ImportDialog.kt +++ b/app/src/main/java/com/futo/platformplayer/dialogs/ImportDialog.kt @@ -22,7 +22,9 @@ import com.futo.platformplayer.UIDialogs import com.futo.platformplayer.api.media.exceptions.NoPlatformClientException import com.futo.platformplayer.assume import com.futo.platformplayer.logging.Logger +import com.futo.platformplayer.models.ImportCache import com.futo.platformplayer.states.StateApp +import com.futo.platformplayer.states.StateBackup import com.futo.platformplayer.stores.v2.ManagedStore import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -66,13 +68,15 @@ class ImportDialog : AlertDialog { private val _name: String; private val _toImport: List<String>; + private val _cache: ImportCache?; - constructor(context: Context, importStore: ManagedStore<*>, name: String, toReconstruct: List<String>, onConcluded: ()->Unit): super(context) { + constructor(context: Context, importStore: ManagedStore<*>, name: String, toReconstruct: List<String>, cache: ImportCache?, onConcluded: ()->Unit): super(context) { _context = context; _store = importStore; _onConcluded = onConcluded; _name = name; _toImport = ArrayList(toReconstruct); + _cache = cache; } override fun onCreate(savedInstanceState: Bundle?) { @@ -146,7 +150,7 @@ class ImportDialog : AlertDialog { val scope = StateApp.instance.scopeOrNull; scope?.launch(Dispatchers.IO) { try { - val migrationResult = _store.importReconstructions(_toImport) { finished, total -> + val migrationResult = _store.importReconstructions(_toImport, _cache) { finished, total -> scope.launch(Dispatchers.Main) { _textProgress.text = "${finished}/${total}"; } diff --git a/app/src/main/java/com/futo/platformplayer/models/HistoryVideo.kt b/app/src/main/java/com/futo/platformplayer/models/HistoryVideo.kt index a05fadc786ccced83a4138ef7754a85897344a98..b491f95fc113f0462b1b0266f9c244306457873d 100644 --- a/app/src/main/java/com/futo/platformplayer/models/HistoryVideo.kt +++ b/app/src/main/java/com/futo/platformplayer/models/HistoryVideo.kt @@ -30,7 +30,7 @@ class HistoryVideo { } companion object { - fun fromReconString(str: String, resolve: ((url: String)->SerializedPlatformVideo)? = null): HistoryVideo { + fun fromReconString(str: String, resolve: ((url: String)->SerializedPlatformVideo?)? = null): HistoryVideo { var index = str.indexOf("|||"); if(index < 0) throw IllegalArgumentException("Invalid history string: " + str); val url = str.substring(0, index); diff --git a/app/src/main/java/com/futo/platformplayer/models/ImportCache.kt b/app/src/main/java/com/futo/platformplayer/models/ImportCache.kt new file mode 100644 index 0000000000000000000000000000000000000000..6462edc0dc0e8b33d312ee9afcffcc09be732fac --- /dev/null +++ b/app/src/main/java/com/futo/platformplayer/models/ImportCache.kt @@ -0,0 +1,11 @@ +package com.futo.platformplayer.models + +import com.futo.platformplayer.api.media.models.channels.SerializedChannel +import com.futo.platformplayer.api.media.models.video.SerializedPlatformVideo +import kotlinx.serialization.Serializable + +@Serializable +class ImportCache( + var videos: List<SerializedPlatformVideo>? = null, + var channels: List<SerializedChannel>? = null +); \ No newline at end of file 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 35bb14ce1fb5f53aefc42b4859ba5f0c524b9b5e..bd428c6d89e629fe59d0072f85104cd7be36c68a 100644 --- a/app/src/main/java/com/futo/platformplayer/states/StateBackup.kt +++ b/app/src/main/java/com/futo/platformplayer/states/StateBackup.kt @@ -10,6 +10,7 @@ import com.futo.platformplayer.UIDialogs 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.SerializedPlatformVideo import com.futo.platformplayer.copyTo import com.futo.platformplayer.encryption.GPasswordEncryptionProvider @@ -17,6 +18,7 @@ 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.ImportCache import com.futo.platformplayer.readBytes import com.futo.platformplayer.stores.FragmentedStorage import com.futo.platformplayer.stores.v2.ManagedStore @@ -58,6 +60,19 @@ class StateBackup { StatePlaylists.instance.toMigrateCheck() ).flatten(); + fun getCache(): ImportCache { + val allPlaylists = StatePlaylists.instance.getPlaylists(); + val videos = allPlaylists.flatMap { it.videos }.distinctBy { it.url }; + + val allSubscriptions = StateSubscriptions.instance.getSubscriptions(); + val channels = allSubscriptions.map { it.channel }; + + return ImportCache( + videos = videos, + channels = channels + ); + } + private fun getAutomaticBackupPassword(customPassword: String? = null): String { val password = customPassword ?: Settings.instance.backup.autoBackupPassword ?: ""; @@ -233,11 +248,10 @@ class StateBackup { .associateBy { it.config.id } .mapValues { it.value.config.sourceUrl!! }; + val cache = getCache(); + + val export = ExportStructure(exportInfo, settings, storesToSave, pluginUrls, pluginSettings, cache); - val export = ExportStructure(exportInfo, settings, storesToSave, pluginUrls, pluginSettings); - //export.videoCache = StatePlaylists.instance.getHistory() - // .distinctBy { it.video.url } - // .map { it.video }; return export; } @@ -324,7 +338,7 @@ class StateBackup { continue; } withContext(Dispatchers.Main) { - UIDialogs.showImportDialog(context, relevantStore, store.key, store.value) { + UIDialogs.showImportDialog(context, relevantStore, store.key, store.value, export.cache) { synchronized(toAwait) { toAwait.remove(store.key); if(toAwait.isEmpty()) @@ -453,8 +467,8 @@ class StateBackup { val stores: Map<String, List<String>>, val plugins: Map<String, String>, val pluginSettings: Map<String, Map<String, String?>>, + var cache: ImportCache? = null ) { - var videoCache: List<SerializedPlatformVideo>? = null; fun asZip(): ByteArray { return ByteArrayOutputStream().use { byteStream -> @@ -478,6 +492,17 @@ class StateBackup { zipStream.putNextEntry(ZipEntry("plugin_settings")); zipStream.write(Json.encodeToString(pluginSettings).toByteArray()); + + if(cache != null) { + if(cache?.videos != null) { + zipStream.putNextEntry(ZipEntry("cache_videos")); + zipStream.write(Json.encodeToString(cache!!.videos).toByteArray()); + } + if(cache?.channels != null) { + zipStream.putNextEntry(ZipEntry("cache_channels")); + zipStream.write(Json.encodeToString(cache!!.channels).toByteArray()); + } + } }; return byteStream.toByteArray(); } @@ -492,6 +517,8 @@ class StateBackup { val stores: MutableMap<String, List<String>> = mutableMapOf(); var plugins: Map<String, String> = mapOf(); var pluginSettings: Map<String, Map<String, String?>> = mapOf(); + var videoCache: List<SerializedPlatformVideo>? = null + var channelCache: List<SerializedChannel>? = null while (zipStream.nextEntry.also { entry = it } != null) { if(entry!!.isDirectory) @@ -503,6 +530,22 @@ class StateBackup { "settings" -> settings = String(zipStream.readBytes()); "plugins" -> plugins = Json.decodeFromString(String(zipStream.readBytes())); "plugin_settings" -> pluginSettings = Json.decodeFromString(String(zipStream.readBytes())); + "cache_videos" -> { + try { + videoCache = Json.decodeFromString(String(zipStream.readBytes())); + } + catch(ex: Exception) { + Logger.e(TAG, "Couldn't deserialize video cache", ex); + } + }; + "cache_channels" -> { + try { + channelCache = Json.decodeFromString(String(zipStream.readBytes())); + } + catch(ex: Exception) { + Logger.e(TAG, "Couldn't deserialize channel cache", ex); + } + }; } else stores[entry!!.name.substring("stores/".length)] = Json.decodeFromString(String(zipStream.readBytes())); @@ -511,7 +554,10 @@ class StateBackup { throw IllegalStateException("Failed to parse zip [${entry?.name}] due to ${ex.message}"); } } - return ExportStructure(exportInfo, settings, stores, plugins, pluginSettings); + return ExportStructure(exportInfo, settings, stores, plugins, pluginSettings, ImportCache( + videos = videoCache, + channels = channelCache + )); } } } 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 d61b8ab303399e3ad5945ffebfcef08aaeaaf473..4499ceda0910db7a4ec04d21b8e9872d87689d66 100644 --- a/app/src/main/java/com/futo/platformplayer/states/StateHistory.kt +++ b/app/src/main/java/com/futo/platformplayer/states/StateHistory.kt @@ -7,6 +7,7 @@ import com.futo.platformplayer.api.media.structures.IPager import com.futo.platformplayer.constructs.Event2 import com.futo.platformplayer.logging.Logger import com.futo.platformplayer.models.HistoryVideo +import com.futo.platformplayer.models.ImportCache import com.futo.platformplayer.stores.FragmentedStorage import com.futo.platformplayer.stores.db.ManagedDBStore import com.futo.platformplayer.stores.db.types.DBHistory @@ -20,8 +21,8 @@ class StateHistory { private val _historyStore = FragmentedStorage.storeJson<HistoryVideo>("history") .withRestore(object: ReconstructStore<HistoryVideo>() { override fun toReconstruction(obj: HistoryVideo): String = obj.toReconString(); - override suspend fun toObject(id: String, backup: String, reconstructionBuilder: Builder): HistoryVideo - = HistoryVideo.fromReconString(backup, null); + override suspend fun toObject(id: String, backup: String, reconstructionBuilder: Builder, cache: ImportCache?): HistoryVideo + = HistoryVideo.fromReconString(backup) { url -> cache?.videos?.find { it.url == url } }; }) .load(); diff --git a/app/src/main/java/com/futo/platformplayer/states/StatePlaylists.kt b/app/src/main/java/com/futo/platformplayer/states/StatePlaylists.kt index 008a5d1c280b0f519e33abd8cafcd1b8f062cd4f..84b6eb517697164f9e710de8f0832fdc525e798d 100644 --- a/app/src/main/java/com/futo/platformplayer/states/StatePlaylists.kt +++ b/app/src/main/java/com/futo/platformplayer/states/StatePlaylists.kt @@ -14,6 +14,7 @@ import com.futo.platformplayer.constructs.Event0 import com.futo.platformplayer.engine.exceptions.ScriptUnavailableException import com.futo.platformplayer.exceptions.ReconstructionException import com.futo.platformplayer.logging.Logger +import com.futo.platformplayer.models.ImportCache import com.futo.platformplayer.models.Playlist import com.futo.platformplayer.stores.FragmentedStorage import com.futo.platformplayer.stores.StringArrayStorage @@ -32,8 +33,10 @@ class StatePlaylists { .withUnique { it.url } .withRestore(object: ReconstructStore<SerializedPlatformVideo>() { override fun toReconstruction(obj: SerializedPlatformVideo): String = obj.url; - override suspend fun toObject(id: String, backup: String, reconstructionBuilder: Builder): SerializedPlatformVideo - = SerializedPlatformVideo.fromVideo(StatePlatform.instance.getContentDetails(backup).await() as IPlatformVideoDetails); + override suspend fun toObject(id: String, backup: String, reconstructionBuilder: Builder, importCache: ImportCache?): SerializedPlatformVideo + = SerializedPlatformVideo.fromVideo( + importCache?.videos?.find { it.url == backup }?.let { Logger.i(TAG, "Reconstruction [${backup}] from cache"); return@let it; } ?: + StatePlatform.instance.getContentDetails(backup).await() as IPlatformVideoDetails); }) .load(); private val _watchlistOrderStore = FragmentedStorage.get<StringArrayStorage>("watchListOrder"); //Temporary workaround to add order.. @@ -154,7 +157,11 @@ class StatePlaylists { val reconstruction = playlistStore.getReconstructionString(playlist, true); val newFile = File(playlistShareDir, playlist.name + ".json"); - newFile.writeText(Json.encodeToString(reconstruction.split("\n")), Charsets.UTF_8); + newFile.writeText(Json.encodeToString(reconstruction.split("\n") + listOf( + "__CACHE:" + Json.encodeToString(ImportCache( + videos = playlist.videos.toList() + )) + )), Charsets.UTF_8); return FileProvider.getUriForFile(context, context.resources.getString(R.string.authority), newFile); } @@ -185,7 +192,7 @@ class StatePlaylists { items.addAll(obj.videos.map { it.url }); return items.map { it.replace("\n","") }.joinToString("\n"); } - override suspend fun toObject(id: String, backup: String, reconstructionBuilder: Builder): Playlist { + override suspend fun toObject(id: String, backup: String, reconstructionBuilder: Builder, importCache: ImportCache?): Playlist { val items = backup.split("\n"); if(items.size <= 0) { throw IllegalStateException("Cannot reconstructor playlist ${id}"); @@ -194,10 +201,17 @@ class StatePlaylists { val name = items[0]; val videos = items.drop(1).filter { it.isNotEmpty() }.map { try { - val video = StatePlatform.instance.getContentDetails(it).await(); + val videoUrl = it; + val video = importCache?.videos?.find { it.url == videoUrl } ?: + StatePlatform.instance.getContentDetails(it).await(); if (video is IPlatformVideoDetails) { return@map SerializedPlatformVideo.fromVideo(video); - } else { + } + else if(video is SerializedPlatformVideo) { + Logger.i(TAG, "Reconstruction [${it}] from cache"); + return@map video; + } + else { return@map null } } 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 4f2e60c1e711561fde6d2f7e4c35325212605e33..da54578dd8549eccf40230b293634b2b66c587b1 100644 --- a/app/src/main/java/com/futo/platformplayer/states/StateSubscriptions.kt +++ b/app/src/main/java/com/futo/platformplayer/states/StateSubscriptions.kt @@ -12,6 +12,7 @@ import com.futo.platformplayer.constructs.Event2 import com.futo.platformplayer.constructs.Event3 import com.futo.platformplayer.functional.CentralizedFeed import com.futo.platformplayer.logging.Logger +import com.futo.platformplayer.models.ImportCache import com.futo.platformplayer.models.Subscription import com.futo.platformplayer.models.SubscriptionGroup import com.futo.platformplayer.polycentric.PolycentricCache @@ -38,8 +39,8 @@ class StateSubscriptions { .withRestore(object: ReconstructStore<Subscription>(){ override fun toReconstruction(obj: Subscription): String = obj.channel.url; - override suspend fun toObject(id: String, backup: String, reconstructionBuilder: Builder): Subscription = - Subscription(SerializedChannel.fromChannel(StatePlatform.instance.getChannelLive(backup, false))); + override suspend fun toObject(id: String, backup: String, reconstructionBuilder: Builder, importCache: ImportCache?): Subscription = + Subscription(importCache?.channels?.find { it.isSameUrl(backup) } ?: SerializedChannel.fromChannel(StatePlatform.instance.getChannelLive(backup, false))); }).load(); private val _subscriptionOthers = FragmentedStorage.storeJson<Subscription>("subscriptions_others") .withUnique { it.channel.url } diff --git a/app/src/main/java/com/futo/platformplayer/stores/v2/ManagedStore.kt b/app/src/main/java/com/futo/platformplayer/stores/v2/ManagedStore.kt index ec0a9fa2279fb821f16ddfd470df1f2982009ffa..9673348401c241c4cfc65052a4dcc92e8043cf7a 100644 --- a/app/src/main/java/com/futo/platformplayer/stores/v2/ManagedStore.kt +++ b/app/src/main/java/com/futo/platformplayer/stores/v2/ManagedStore.kt @@ -2,6 +2,7 @@ package com.futo.platformplayer.stores.v2 import com.futo.platformplayer.assume import com.futo.platformplayer.logging.Logger +import com.futo.platformplayer.models.ImportCache import com.futo.platformplayer.states.StateApp import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -105,7 +106,7 @@ class ManagedStore<T>{ _toReconstruct.clear(); } } - suspend fun importReconstructions(items: List<String>, onProgress: ((Int, Int)->Unit)? = null): ReconstructionResult { + suspend fun importReconstructions(items: List<String>, cache: ImportCache? = null, onProgress: ((Int, Int)->Unit)? = null): ReconstructionResult { var successes = 0; val exs = ArrayList<Throwable>(); @@ -120,7 +121,7 @@ class ManagedStore<T>{ for (i in 0 .. 1) { try { Logger.i(TAG, "Importing ${logName(recon)}"); - val reconId = createFromReconstruction(recon, builder); + val reconId = createFromReconstruction(recon, builder, cache); successes++; Logger.i(TAG, "Imported ${logName(reconId)}"); break; @@ -272,12 +273,12 @@ class ManagedStore<T>{ save(obj, withReconstruction, onlyExisting); } - suspend fun createFromReconstruction(reconstruction: String, builder: ReconstructStore.Builder): String { + suspend fun createFromReconstruction(reconstruction: String, builder: ReconstructStore.Builder, cache: ImportCache? = null): String { if(_reconstructStore == null) throw IllegalStateException("Can't reconstruct as no reconstruction is implemented for this type"); val id = UUID.randomUUID().toString(); - val reconstruct = _reconstructStore!!.toObjectWithHeader(id, reconstruction, builder); + val reconstruct = _reconstructStore!!.toObjectWithHeader(id, reconstruction, builder, cache); save(reconstruct); return id; } diff --git a/app/src/main/java/com/futo/platformplayer/stores/v2/ReconstructStore.kt b/app/src/main/java/com/futo/platformplayer/stores/v2/ReconstructStore.kt index 78004a297c8af059f0ba844e1a6d1eeedb4518ae..9e5edf1338fd2fbfd7fbb4adaf9819088cbf39a1 100644 --- a/app/src/main/java/com/futo/platformplayer/stores/v2/ReconstructStore.kt +++ b/app/src/main/java/com/futo/platformplayer/stores/v2/ReconstructStore.kt @@ -1,5 +1,7 @@ package com.futo.platformplayer.stores.v2 +import com.futo.platformplayer.models.ImportCache + abstract class ReconstructStore<T> { open val backupOnSave: Boolean = false; open val backupOnCreate: Boolean = true; @@ -11,18 +13,18 @@ abstract class ReconstructStore<T> { } abstract fun toReconstruction(obj: T): String; - abstract suspend fun toObject(id: String, backup: String, reconstructionBuilder: Builder): T; + abstract suspend fun toObject(id: String, backup: String, reconstructionBuilder: Builder, importCache: ImportCache? = null): T; fun toReconstructionWithHeader(obj: T, fallbackName: String): String { val identifier = identifierName ?: fallbackName; return "@/${identifier}\n${toReconstruction(obj)}"; } - suspend fun toObjectWithHeader(id: String, backup: String, builder: Builder): T { + suspend fun toObjectWithHeader(id: String, backup: String, builder: Builder, importCache: ImportCache? = null): T { if(backup.startsWith("@/") && backup.contains("\n")) - return toObject(id, backup.substring(backup.indexOf("\n") + 1), builder); + return toObject(id, backup.substring(backup.indexOf("\n") + 1), builder, importCache); else - return toObject(id, backup, builder); + return toObject(id, backup, builder, importCache); } diff --git a/app/src/stable/assets/sources/youtube b/app/src/stable/assets/sources/youtube index 83cccf8ba5ae87d8a437775d9b341a9e3be07e74..bef199baa9df5cb3192c7a3f8baf8c57e9fbdaea 160000 --- a/app/src/stable/assets/sources/youtube +++ b/app/src/stable/assets/sources/youtube @@ -1 +1 @@ -Subproject commit 83cccf8ba5ae87d8a437775d9b341a9e3be07e74 +Subproject commit bef199baa9df5cb3192c7a3f8baf8c57e9fbdaea diff --git a/app/src/unstable/assets/sources/youtube b/app/src/unstable/assets/sources/youtube index 83cccf8ba5ae87d8a437775d9b341a9e3be07e74..bef199baa9df5cb3192c7a3f8baf8c57e9fbdaea 160000 --- a/app/src/unstable/assets/sources/youtube +++ b/app/src/unstable/assets/sources/youtube @@ -1 +1 @@ -Subproject commit 83cccf8ba5ae87d8a437775d9b341a9e3be07e74 +Subproject commit bef199baa9df5cb3192c7a3f8baf8c57e9fbdaea