Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add flow support for elements #4031

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions playback/core/src/main/kotlin/element/ElementsContainer.kt
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
package org.jellyfin.playback.core.element

import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import java.util.concurrent.ConcurrentHashMap

/**
* Container to hold elements identified with an [ElementKey].
*/
open class ElementsContainer {
private val elements = ConcurrentHashMap<ElementKey<*>, Any?>()
private val updateFlow = MutableSharedFlow<ElementKey<*>>(
replay = 1,
extraBufferCapacity = 1,
onBufferOverflow = BufferOverflow.DROP_OLDEST,
)

fun <T : Any> get(key: ElementKey<T>): T = getOrNull(key)
?: error("No element found for key $key.")
Expand All @@ -18,9 +28,17 @@ open class ElementsContainer {

fun <T : Any> put(key: ElementKey<T>, value: T) {
elements[key] = value
updateFlow.tryEmit(key)
}

fun <T : Any> remove(key: ElementKey<T>) {
elements.remove(key)
updateFlow.tryEmit(key)
}

fun <T : Any> getFlow(key: ElementKey<T>): Flow<T?> {
return updateFlow
.map { getOrNull(key) }
.distinctUntilChanged()
}
}
9 changes: 9 additions & 0 deletions playback/core/src/main/kotlin/element/delegates.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.jellyfin.playback.core.element

import kotlinx.coroutines.flow.Flow
import kotlin.properties.ReadOnlyProperty
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty

Expand Down Expand Up @@ -38,3 +40,10 @@ fun <T : Any> requiredElement(
thisRef.put(key, value)
}
}

/**
* Delegate for the flow of an element.
*/
fun <T : Any> elementFlow(
key: ElementKey<T>,
) = ReadOnlyProperty<ElementsContainer, Flow<T?>> { thisRef, _ -> thisRef.getFlow(key) }
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package org.jellyfin.playback.core.mediastream

import org.jellyfin.playback.core.element.ElementKey
import org.jellyfin.playback.core.element.element
import org.jellyfin.playback.core.element.elementFlow
import org.jellyfin.playback.core.queue.QueueEntry

private val mediaStreamKey = ElementKey<PlayableMediaStream>("MediaStream")
Expand All @@ -10,3 +11,8 @@ private val mediaStreamKey = ElementKey<PlayableMediaStream>("MediaStream")
* Get or set the [MediaStream] for this [QueueEntry].
*/
var QueueEntry.mediaStream by element(mediaStreamKey)

/**
* Get the [MediaStream] flow for this [QueueEntry].
*/
val QueueEntry.mediaStreamFlow by elementFlow(mediaStreamKey)
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package org.jellyfin.playback.core.mediastream

import org.jellyfin.playback.core.element.ElementKey
import org.jellyfin.playback.core.element.element
import org.jellyfin.playback.core.element.elementFlow
import org.jellyfin.playback.core.queue.QueueEntry

private val normalizationGainKey = ElementKey<Float>("NormalizationGain")
Expand All @@ -11,3 +12,9 @@ private val normalizationGainKey = ElementKey<Float>("NormalizationGain")
* apply a gain to the audio output. The normalization gain must target a loudness of -23LUFS.
*/
var QueueEntry.normalizationGain by element(normalizationGainKey)

/**
* Get the flow of [normalizationGain].
* @see normalizationGain
*/
val QueueEntry.normalizationGainFlow by elementFlow(normalizationGainKey)
7 changes: 7 additions & 0 deletions playback/core/src/main/kotlin/queue/QueueEntryMetadata.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.jellyfin.playback.core.queue

import org.jellyfin.playback.core.element.ElementKey
import org.jellyfin.playback.core.element.elementFlow
import org.jellyfin.playback.core.element.requiredElement
import java.time.LocalDate
import kotlin.time.Duration
Expand Down Expand Up @@ -42,3 +43,9 @@ private val metadataKey = ElementKey<QueueEntryMetadata>("QueueEntryMetadata")
* Get or set the [QueueEntryMetadata] for this [QueueEntry]. Defaults to [QueueEntryMetadata.Empty].
*/
var QueueEntry.metadata by requiredElement(metadataKey) { QueueEntryMetadata.Empty }

/**
* Get the flow of [metadata].
* @see metadata
*/
val QueueEntry.metadataFlow by elementFlow(metadataKey)
6 changes: 6 additions & 0 deletions playback/jellyfin/src/main/kotlin/queue/baseItemElement.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package org.jellyfin.playback.jellyfin.queue

import org.jellyfin.playback.core.element.ElementKey
import org.jellyfin.playback.core.element.element
import org.jellyfin.playback.core.element.elementFlow
import org.jellyfin.playback.core.queue.QueueEntry
import org.jellyfin.sdk.model.api.BaseItemDto

Expand All @@ -11,3 +12,8 @@ private val baseItemKey = ElementKey<BaseItemDto>("BaseItemDto")
* Get or set the [BaseItemDto] for this [QueueEntry].
*/
var QueueEntry.baseItem by element(baseItemKey)

/**
* Get the [BaseItemDto] flow for this [QueueEntry].
*/
val QueueEntry.baseItemFlow by elementFlow(baseItemKey)
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package org.jellyfin.playback.jellyfin.queue

import org.jellyfin.playback.core.element.ElementKey
import org.jellyfin.playback.core.element.element
import org.jellyfin.playback.core.element.elementFlow
import org.jellyfin.playback.core.queue.QueueEntry

private val mediaSourceIdKey = ElementKey<String>("MediaSource")
Expand All @@ -11,3 +12,9 @@ private val mediaSourceIdKey = ElementKey<String>("MediaSource")
* behavior.
*/
var QueueEntry.mediaSourceId by element(mediaSourceIdKey)

/**
* Get the flow of [mediaSourceId].
* @see mediaSourceId
*/
val QueueEntry.mediaSourceIdFlow by elementFlow(mediaSourceIdKey)
Loading