diff --git a/musikr/src/main/java/org/oxycblt/musikr/pipeline/ExtractStep.kt b/musikr/src/main/java/org/oxycblt/musikr/pipeline/ExtractStep.kt index c04472475..89f98b016 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/pipeline/ExtractStep.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/pipeline/ExtractStep.kt @@ -89,6 +89,7 @@ private class ExtractStepImpl( val fds = uncachedSongs + .shuffle() .mapNotNull { wrap(it) { file -> withContext(Dispatchers.IO) { diff --git a/musikr/src/main/java/org/oxycblt/musikr/pipeline/FlowUtil.kt b/musikr/src/main/java/org/oxycblt/musikr/pipeline/FlowUtil.kt index 6044db976..2ae472a29 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/pipeline/FlowUtil.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/pipeline/FlowUtil.kt @@ -20,9 +20,12 @@ package org.oxycblt.musikr.pipeline import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.asFlow +import kotlinx.coroutines.flow.emitAll import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.receiveAsFlow +import kotlinx.coroutines.flow.toList import kotlinx.coroutines.flow.withIndex internal sealed interface Divert { @@ -79,3 +82,15 @@ internal fun Flow.distribute(n: Int): DistributedFlow { val hotFlows = posChannels.map { it.receiveAsFlow() }.toTypedArray() return DistributedFlow(managerFlow, hotFlows) } + +internal fun Flow.shuffle() = flow { + // As far as I'm aware, the only way to get a truly normal distribution + // on a flow is by evaluating it. I tried a bunch of different strategies + // on lazily shuffling a flow and it simply doesn't produce a good enough + // distribution since you need to emit late stuff early and early stuff + // late. It's best to just eval and re-emit. + val output = mutableListOf() + toList(output) + output.shuffle() + emitAll(output.asFlow()) +}