mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-08-07 20:00:06 +00:00
Fix mobile home catalog cache invalidation
This commit is contained in:
parent
f2eddbaf5b
commit
4aa29087df
3 changed files with 94 additions and 24 deletions
|
|
@ -1,6 +1,8 @@
|
|||
package com.nuvio.app.features.home
|
||||
|
||||
import com.nuvio.app.core.i18n.localizedMediaTypeLabel
|
||||
import com.nuvio.app.features.addons.AddonCatalog
|
||||
import com.nuvio.app.features.addons.AddonManifest
|
||||
import com.nuvio.app.features.addons.ManagedAddon
|
||||
import com.nuvio.app.features.addons.enabledAddons
|
||||
import com.nuvio.app.features.catalog.supportsPagination
|
||||
|
|
@ -17,7 +19,21 @@ data class HomeCatalogDefinition(
|
|||
val type: String,
|
||||
val catalogId: String,
|
||||
val supportsPagination: Boolean,
|
||||
)
|
||||
val descriptorSignature: String,
|
||||
) {
|
||||
val cacheKey: String
|
||||
get() = "$key|$descriptorSignature"
|
||||
}
|
||||
|
||||
fun buildHomeCatalogRefreshSignature(addons: List<ManagedAddon>): List<String> =
|
||||
addons.enabledAddons().mapNotNull { addon ->
|
||||
val manifest = addon.manifest ?: return@mapNotNull null
|
||||
addon to manifest
|
||||
}.flatMap { (addon, manifest) ->
|
||||
manifest.catalogs.map { catalog ->
|
||||
buildHomeCatalogDescriptorSignature(addon, manifest, catalog)
|
||||
}
|
||||
}.sorted()
|
||||
|
||||
fun buildHomeCatalogDefinitions(addons: List<ManagedAddon>): List<HomeCatalogDefinition> =
|
||||
addons.enabledAddons().mapNotNull { addon ->
|
||||
|
|
@ -41,8 +57,68 @@ fun buildHomeCatalogDefinitions(addons: List<ManagedAddon>): List<HomeCatalogDef
|
|||
type = catalog.type,
|
||||
catalogId = catalog.id,
|
||||
supportsPagination = catalog.supportsPagination(),
|
||||
descriptorSignature = buildHomeCatalogDescriptorSignature(addon, manifest, catalog),
|
||||
)
|
||||
}
|
||||
}.distinctBy(HomeCatalogDefinition::key)
|
||||
|
||||
private fun buildHomeCatalogDescriptorSignature(
|
||||
addon: ManagedAddon,
|
||||
manifest: AddonManifest,
|
||||
catalog: AddonCatalog,
|
||||
): String =
|
||||
buildString {
|
||||
append(addon.displayTitle)
|
||||
append('|')
|
||||
append(manifest.id)
|
||||
append('|')
|
||||
append(manifest.name)
|
||||
append('|')
|
||||
append(manifest.version)
|
||||
append('|')
|
||||
append(manifest.description)
|
||||
append('|')
|
||||
append(manifest.logoUrl.orEmpty())
|
||||
append('|')
|
||||
append(manifest.transportUrl)
|
||||
append('|')
|
||||
append(manifest.types.joinToString(","))
|
||||
append('|')
|
||||
append(manifest.idPrefixes.joinToString(","))
|
||||
append('|')
|
||||
append(manifest.resources.joinToString(",") { resource ->
|
||||
listOf(
|
||||
resource.name,
|
||||
resource.types.joinToString("/"),
|
||||
resource.idPrefixes.joinToString("/"),
|
||||
).joinToString(":")
|
||||
})
|
||||
append('|')
|
||||
append(
|
||||
listOf(
|
||||
manifest.behaviorHints.configurable,
|
||||
manifest.behaviorHints.configurationRequired,
|
||||
manifest.behaviorHints.adult,
|
||||
manifest.behaviorHints.p2p,
|
||||
).joinToString(":"),
|
||||
)
|
||||
append('|')
|
||||
append(catalog.type)
|
||||
append('|')
|
||||
append(catalog.id)
|
||||
append('|')
|
||||
append(catalog.name)
|
||||
append('|')
|
||||
append(catalog.supportsPagination())
|
||||
append('|')
|
||||
append(catalog.extra.joinToString(",") { extra ->
|
||||
listOf(
|
||||
extra.name,
|
||||
extra.isRequired.toString(),
|
||||
extra.options.joinToString("/"),
|
||||
extra.optionsLimit?.toString().orEmpty(),
|
||||
).joinToString(":")
|
||||
})
|
||||
}
|
||||
|
||||
internal fun String.displayLabel(): String = localizedMediaTypeLabel(this)
|
||||
|
|
|
|||
|
|
@ -47,15 +47,15 @@ object HomeRepository {
|
|||
val activeAddons = addons.enabledAddons()
|
||||
val requests = buildHomeCatalogDefinitions(activeAddons)
|
||||
currentDefinitions = requests
|
||||
val requestKeys = requests.mapTo(mutableSetOf(), HomeCatalogDefinition::key)
|
||||
cachedSections = cachedSections.filterKeys(requestKeys::contains)
|
||||
val requestCacheKeys = requests.mapTo(mutableSetOf(), HomeCatalogDefinition::cacheKey)
|
||||
cachedSections = cachedSections.filterKeys(requestCacheKeys::contains)
|
||||
val requestKey = requests.joinToString(separator = "|") { request ->
|
||||
"${request.manifestUrl}:${request.type}:${request.catalogId}"
|
||||
request.cacheKey
|
||||
}
|
||||
|
||||
if (!force && activeRequestKey == requestKey && _uiState.value.isLoading) return
|
||||
|
||||
if (!force && requestKey == lastRequestKey && requestKeys.all(cachedSections::containsKey)) {
|
||||
if (!force && requestKey == lastRequestKey && requestCacheKeys.all(cachedSections::containsKey)) {
|
||||
if (_uiState.value.sections.isEmpty() || _uiState.value.heroItems.isEmpty()) {
|
||||
applyCurrentSettings()
|
||||
}
|
||||
|
|
@ -90,7 +90,7 @@ object HomeRepository {
|
|||
snapshot = HomeCatalogSettingsRepository.snapshot(),
|
||||
)
|
||||
val pendingRequests = prioritizedRequests.filter { definition ->
|
||||
force || cachedSections[definition.key] == null
|
||||
force || cachedSections[definition.cacheKey] == null
|
||||
}
|
||||
if (pendingRequests.isEmpty()) {
|
||||
publishCurrentState(
|
||||
|
|
@ -108,16 +108,20 @@ object HomeRepository {
|
|||
pendingRequests.chunked(HOME_CATALOG_FETCH_BATCH_SIZE).forEach { batch ->
|
||||
if (activeRequestKey != requestKey) return@launch
|
||||
val results = batch.map { request ->
|
||||
async { runCatching { request.toSection() } }
|
||||
async { request to runCatching { request.toSection() } }
|
||||
}.awaitAll()
|
||||
|
||||
if (activeRequestKey != requestKey) return@launch
|
||||
|
||||
results.mapNotNull { it.getOrNull() }.forEach { section ->
|
||||
loadedSections[section.key] = section
|
||||
results.mapNotNull { (request, result) ->
|
||||
result.getOrNull()?.let { section -> request.cacheKey to section }
|
||||
}.forEach { (cacheKey, section) ->
|
||||
loadedSections[cacheKey] = section
|
||||
}
|
||||
if (firstErrorMessage == null) {
|
||||
firstErrorMessage = results.firstNotNullOfOrNull { it.exceptionOrNull()?.message }
|
||||
firstErrorMessage = results.firstNotNullOfOrNull { (_, result) ->
|
||||
result.exceptionOrNull()?.message
|
||||
}
|
||||
}
|
||||
cachedSections = loadedSections.toMap()
|
||||
lastErrorMessage = firstErrorMessage
|
||||
|
|
@ -190,7 +194,7 @@ object HomeRepository {
|
|||
val preference = preferences[definition.key]
|
||||
if (preference?.enabled == false) return@mapNotNull null
|
||||
|
||||
val section = cachedSections[definition.key]?.withReleaseFilter() ?: return@mapNotNull null
|
||||
val section = cachedSections[definition.cacheKey]?.withReleaseFilter() ?: return@mapNotNull null
|
||||
if (section.items.isEmpty()) return@mapNotNull null
|
||||
val customTitle = preference?.customTitle.orEmpty()
|
||||
section.copy(
|
||||
|
|
@ -202,7 +206,7 @@ object HomeRepository {
|
|||
val heroRandom = Random((requestKey?.hashCode() ?: 0).absoluteValue + 1)
|
||||
currentDefinitions
|
||||
.filter { definition -> preferences[definition.key]?.heroSourceEnabled != false }
|
||||
.mapNotNull { definition -> cachedSections[definition.key] }
|
||||
.mapNotNull { definition -> cachedSections[definition.cacheKey] }
|
||||
.map { section -> section.withReleaseFilter() }
|
||||
.flatMap { section -> section.items }
|
||||
.distinctBy { item -> "${item.type}:${item.id}" }
|
||||
|
|
|
|||
|
|
@ -433,18 +433,8 @@ fun HomeScreen(
|
|||
.sorted()
|
||||
}
|
||||
|
||||
val catalogRefreshKey = remember(availableManifests) {
|
||||
availableManifests
|
||||
.map { manifest ->
|
||||
buildString {
|
||||
append(manifest.transportUrl)
|
||||
append(':')
|
||||
append(manifest.catalogs.joinToString(separator = ",") { catalog ->
|
||||
"${catalog.type}:${catalog.id}:${catalog.extra.count { it.isRequired }}"
|
||||
})
|
||||
}
|
||||
}
|
||||
.sorted()
|
||||
val catalogRefreshKey = remember(enabledAddons) {
|
||||
buildHomeCatalogRefreshSignature(enabledAddons)
|
||||
}
|
||||
|
||||
LaunchedEffect(catalogRefreshKey) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue