mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-04-25 02:23:11 +00:00
feat: add support for custom addon names
This commit is contained in:
parent
6c17efdbef
commit
ebcccb9b4c
10 changed files with 51 additions and 25 deletions
|
|
@ -44,6 +44,7 @@ data class AddonBehaviorHints(
|
|||
data class ManagedAddon(
|
||||
val manifestUrl: String,
|
||||
val manifest: AddonManifest? = null,
|
||||
val userSetName: String? = null,
|
||||
val isRefreshing: Boolean = false,
|
||||
val errorMessage: String? = null,
|
||||
) {
|
||||
|
|
@ -51,7 +52,9 @@ data class ManagedAddon(
|
|||
get() = manifest != null
|
||||
|
||||
val displayTitle: String
|
||||
get() = manifest?.name ?: manifestUrl.substringBefore("?").substringAfterLast("/").ifBlank { "Addon" }
|
||||
get() = userSetName?.takeIf { it.isNotBlank() && it != manifest?.name }
|
||||
?: manifest?.name
|
||||
?: manifestUrl.substringBefore("?").substringAfterLast("/").ifBlank { "Addon" }
|
||||
}
|
||||
|
||||
data class AddonsUiState(
|
||||
|
|
|
|||
|
|
@ -108,6 +108,13 @@ object AddonRepository {
|
|||
}
|
||||
.decodeList<AddonRow>()
|
||||
|
||||
val namesByUrl = mutableMapOf<String, String>()
|
||||
rows.forEach { row ->
|
||||
if (!row.name.isNullOrBlank()) {
|
||||
namesByUrl[ensureManifestSuffix(row.url)] = row.name
|
||||
}
|
||||
}
|
||||
|
||||
val urls = dedupeManifestUrls(rows.map { it.url })
|
||||
log.i { "pullFromServer() — server returned ${rows.size} addons" }
|
||||
urls.forEachIndexed { i, u -> log.d { " server[$i]: $u" } }
|
||||
|
|
@ -164,7 +171,7 @@ object AddonRepository {
|
|||
val existingByUrl = _uiState.value.addons.associateBy(ManagedAddon::manifestUrl)
|
||||
_uiState.value = AddonsUiState(
|
||||
addons = urls.map { url ->
|
||||
existingByUrl[url].toPendingAddon(url)
|
||||
existingByUrl[url].toPendingAddon(url, namesByUrl[url])
|
||||
},
|
||||
)
|
||||
persist()
|
||||
|
|
@ -311,7 +318,7 @@ object AddonRepository {
|
|||
.mapIndexed { index, addon ->
|
||||
AddonPushItem(
|
||||
url = addon.manifestUrl,
|
||||
name = addon.manifest?.name ?: "",
|
||||
name = addon.userSetName?.takeIf { it.isNotBlank() } ?: addon.manifest?.name ?: "",
|
||||
enabled = true,
|
||||
sortOrder = index,
|
||||
)
|
||||
|
|
@ -369,21 +376,27 @@ object AddonRepository {
|
|||
}
|
||||
}
|
||||
|
||||
private fun ManagedAddon?.toPendingAddon(manifestUrl: String): ManagedAddon =
|
||||
private fun ManagedAddon?.toPendingAddon(manifestUrl: String, userSetName: String? = null): ManagedAddon =
|
||||
when {
|
||||
this == null -> ManagedAddon(
|
||||
manifestUrl = manifestUrl,
|
||||
isRefreshing = true,
|
||||
userSetName = userSetName,
|
||||
)
|
||||
manifest != null -> copy(
|
||||
manifestUrl = manifestUrl,
|
||||
isRefreshing = false,
|
||||
userSetName = userSetName ?: this.userSetName,
|
||||
)
|
||||
isRefreshing -> copy(
|
||||
manifestUrl = manifestUrl,
|
||||
userSetName = userSetName ?: this.userSetName,
|
||||
)
|
||||
isRefreshing -> copy(manifestUrl = manifestUrl)
|
||||
else -> copy(
|
||||
manifestUrl = manifestUrl,
|
||||
isRefreshing = true,
|
||||
errorMessage = null,
|
||||
userSetName = userSetName ?: this.userSetName,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -330,7 +330,7 @@ private fun InstalledAddonCard(
|
|||
Spacer(modifier = Modifier.width(16.dp))
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
Text(
|
||||
text = manifest?.name ?: addon.displayTitle,
|
||||
text = addon.displayTitle,
|
||||
style = MaterialTheme.typography.headlineLarge,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
maxLines = 2,
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ object CollectionRepository {
|
|||
.map { catalog ->
|
||||
AvailableCatalog(
|
||||
addonId = manifest.id,
|
||||
addonName = manifest.name,
|
||||
addonName = addon.displayTitle,
|
||||
type = catalog.type,
|
||||
catalogId = catalog.id,
|
||||
catalogName = catalog.name,
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ fun buildHomeCatalogDefinitions(addons: List<ManagedAddon>): List<HomeCatalogDef
|
|||
HomeCatalogDefinition(
|
||||
key = "${manifest.id}:${catalog.type}:${catalog.id}",
|
||||
defaultTitle = "${catalog.name} - ${catalog.type.displayLabel()}",
|
||||
addonName = manifest.name,
|
||||
addonName = addon.displayTitle,
|
||||
manifestUrl = addon.manifestUrl,
|
||||
type = catalog.type,
|
||||
catalogId = catalog.id,
|
||||
|
|
|
|||
|
|
@ -629,7 +629,7 @@ fun PlayerScreen(
|
|||
)
|
||||
|
||||
val installedAddonNames = AddonRepository.uiState.value.addons
|
||||
.mapNotNull { it.manifest?.name }
|
||||
.map { it.displayTitle }
|
||||
.toSet()
|
||||
|
||||
val timeoutMs = settings.streamAutoPlayTimeoutSeconds * 1000L
|
||||
|
|
|
|||
|
|
@ -165,6 +165,10 @@ object PlayerStreamsRepository {
|
|||
return
|
||||
}
|
||||
|
||||
val addonDisplayNames = installedAddons.associate {
|
||||
(it.manifest?.id ?: it.manifestUrl) to it.displayTitle
|
||||
}
|
||||
|
||||
val streamAddons = installedAddons
|
||||
.mapNotNull { it.manifest }
|
||||
.filter { manifest ->
|
||||
|
|
@ -186,7 +190,7 @@ object PlayerStreamsRepository {
|
|||
|
||||
val initialGroups = streamAddons.map { manifest ->
|
||||
AddonStreamGroup(
|
||||
addonName = manifest.name,
|
||||
addonName = addonDisplayNames[manifest.id] ?: manifest.name,
|
||||
addonId = manifest.id,
|
||||
streams = emptyList(),
|
||||
isLoading = true,
|
||||
|
|
@ -214,16 +218,17 @@ object PlayerStreamsRepository {
|
|||
.removeSuffix("/manifest.json")
|
||||
val url = "$baseUrl/stream/$type/$encodedId.json"
|
||||
|
||||
val displayName = addonDisplayNames[manifest.id] ?: manifest.name
|
||||
runCatching {
|
||||
val payload = httpGetText(url)
|
||||
StreamParser.parse(payload, manifest.name, manifest.id)
|
||||
StreamParser.parse(payload, displayName, manifest.id)
|
||||
}.fold(
|
||||
onSuccess = { streams ->
|
||||
AddonStreamGroup(manifest.name, manifest.id, streams, isLoading = false)
|
||||
AddonStreamGroup(displayName, manifest.id, streams, isLoading = false)
|
||||
},
|
||||
onFailure = { err ->
|
||||
log.w(err) { "Failed: ${manifest.name}" }
|
||||
AddonStreamGroup(manifest.name, manifest.id, emptyList(), isLoading = false, error = err.message)
|
||||
log.w(err) { "Failed: ${displayName}" }
|
||||
AddonStreamGroup(displayName, manifest.id, emptyList(), isLoading = false, error = err.message)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ object SubtitleRepository {
|
|||
id = id,
|
||||
url = url,
|
||||
language = lang,
|
||||
display = "${formatLanguage(lang)} (${manifest.name})",
|
||||
display = "${formatLanguage(lang)} (${addon.displayTitle})",
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -288,7 +288,7 @@ object SearchRepository {
|
|||
val genreExtra = catalog.genreExtra()
|
||||
DiscoverCatalogOption(
|
||||
key = "${manifest.id}:${catalog.type}:${catalog.id}",
|
||||
addonName = manifest.name,
|
||||
addonName = addon.displayTitle,
|
||||
manifestUrl = addon.manifestUrl,
|
||||
type = catalog.type,
|
||||
catalogId = catalog.id,
|
||||
|
|
@ -314,8 +314,8 @@ object SearchRepository {
|
|||
return HomeCatalogSection(
|
||||
key = "${manifest.id}:search:$type:$catalogId:${query.lowercase()}",
|
||||
title = "$catalogName - ${type.displayLabel()}",
|
||||
subtitle = manifest.name,
|
||||
addonName = manifest.name,
|
||||
subtitle = addon.displayTitle,
|
||||
addonName = addon.displayTitle,
|
||||
type = type,
|
||||
manifestUrl = manifest.transportUrl,
|
||||
catalogId = catalogId,
|
||||
|
|
|
|||
|
|
@ -127,6 +127,10 @@ object StreamsRepository {
|
|||
return
|
||||
}
|
||||
|
||||
val addonDisplayNames = installedAddons.associate {
|
||||
(it.manifest?.id ?: it.manifestUrl) to it.displayTitle
|
||||
}
|
||||
|
||||
val streamAddons = installedAddons
|
||||
.mapNotNull { it.manifest }
|
||||
.filter { manifest ->
|
||||
|
|
@ -151,7 +155,7 @@ object StreamsRepository {
|
|||
// Initialise loading placeholders
|
||||
val initialGroups = streamAddons.map { manifest ->
|
||||
AddonStreamGroup(
|
||||
addonName = manifest.name,
|
||||
addonName = addonDisplayNames[manifest.id] ?: manifest.name,
|
||||
addonId = manifest.id,
|
||||
streams = emptyList(),
|
||||
isLoading = true,
|
||||
|
|
@ -182,7 +186,7 @@ object StreamsRepository {
|
|||
val totalTasks = streamAddons.size + pluginRemainingByAddonId.values.sum()
|
||||
|
||||
val installedAddonNames = installedAddons
|
||||
.mapNotNull { it.manifest?.name }
|
||||
.map { it.displayTitle }
|
||||
.toSet()
|
||||
var autoSelectTriggered = false
|
||||
var timeoutElapsed = false
|
||||
|
|
@ -237,27 +241,28 @@ object StreamsRepository {
|
|||
val url = "$baseUrl/stream/$type/$encodedId.json"
|
||||
log.d { "Fetching streams from: $url" }
|
||||
|
||||
val displayName = addonDisplayNames[manifest.id] ?: manifest.name
|
||||
val group = runCatching {
|
||||
val payload = httpGetText(url)
|
||||
StreamParser.parse(
|
||||
payload = payload,
|
||||
addonName = manifest.name,
|
||||
addonName = displayName,
|
||||
addonId = manifest.id,
|
||||
)
|
||||
}.fold(
|
||||
onSuccess = { streams ->
|
||||
log.d { "Got ${streams.size} streams from ${manifest.name}" }
|
||||
log.d { "Got ${streams.size} streams from ${displayName}" }
|
||||
AddonStreamGroup(
|
||||
addonName = manifest.name,
|
||||
addonName = displayName,
|
||||
addonId = manifest.id,
|
||||
streams = streams,
|
||||
isLoading = false,
|
||||
)
|
||||
},
|
||||
onFailure = { err ->
|
||||
log.w(err) { "Failed to fetch streams from ${manifest.name}" }
|
||||
log.w(err) { "Failed to fetch streams from ${displayName}" }
|
||||
AddonStreamGroup(
|
||||
addonName = manifest.name,
|
||||
addonName = displayName,
|
||||
addonId = manifest.id,
|
||||
streams = emptyList(),
|
||||
isLoading = false,
|
||||
|
|
|
|||
Loading…
Reference in a new issue