feat: cahnge display order of debrid links

This commit is contained in:
tapframe 2026-05-20 00:06:58 +05:30
parent 50f9cdd8ea
commit 507d842098
3 changed files with 85 additions and 36 deletions

View file

@ -13,6 +13,7 @@ import com.nuvio.app.features.plugins.pluginContentId
import com.nuvio.app.features.plugins.PluginRuntimeResult
import com.nuvio.app.features.plugins.PluginScraper
import com.nuvio.app.features.streams.AddonStreamGroup
import com.nuvio.app.features.streams.StreamAutoPlaySelector
import com.nuvio.app.features.streams.StreamItem
import com.nuvio.app.features.streams.StreamParser
import com.nuvio.app.features.streams.StreamsUiState
@ -21,6 +22,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.async
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
@ -199,7 +201,8 @@ object PlayerStreamsRepository {
return
}
val initialGroups = streamAddons.map { addon ->
val installedAddonOrder = streamAddons.map { it.addonName }
val initialGroups = StreamAutoPlaySelector.orderAddonStreams(streamAddons.map { addon ->
AddonStreamGroup(
addonName = addon.addonName,
addonId = addon.addonId,
@ -220,7 +223,7 @@ object PlayerStreamsRepository {
streams = emptyList(),
isLoading = true,
)
}
}, installedAddonOrder)
stateFlow.value = StreamsUiState(
groups = initialGroups,
activeAddonIds = initialGroups.map { it.addonId }.toSet(),
@ -299,11 +302,20 @@ object PlayerStreamsRepository {
}
val jobs = addonJobs + pluginJobs + debridJobs
var debridPreparationLaunched = false
val completions = Channel<AddonStreamGroup>(capacity = Channel.BUFFERED)
jobs.forEach { deferred ->
val result = deferred.await()
launch {
completions.send(deferred.await())
}
}
var debridPreparationLaunched = false
repeat(jobs.size) {
val result = completions.receive()
stateFlow.update { current ->
val updated = current.groups.map { g -> if (g.addonId == result.addonId) result else g }
val updated = StreamAutoPlaySelector.orderAddonStreams(
groups = current.groups.map { g -> if (g.addonId == result.addonId) result else g },
installedOrder = installedAddonOrder,
)
val anyLoading = updated.any { it.isLoading }
current.copy(
groups = updated,
@ -340,6 +352,7 @@ object PlayerStreamsRepository {
}
}
}
completions.close()
}
setJob(job)
}

View file

@ -2,6 +2,34 @@ package com.nuvio.app.features.streams
object StreamAutoPlaySelector {
fun orderAddonStreams(
groups: List<AddonStreamGroup>,
installedOrder: List<String>,
): List<AddonStreamGroup> {
if (groups.isEmpty()) return groups
val addonRankByName = HashMap<String, Int>(installedOrder.size)
installedOrder.forEachIndexed { index, addonName ->
if (addonName !in addonRankByName) {
addonRankByName[addonName] = index
}
}
val (directDebridEntries, remainingEntries) = groups.partition { group ->
group.addonId.startsWith("debrid:") ||
group.streams.any { stream -> stream.isDirectDebridStream }
}
if (installedOrder.isEmpty()) return directDebridEntries + remainingEntries
val (addonEntries, pluginEntries) = remainingEntries.partition { group ->
group.addonName in addonRankByName
}
val orderedAddons = addonEntries.sortedBy { group ->
addonRankByName.getValue(group.addonName)
}
return directDebridEntries + orderedAddons + pluginEntries
}
fun selectAutoPlayStream(
streams: List<StreamItem>,
mode: StreamAutoPlayMode,

View file

@ -184,7 +184,8 @@ object StreamsRepository {
}
// Initialise loading placeholders
val initialGroups = streamAddons.map { addon ->
val installedAddonOrder = streamAddons.map { it.addonName }
val initialGroups = StreamAutoPlaySelector.orderAddonStreams(streamAddons.map { addon ->
AddonStreamGroup(
addonName = addon.addonName,
addonId = addon.addonId,
@ -205,7 +206,7 @@ object StreamsRepository {
streams = emptyList(),
isLoading = true,
)
}
}, installedAddonOrder)
_uiState.value = StreamsUiState(
requestToken = requestToken,
groups = initialGroups,
@ -226,9 +227,7 @@ object StreamsRepository {
pluginProviderGroups.sumOf { it.scrapers.size } +
debridTargets.size
val installedAddonNames = installedAddons
.map { it.displayTitle }
.toSet()
val installedAddonNames = installedAddonOrder.toSet()
var autoSelectTriggered = false
var timeoutElapsed = false
var debridPreparationLaunched = false
@ -383,9 +382,12 @@ object StreamsRepository {
is StreamLoadCompletion.Addon -> {
val result = completion.group
_uiState.update { current ->
val updated = current.groups.map { group ->
if (group.addonId == result.addonId) result else group
}
val updated = StreamAutoPlaySelector.orderAddonStreams(
groups = current.groups.map { group ->
if (group.addonId == result.addonId) result else group
},
installedOrder = installedAddonOrder,
)
val anyLoading = updated.any { it.isLoading }
current.copy(
groups = updated,
@ -403,28 +405,31 @@ object StreamsRepository {
}
_uiState.update { current ->
val updated = current.groups.map { group ->
if (group.addonId != completion.addonId) {
group
} else {
val mergedStreams = if (completion.streams.isEmpty()) {
group.streams
val updated = StreamAutoPlaySelector.orderAddonStreams(
groups = current.groups.map { group ->
if (group.addonId != completion.addonId) {
group
} else {
(group.streams + completion.streams).sortedForGroupedDisplay()
val mergedStreams = if (completion.streams.isEmpty()) {
group.streams
} else {
(group.streams + completion.streams).sortedForGroupedDisplay()
}
val stillLoading = remaining > 0
val finalError = if (mergedStreams.isEmpty() && !stillLoading) {
pluginFirstErrorByAddonId[completion.addonId]
} else {
null
}
group.copy(
streams = mergedStreams,
isLoading = stillLoading,
error = finalError,
)
}
val stillLoading = remaining > 0
val finalError = if (mergedStreams.isEmpty() && !stillLoading) {
pluginFirstErrorByAddonId[completion.addonId]
} else {
null
}
group.copy(
streams = mergedStreams,
isLoading = stillLoading,
error = finalError,
)
}
}
},
installedOrder = installedAddonOrder,
)
val anyLoading = updated.any { it.isLoading }
current.copy(
groups = updated,
@ -437,9 +442,12 @@ object StreamsRepository {
is StreamLoadCompletion.Debrid -> {
val result = completion.group
_uiState.update { current ->
val updated = current.groups.map { group ->
if (group.addonId == result.addonId) result else group
}
val updated = StreamAutoPlaySelector.orderAddonStreams(
groups = current.groups.map { group ->
if (group.addonId == result.addonId) result else group
},
installedOrder = installedAddonOrder,
)
val anyLoading = updated.any { it.isLoading }
current.copy(
groups = updated,