Remember playback choices & fix some track selection issues (#26)

Remembers changes in playback tracks across playbacks. So, if you change
the audio track, quit the app, and return to the same id, the app will
play the audio track previously chosen.

Additionally, this PR fixes a UI inconsistency when there are multiple
versions of a item. Previously sometimes the audio/subtitle tracks for
wrong version would be shown during playback.
This commit is contained in:
damontecres 2025-10-17 17:19:44 -04:00 committed by GitHub
parent f220aeee44
commit 6194eba8c5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
31 changed files with 1152 additions and 154 deletions

View file

@ -1,6 +1,10 @@
package com.github.damontecres.wholphin.util
import android.os.Build
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import com.github.damontecres.wholphin.R
import com.github.damontecres.wholphin.data.ChosenStreams
import com.github.damontecres.wholphin.ui.isNotNullOrBlank
import org.jellyfin.sdk.model.api.BaseItemDto
import org.jellyfin.sdk.model.api.MediaStream
@ -60,3 +64,25 @@ fun formatSubtitleLang(mediaStreams: List<MediaStream>?): String? =
?.mapNotNull { it.language }
?.distinct()
?.joinToString(", ") { languageName(it) }
fun getAudioDisplay(
item: BaseItemDto,
chosenStreams: ChosenStreams?,
) = (
chosenStreams?.audioStream
?: item.mediaStreams?.firstOrNull { it.type == MediaStreamType.AUDIO }
)?.displayTitle
?.replace(" - Default", "")
?.ifBlank { null }
@Composable
fun getSubtitleDisplay(
item: BaseItemDto,
chosenStreams: ChosenStreams?,
) = if (chosenStreams?.subtitlesDisabled == true) {
stringResource(R.string.disabled)
} else if (chosenStreams?.subtitleStream != null) {
languageName(chosenStreams.subtitleStream.language)
} else {
formatSubtitleLang(item.mediaStreams)
}

View file

@ -3,6 +3,7 @@ package com.github.damontecres.wholphin.util
import androidx.annotation.OptIn
import androidx.media3.common.Player
import androidx.media3.common.util.UnstableApi
import com.github.damontecres.wholphin.data.model.ItemPlayback
import com.github.damontecres.wholphin.ui.playback.CurrentPlayback
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@ -32,6 +33,7 @@ class TrackActivityPlaybackListener(
private val api: ApiClient,
private val player: Player,
var playback: CurrentPlayback,
var itemPlayback: ItemPlayback,
) : Player.Listener {
private val coroutineScope = CoroutineScope(Dispatchers.Main)
private val task: TimerTask
@ -46,14 +48,14 @@ class TrackActivityPlaybackListener(
api.playStateApi.reportPlaybackStart(
PlaybackStartInfo(
canSeek = true,
itemId = playback.itemId,
itemId = itemPlayback.itemId,
isPaused = withContext(Dispatchers.Main) { !player.isPlaying },
playMethod = playback.playMethod,
repeatMode = RepeatMode.REPEAT_NONE,
playbackOrder = PlaybackOrder.DEFAULT,
isMuted = false,
audioStreamIndex = playback.audioIndex,
subtitleStreamIndex = playback.subtitleIndex,
audioStreamIndex = itemPlayback.audioIndex.takeIf { itemPlayback.audioIndexEnabled },
subtitleStreamIndex = itemPlayback.subtitleIndex.takeIf { itemPlayback.subtitleIndexEnabled },
),
)
}
@ -93,7 +95,7 @@ class TrackActivityPlaybackListener(
coroutineScope.launch(Dispatchers.IO + ExceptionHandler()) {
api.playStateApi.reportPlaybackStopped(
PlaybackStopInfo(
itemId = playback.itemId,
itemId = itemPlayback.itemId,
positionTicks = withContext(Dispatchers.Main) { player.currentPosition.milliseconds.inWholeTicks },
failed = false,
playSessionId = playback.playSessionId,
@ -130,7 +132,7 @@ class TrackActivityPlaybackListener(
// Timber.v("saveActivity: itemId=$itemId, pos=$calcPosition")
api.playStateApi.reportPlaybackProgress(
PlaybackProgressInfo(
itemId = playback.itemId,
itemId = itemPlayback.itemId,
positionTicks = calcPosition.inWholeTicks,
canSeek = true,
isPaused = withContext(Dispatchers.Main) { !player.isPlaying },
@ -139,8 +141,8 @@ class TrackActivityPlaybackListener(
repeatMode = RepeatMode.REPEAT_NONE,
playbackOrder = PlaybackOrder.DEFAULT,
playSessionId = playback.playSessionId,
audioStreamIndex = playback.audioIndex,
subtitleStreamIndex = playback.subtitleIndex,
audioStreamIndex = itemPlayback.audioIndex.takeIf { itemPlayback.audioIndexEnabled },
subtitleStreamIndex = itemPlayback.subtitleIndex.takeIf { itemPlayback.subtitleIndexEnabled },
),
)
}