diff --git a/playback/jellyfin/src/main/kotlin/mediastream/AudioMediaStreamResolver.kt b/playback/jellyfin/src/main/kotlin/mediastream/AudioMediaStreamResolver.kt index 9e0eba9f69..0f21147c15 100644 --- a/playback/jellyfin/src/main/kotlin/mediastream/AudioMediaStreamResolver.kt +++ b/playback/jellyfin/src/main/kotlin/mediastream/AudioMediaStreamResolver.kt @@ -8,6 +8,7 @@ import org.jellyfin.playback.core.mediastream.PlayableMediaStream import org.jellyfin.playback.core.queue.QueueEntry import org.jellyfin.playback.core.support.PlaySupportReport import org.jellyfin.playback.jellyfin.queue.baseItem +import org.jellyfin.playback.jellyfin.queue.mediaSourceId import org.jellyfin.sdk.api.client.ApiClient import org.jellyfin.sdk.api.client.extensions.audioApi import org.jellyfin.sdk.api.client.extensions.dynamicHlsApi @@ -54,7 +55,7 @@ class AudioMediaStreamResolver( val baseItem = queueEntry.baseItem if (baseItem == null || baseItem.mediaType != MediaType.Audio) return null - val mediaInfo = getPlaybackInfo(baseItem) + val mediaInfo = getPlaybackInfo(baseItem, queueEntry.mediaSourceId) // Test for direct play support val directPlayStream = mediaInfo.getDirectPlayStream() diff --git a/playback/jellyfin/src/main/kotlin/mediastream/JellyfinStreamResolver.kt b/playback/jellyfin/src/main/kotlin/mediastream/JellyfinStreamResolver.kt index 7ebeb42249..8a4d787a88 100644 --- a/playback/jellyfin/src/main/kotlin/mediastream/JellyfinStreamResolver.kt +++ b/playback/jellyfin/src/main/kotlin/mediastream/JellyfinStreamResolver.kt @@ -5,6 +5,7 @@ import org.jellyfin.sdk.api.client.ApiClient import org.jellyfin.sdk.api.client.extensions.mediaInfoApi import org.jellyfin.sdk.model.api.BaseItemDto import org.jellyfin.sdk.model.api.DeviceProfile +import org.jellyfin.sdk.model.api.MediaProtocol import org.jellyfin.sdk.model.api.MediaSourceInfo import org.jellyfin.sdk.model.api.PlaybackInfoDto @@ -19,41 +20,41 @@ abstract class JellyfinStreamResolver( protected suspend fun getPlaybackInfo( item: BaseItemDto, - mediaSource: MediaSourceInfo? = null, + mediaSourceId: String? = null, ): MediaInfo { val response by api.mediaInfoApi.getPostedPlaybackInfo( itemId = item.id, data = PlaybackInfoDto( userId = api.userId, maxStreamingBitrate = profile.maxStreamingBitrate, - mediaSourceId = mediaSource?.id, - liveStreamId = mediaSource?.liveStreamId, + mediaSourceId = mediaSourceId, deviceProfile = profile, enableDirectPlay = true, enableDirectStream = true, enableTranscoding = true, allowVideoStreamCopy = true, allowAudioStreamCopy = true, - autoOpenLiveStream = true, + autoOpenLiveStream = false, ) ) if (response.errorCode != null) { - error("Failed to get media info for item ${item.id} source ${mediaSource?.id}: ${response.errorCode}") + error("Failed to get media info for item ${item.id} source ${mediaSourceId}: ${response.errorCode}") } - val responseMediaSource = when (mediaSource) { - null -> response.mediaSources.firstOrNull() - else -> response.mediaSources.firstOrNull { it.id === mediaSource.id } - } + val mediaSource = response.mediaSources + // Filter out invalid streams (like strm files) + .filter { it.protocol == MediaProtocol.FILE && !it.isRemote } + // Select first media source + .firstOrNull { mediaSourceId == null || it.id == mediaSourceId } - requireNotNull(responseMediaSource) { - "Failed to get media info for item ${item.id} source ${mediaSource?.id}: media source missing in response" + requireNotNull(mediaSource) { + "Failed to get media info for item ${item.id} source ${mediaSourceId}: media source missing in response" } return MediaInfo( playSessionId = response.playSessionId.orEmpty(), - mediaSource = responseMediaSource + mediaSource = mediaSource ) } } diff --git a/playback/jellyfin/src/main/kotlin/mediastream/UniversalAudioMediaStreamResolver.kt b/playback/jellyfin/src/main/kotlin/mediastream/UniversalAudioMediaStreamResolver.kt index b8c32015ba..200add0974 100644 --- a/playback/jellyfin/src/main/kotlin/mediastream/UniversalAudioMediaStreamResolver.kt +++ b/playback/jellyfin/src/main/kotlin/mediastream/UniversalAudioMediaStreamResolver.kt @@ -6,6 +6,7 @@ import org.jellyfin.playback.core.mediastream.PlayableMediaStream import org.jellyfin.playback.core.queue.QueueEntry import org.jellyfin.playback.core.support.PlaySupportReport import org.jellyfin.playback.jellyfin.queue.baseItem +import org.jellyfin.playback.jellyfin.queue.mediaSourceId import org.jellyfin.sdk.api.client.ApiClient import org.jellyfin.sdk.api.client.extensions.universalAudioApi import org.jellyfin.sdk.model.api.BaseItemKind @@ -22,7 +23,7 @@ class UniversalAudioMediaStreamResolver( val baseItem = queueEntry.baseItem if (baseItem == null || baseItem.type != BaseItemKind.AUDIO) return null - val mediaInfo = getPlaybackInfo(baseItem) + val mediaInfo = getPlaybackInfo(baseItem, queueEntry.mediaSourceId) val url = api.universalAudioApi.getUniversalAudioStreamUrl( itemId = baseItem.id, diff --git a/playback/jellyfin/src/main/kotlin/mediastream/VideoMediaStreamResolver.kt b/playback/jellyfin/src/main/kotlin/mediastream/VideoMediaStreamResolver.kt index 2a28d53712..05717236fc 100644 --- a/playback/jellyfin/src/main/kotlin/mediastream/VideoMediaStreamResolver.kt +++ b/playback/jellyfin/src/main/kotlin/mediastream/VideoMediaStreamResolver.kt @@ -8,6 +8,7 @@ import org.jellyfin.playback.core.mediastream.PlayableMediaStream import org.jellyfin.playback.core.queue.QueueEntry import org.jellyfin.playback.core.support.PlaySupportReport import org.jellyfin.playback.jellyfin.queue.baseItem +import org.jellyfin.playback.jellyfin.queue.mediaSourceId import org.jellyfin.sdk.api.client.ApiClient import org.jellyfin.sdk.api.client.extensions.dynamicHlsApi import org.jellyfin.sdk.api.client.extensions.videosApi @@ -54,7 +55,7 @@ class VideoMediaStreamResolver( val baseItem = queueEntry.baseItem if (baseItem == null || baseItem.mediaType != MediaType.Video) return null - val mediaInfo = getPlaybackInfo(baseItem) + val mediaInfo = getPlaybackInfo(baseItem, queueEntry.mediaSourceId) // Test for direct play support val directPlayStream = mediaInfo.getDirectPlayStream() diff --git a/playback/jellyfin/src/main/kotlin/queue/mediaSourceIdElement.kt b/playback/jellyfin/src/main/kotlin/queue/mediaSourceIdElement.kt new file mode 100644 index 0000000000..a3c1b68e8b --- /dev/null +++ b/playback/jellyfin/src/main/kotlin/queue/mediaSourceIdElement.kt @@ -0,0 +1,13 @@ +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.queue.QueueEntry + +private val mediaSourceIdKey = ElementKey("MediaSource") + +/** + * Get or set the id of the MediaSource to use during playback. Or null for the default selection + * behavior. + */ +var QueueEntry.mediaSourceId by element(mediaSourceIdKey)