mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-07-09 16:11:20 +02:00
Persist audio & subtitle track changes for series if in different language (#405)
This only applies if the user has set a preferred audio and/or subtitle language on the web UI! If the user chooses an audio/subtitle track that is a different language than their preferred, it will be remembered for that series. Playback of future episodes of the series will pick a matching language. The audio & subtitle selections are independent. You can make the choice before playback or during playback. Closes #378
This commit is contained in:
parent
033bdccaa2
commit
0f4254c6ec
21 changed files with 990 additions and 324 deletions
|
|
@ -9,6 +9,7 @@ import androidx.compose.foundation.layout.padding
|
|||
import androidx.compose.foundation.layout.widthIn
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.NonRestartableComposable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
|
|
@ -26,12 +27,8 @@ import androidx.tv.material3.MaterialTheme
|
|||
import androidx.tv.material3.ProvideTextStyle
|
||||
import androidx.tv.material3.Text
|
||||
import com.github.damontecres.wholphin.R
|
||||
import com.github.damontecres.wholphin.data.model.ItemPlayback
|
||||
import com.github.damontecres.wholphin.data.model.TrackIndex
|
||||
import com.github.damontecres.wholphin.data.model.chooseSource
|
||||
import com.github.damontecres.wholphin.data.model.chooseStream
|
||||
import com.github.damontecres.wholphin.data.ChosenStreams
|
||||
import com.github.damontecres.wholphin.preferences.AppThemeColors
|
||||
import com.github.damontecres.wholphin.preferences.UserPreferences
|
||||
import com.github.damontecres.wholphin.ui.FontAwesome
|
||||
import com.github.damontecres.wholphin.ui.PreviewTvSpec
|
||||
import com.github.damontecres.wholphin.ui.playback.audioStreamCount
|
||||
|
|
@ -40,16 +37,30 @@ import com.github.damontecres.wholphin.ui.playback.externalSubtitlesCount
|
|||
import com.github.damontecres.wholphin.ui.theme.WholphinTheme
|
||||
import com.github.damontecres.wholphin.util.languageName
|
||||
import com.github.damontecres.wholphin.util.profile.Codec
|
||||
import org.jellyfin.sdk.model.api.BaseItemDto
|
||||
import org.jellyfin.sdk.model.api.MediaStreamType
|
||||
import org.jellyfin.sdk.model.api.MediaSourceInfo
|
||||
import org.jellyfin.sdk.model.api.MediaStream
|
||||
import org.jellyfin.sdk.model.api.VideoRange
|
||||
import org.jellyfin.sdk.model.api.VideoRangeType
|
||||
|
||||
@Composable
|
||||
@NonRestartableComposable
|
||||
fun VideoStreamDetails(
|
||||
preferences: UserPreferences,
|
||||
dto: BaseItemDto,
|
||||
itemPlayback: ItemPlayback?,
|
||||
chosenStreams: ChosenStreams?,
|
||||
modifier: Modifier = Modifier,
|
||||
) = VideoStreamDetails(
|
||||
chosenStreams?.source,
|
||||
chosenStreams?.videoStream,
|
||||
chosenStreams?.audioStream,
|
||||
chosenStreams?.subtitleStream,
|
||||
modifier,
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun VideoStreamDetails(
|
||||
source: MediaSourceInfo?,
|
||||
videoStream: MediaStream?,
|
||||
audioStream: MediaStream?,
|
||||
subtitleStream: MediaStream?,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
|
|
@ -57,17 +68,6 @@ fun VideoStreamDetails(
|
|||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
modifier = modifier,
|
||||
) {
|
||||
val source = remember(dto, itemPlayback) { chooseSource(dto, itemPlayback) }
|
||||
|
||||
val videoStream =
|
||||
remember(dto, itemPlayback) {
|
||||
chooseStream(
|
||||
dto,
|
||||
itemPlayback,
|
||||
MediaStreamType.VIDEO,
|
||||
preferences,
|
||||
)
|
||||
}
|
||||
val video =
|
||||
remember(videoStream) {
|
||||
videoStream
|
||||
|
|
@ -95,15 +95,6 @@ fun VideoStreamDetails(
|
|||
StreamLabel(it)
|
||||
}
|
||||
|
||||
val audioStream =
|
||||
remember(dto, itemPlayback) {
|
||||
chooseStream(
|
||||
dto,
|
||||
itemPlayback,
|
||||
MediaStreamType.AUDIO,
|
||||
preferences,
|
||||
)
|
||||
}
|
||||
val audioCount = remember(source) { source?.audioStreamCount ?: 0 }
|
||||
val audio =
|
||||
remember(audioCount, audioStream) {
|
||||
|
|
@ -124,23 +115,14 @@ fun VideoStreamDetails(
|
|||
modifier = Modifier.widthIn(max = 200.dp),
|
||||
)
|
||||
|
||||
val subtitleStream =
|
||||
remember(dto, itemPlayback) {
|
||||
chooseStream(
|
||||
dto,
|
||||
itemPlayback,
|
||||
MediaStreamType.SUBTITLE,
|
||||
preferences,
|
||||
)
|
||||
}
|
||||
val subtitleCount =
|
||||
remember(source) {
|
||||
(source?.embeddedSubtitleCount ?: 0) + (source?.externalSubtitlesCount ?: 0)
|
||||
}
|
||||
var disabled by remember { mutableStateOf(false) }
|
||||
val subtitle =
|
||||
remember(subtitleCount, subtitleStream, itemPlayback) {
|
||||
if (itemPlayback?.subtitleIndex == TrackIndex.DISABLED) {
|
||||
remember(subtitleCount, subtitleStream) {
|
||||
if (subtitleCount > 0 && subtitleStream == null) {
|
||||
disabled = true
|
||||
context.getString(R.string.disabled)
|
||||
} else if (subtitleCount == 0 || subtitleStream == null) {
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ import androidx.lifecycle.compose.LifecycleStartEffect
|
|||
import com.github.damontecres.wholphin.R
|
||||
import com.github.damontecres.wholphin.data.ChosenStreams
|
||||
import com.github.damontecres.wholphin.data.model.BaseItem
|
||||
import com.github.damontecres.wholphin.data.model.chooseSource
|
||||
import com.github.damontecres.wholphin.preferences.UserPreferences
|
||||
import com.github.damontecres.wholphin.ui.components.DetailsBackdropImage
|
||||
import com.github.damontecres.wholphin.ui.components.DialogParams
|
||||
|
|
@ -57,6 +56,7 @@ import kotlinx.coroutines.launch
|
|||
import org.jellyfin.sdk.model.api.MediaType
|
||||
import org.jellyfin.sdk.model.extensions.ticks
|
||||
import org.jellyfin.sdk.model.serializer.toUUID
|
||||
import org.jellyfin.sdk.model.serializer.toUUIDOrNull
|
||||
import java.util.UUID
|
||||
import kotlin.time.Duration
|
||||
|
||||
|
|
@ -157,7 +157,7 @@ fun EpisodeDetails(
|
|||
watched = ep.data.userData?.played ?: false,
|
||||
favorite = ep.data.userData?.isFavorite ?: false,
|
||||
seriesId = ep.data.seriesId,
|
||||
sourceId = chosenStreams?.sourceId,
|
||||
sourceId = chosenStreams?.source?.id?.toUUIDOrNull(),
|
||||
actions = moreActions,
|
||||
onChooseVersion = {
|
||||
chooseVersion =
|
||||
|
|
@ -174,25 +174,26 @@ fun EpisodeDetails(
|
|||
moreDialog = null
|
||||
},
|
||||
onChooseTracks = { type ->
|
||||
chooseSource(
|
||||
ep.data,
|
||||
chosenStreams?.itemPlayback,
|
||||
)?.let { source ->
|
||||
chooseVersion =
|
||||
chooseStream(
|
||||
context = context,
|
||||
streams = source.mediaStreams.orEmpty(),
|
||||
type = type,
|
||||
onClick = { trackIndex ->
|
||||
viewModel.saveTrackSelection(
|
||||
ep,
|
||||
chosenStreams?.itemPlayback,
|
||||
trackIndex,
|
||||
type,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
viewModel.streamChoiceService
|
||||
.chooseSource(
|
||||
ep.data,
|
||||
chosenStreams?.itemPlayback,
|
||||
)?.let { source ->
|
||||
chooseVersion =
|
||||
chooseStream(
|
||||
context = context,
|
||||
streams = source.mediaStreams.orEmpty(),
|
||||
type = type,
|
||||
onClick = { trackIndex ->
|
||||
viewModel.saveTrackSelection(
|
||||
ep,
|
||||
chosenStreams?.itemPlayback,
|
||||
trackIndex,
|
||||
type,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
},
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -58,9 +58,7 @@ fun EpisodeDetailsHeader(
|
|||
EpisodeQuickDetails(dto)
|
||||
|
||||
VideoStreamDetails(
|
||||
preferences = preferences,
|
||||
dto = dto,
|
||||
itemPlayback = chosenStreams?.itemPlayback,
|
||||
chosenStreams = chosenStreams,
|
||||
modifier = Modifier.padding(bottom = padding),
|
||||
)
|
||||
dto.taglines?.firstOrNull()?.let { tagline ->
|
||||
|
|
|
|||
|
|
@ -12,7 +12,9 @@ import com.github.damontecres.wholphin.data.model.ItemPlayback
|
|||
import com.github.damontecres.wholphin.preferences.ThemeSongVolume
|
||||
import com.github.damontecres.wholphin.services.FavoriteWatchManager
|
||||
import com.github.damontecres.wholphin.services.NavigationManager
|
||||
import com.github.damontecres.wholphin.services.StreamChoiceService
|
||||
import com.github.damontecres.wholphin.services.ThemeSongPlayer
|
||||
import com.github.damontecres.wholphin.services.UserPreferencesService
|
||||
import com.github.damontecres.wholphin.ui.launchIO
|
||||
import com.github.damontecres.wholphin.ui.nav.Destination
|
||||
import com.github.damontecres.wholphin.ui.setValueOnMain
|
||||
|
|
@ -44,8 +46,10 @@ class EpisodeViewModel
|
|||
private val navigationManager: NavigationManager,
|
||||
val serverRepository: ServerRepository,
|
||||
val itemPlaybackRepository: ItemPlaybackRepository,
|
||||
val streamChoiceService: StreamChoiceService,
|
||||
private val themeSongPlayer: ThemeSongPlayer,
|
||||
private val favoriteWatchManager: FavoriteWatchManager,
|
||||
private val userPreferencesService: UserPreferencesService,
|
||||
@Assisted val itemId: UUID,
|
||||
) : ViewModel() {
|
||||
@AssistedFactory
|
||||
|
|
@ -85,8 +89,9 @@ class EpisodeViewModel
|
|||
"Error fetching movie",
|
||||
),
|
||||
) {
|
||||
val prefs = userPreferencesService.getCurrent()
|
||||
val item = fetchAndSetItem().await()
|
||||
val result = itemPlaybackRepository.getSelectedTracks(item.id, item)
|
||||
val result = itemPlaybackRepository.getSelectedTracks(item.id, item, prefs)
|
||||
withContext(Dispatchers.Main) {
|
||||
this@EpisodeViewModel.item.value = item
|
||||
chosenStreams.value = result
|
||||
|
|
@ -115,10 +120,12 @@ class EpisodeViewModel
|
|||
sourceId: UUID,
|
||||
) {
|
||||
viewModelScope.launchIO {
|
||||
val prefs = userPreferencesService.getCurrent()
|
||||
val plc = streamChoiceService.getPlaybackLanguageChoice(item.data)
|
||||
val result = itemPlaybackRepository.savePlayVersion(item.id, sourceId)
|
||||
val chosen =
|
||||
result?.let {
|
||||
itemPlaybackRepository.getChosenItemFromPlayback(item, result)
|
||||
itemPlaybackRepository.getChosenItemFromPlayback(item, result, plc, prefs)
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
chosenStreams.value = chosen
|
||||
|
|
@ -133,6 +140,8 @@ class EpisodeViewModel
|
|||
type: MediaStreamType,
|
||||
) {
|
||||
viewModelScope.launchIO {
|
||||
val prefs = userPreferencesService.getCurrent()
|
||||
val plc = streamChoiceService.getPlaybackLanguageChoice(item.data)
|
||||
val result =
|
||||
itemPlaybackRepository.saveTrackSelection(
|
||||
item = item,
|
||||
|
|
@ -142,7 +151,7 @@ class EpisodeViewModel
|
|||
)
|
||||
val chosen =
|
||||
result?.let {
|
||||
itemPlaybackRepository.getChosenItemFromPlayback(item, result)
|
||||
itemPlaybackRepository.getChosenItemFromPlayback(item, result, plc, prefs)
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
chosenStreams.value = chosen
|
||||
|
|
|
|||
|
|
@ -45,7 +45,6 @@ import com.github.damontecres.wholphin.data.model.Person
|
|||
import com.github.damontecres.wholphin.data.model.RemoteTrailer
|
||||
import com.github.damontecres.wholphin.data.model.Trailer
|
||||
import com.github.damontecres.wholphin.data.model.aspectRatioFloat
|
||||
import com.github.damontecres.wholphin.data.model.chooseSource
|
||||
import com.github.damontecres.wholphin.preferences.UserPreferences
|
||||
import com.github.damontecres.wholphin.services.TrailerService
|
||||
import com.github.damontecres.wholphin.ui.AspectRatios
|
||||
|
|
@ -83,6 +82,7 @@ import org.jellyfin.sdk.model.api.BaseItemKind
|
|||
import org.jellyfin.sdk.model.api.MediaType
|
||||
import org.jellyfin.sdk.model.extensions.ticks
|
||||
import org.jellyfin.sdk.model.serializer.toUUID
|
||||
import org.jellyfin.sdk.model.serializer.toUUIDOrNull
|
||||
import java.util.UUID
|
||||
import kotlin.time.Duration
|
||||
|
||||
|
|
@ -204,7 +204,7 @@ fun MovieDetails(
|
|||
watched = movie.data.userData?.played ?: false,
|
||||
favorite = movie.data.userData?.isFavorite ?: false,
|
||||
seriesId = null,
|
||||
sourceId = chosenStreams?.sourceId,
|
||||
sourceId = chosenStreams?.source?.id?.toUUIDOrNull(),
|
||||
actions = moreActions,
|
||||
onChooseVersion = {
|
||||
chooseVersion =
|
||||
|
|
@ -221,25 +221,26 @@ fun MovieDetails(
|
|||
moreDialog = null
|
||||
},
|
||||
onChooseTracks = { type ->
|
||||
chooseSource(
|
||||
movie.data,
|
||||
chosenStreams?.itemPlayback,
|
||||
)?.let { source ->
|
||||
chooseVersion =
|
||||
chooseStream(
|
||||
context = context,
|
||||
streams = source.mediaStreams.orEmpty(),
|
||||
type = type,
|
||||
onClick = { trackIndex ->
|
||||
viewModel.saveTrackSelection(
|
||||
movie,
|
||||
chosenStreams?.itemPlayback,
|
||||
trackIndex,
|
||||
type,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
viewModel.streamChoiceService
|
||||
.chooseSource(
|
||||
movie.data,
|
||||
chosenStreams?.itemPlayback,
|
||||
)?.let { source ->
|
||||
chooseVersion =
|
||||
chooseStream(
|
||||
context = context,
|
||||
streams = source.mediaStreams.orEmpty(),
|
||||
type = type,
|
||||
onClick = { trackIndex ->
|
||||
viewModel.saveTrackSelection(
|
||||
movie,
|
||||
chosenStreams?.itemPlayback,
|
||||
trackIndex,
|
||||
type,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
},
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -72,9 +72,7 @@ fun MovieDetailsHeader(
|
|||
}
|
||||
|
||||
VideoStreamDetails(
|
||||
preferences = preferences,
|
||||
dto = dto,
|
||||
itemPlayback = chosenStreams?.itemPlayback,
|
||||
chosenStreams = chosenStreams,
|
||||
modifier = Modifier.padding(bottom = padding),
|
||||
)
|
||||
dto.taglines?.firstOrNull()?.let { tagline ->
|
||||
|
|
|
|||
|
|
@ -18,8 +18,10 @@ import com.github.damontecres.wholphin.services.ExtrasService
|
|||
import com.github.damontecres.wholphin.services.FavoriteWatchManager
|
||||
import com.github.damontecres.wholphin.services.NavigationManager
|
||||
import com.github.damontecres.wholphin.services.PeopleFavorites
|
||||
import com.github.damontecres.wholphin.services.StreamChoiceService
|
||||
import com.github.damontecres.wholphin.services.ThemeSongPlayer
|
||||
import com.github.damontecres.wholphin.services.TrailerService
|
||||
import com.github.damontecres.wholphin.services.UserPreferencesService
|
||||
import com.github.damontecres.wholphin.ui.SlimItemFields
|
||||
import com.github.damontecres.wholphin.ui.launchIO
|
||||
import com.github.damontecres.wholphin.ui.nav.Destination
|
||||
|
|
@ -54,11 +56,13 @@ class MovieViewModel
|
|||
private val navigationManager: NavigationManager,
|
||||
val serverRepository: ServerRepository,
|
||||
val itemPlaybackRepository: ItemPlaybackRepository,
|
||||
val streamChoiceService: StreamChoiceService,
|
||||
private val themeSongPlayer: ThemeSongPlayer,
|
||||
private val favoriteWatchManager: FavoriteWatchManager,
|
||||
private val peopleFavorites: PeopleFavorites,
|
||||
private val trailerService: TrailerService,
|
||||
private val extrasService: ExtrasService,
|
||||
private val userPreferencesService: UserPreferencesService,
|
||||
@Assisted val itemId: UUID,
|
||||
) : ViewModel() {
|
||||
@AssistedFactory
|
||||
|
|
@ -104,7 +108,12 @@ class MovieViewModel
|
|||
),
|
||||
) {
|
||||
val item = fetchAndSetItem().await()
|
||||
val result = itemPlaybackRepository.getSelectedTracks(item.id, item)
|
||||
val result =
|
||||
itemPlaybackRepository.getSelectedTracks(
|
||||
item.id,
|
||||
item,
|
||||
userPreferencesService.getCurrent(),
|
||||
)
|
||||
withContext(Dispatchers.Main) {
|
||||
this@MovieViewModel.item.value = item
|
||||
chosenStreams.value = result
|
||||
|
|
@ -172,10 +181,12 @@ class MovieViewModel
|
|||
sourceId: UUID,
|
||||
) {
|
||||
viewModelScope.launchIO {
|
||||
val prefs = userPreferencesService.getCurrent()
|
||||
val plc = streamChoiceService.getPlaybackLanguageChoice(item.data)
|
||||
val result = itemPlaybackRepository.savePlayVersion(item.id, sourceId)
|
||||
val chosen =
|
||||
result?.let {
|
||||
itemPlaybackRepository.getChosenItemFromPlayback(item, result)
|
||||
itemPlaybackRepository.getChosenItemFromPlayback(item, result, plc, prefs)
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
chosenStreams.value = chosen
|
||||
|
|
@ -190,6 +201,8 @@ class MovieViewModel
|
|||
type: MediaStreamType,
|
||||
) {
|
||||
viewModelScope.launchIO {
|
||||
val prefs = userPreferencesService.getCurrent()
|
||||
val plc = streamChoiceService.getPlaybackLanguageChoice(item.data)
|
||||
val result =
|
||||
itemPlaybackRepository.saveTrackSelection(
|
||||
item = item,
|
||||
|
|
@ -199,7 +212,7 @@ class MovieViewModel
|
|||
)
|
||||
val chosen =
|
||||
result?.let {
|
||||
itemPlaybackRepository.getChosenItemFromPlayback(item, result)
|
||||
itemPlaybackRepository.getChosenItemFromPlayback(item, result, plc, prefs)
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
chosenStreams.value = chosen
|
||||
|
|
|
|||
|
|
@ -37,9 +37,7 @@ fun FocusedEpisodeHeader(
|
|||
|
||||
if (dto != null) {
|
||||
VideoStreamDetails(
|
||||
preferences = preferences,
|
||||
dto = dto,
|
||||
itemPlayback = chosenStreams?.itemPlayback,
|
||||
chosenStreams = chosenStreams,
|
||||
modifier = Modifier,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ import androidx.lifecycle.compose.LifecycleStartEffect
|
|||
import androidx.lifecycle.map
|
||||
import com.github.damontecres.wholphin.R
|
||||
import com.github.damontecres.wholphin.data.model.BaseItem
|
||||
import com.github.damontecres.wholphin.data.model.chooseSource
|
||||
import com.github.damontecres.wholphin.preferences.UserPreferences
|
||||
import com.github.damontecres.wholphin.ui.OneTimeLaunchedEffect
|
||||
import com.github.damontecres.wholphin.ui.components.DialogParams
|
||||
|
|
@ -53,6 +52,7 @@ import org.jellyfin.sdk.model.api.PersonKind
|
|||
import org.jellyfin.sdk.model.extensions.ticks
|
||||
import org.jellyfin.sdk.model.serializer.UUIDSerializer
|
||||
import org.jellyfin.sdk.model.serializer.toUUID
|
||||
import org.jellyfin.sdk.model.serializer.toUUIDOrNull
|
||||
import timber.log.Timber
|
||||
import java.util.UUID
|
||||
import kotlin.time.Duration
|
||||
|
|
@ -219,7 +219,7 @@ fun SeriesOverview(
|
|||
watched = ep.data.userData?.played ?: false,
|
||||
favorite = ep.data.userData?.isFavorite ?: false,
|
||||
seriesId = series.id,
|
||||
sourceId = chosenStreams?.sourceId,
|
||||
sourceId = chosenStreams?.source?.id?.toUUIDOrNull(),
|
||||
actions =
|
||||
MoreDialogActions(
|
||||
navigateTo = viewModel::navigateTo,
|
||||
|
|
@ -257,25 +257,26 @@ fun SeriesOverview(
|
|||
moreDialog = null
|
||||
},
|
||||
onChooseTracks = { type ->
|
||||
chooseSource(
|
||||
ep.data,
|
||||
chosenStreams?.itemPlayback,
|
||||
)?.let { source ->
|
||||
chooseVersion =
|
||||
chooseStream(
|
||||
context = context,
|
||||
streams = source.mediaStreams.orEmpty(),
|
||||
type = type,
|
||||
onClick = { trackIndex ->
|
||||
viewModel.saveTrackSelection(
|
||||
ep,
|
||||
chosenStreams?.itemPlayback,
|
||||
trackIndex,
|
||||
type,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
viewModel.streamChoiceService
|
||||
.chooseSource(
|
||||
ep.data,
|
||||
chosenStreams?.itemPlayback,
|
||||
)?.let { source ->
|
||||
chooseVersion =
|
||||
chooseStream(
|
||||
context = context,
|
||||
streams = source.mediaStreams.orEmpty(),
|
||||
type = type,
|
||||
onClick = { trackIndex ->
|
||||
viewModel.saveTrackSelection(
|
||||
ep,
|
||||
chosenStreams?.itemPlayback,
|
||||
trackIndex,
|
||||
type,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
},
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -18,8 +18,10 @@ import com.github.damontecres.wholphin.services.ExtrasService
|
|||
import com.github.damontecres.wholphin.services.FavoriteWatchManager
|
||||
import com.github.damontecres.wholphin.services.NavigationManager
|
||||
import com.github.damontecres.wholphin.services.PeopleFavorites
|
||||
import com.github.damontecres.wholphin.services.StreamChoiceService
|
||||
import com.github.damontecres.wholphin.services.ThemeSongPlayer
|
||||
import com.github.damontecres.wholphin.services.TrailerService
|
||||
import com.github.damontecres.wholphin.services.UserPreferencesService
|
||||
import com.github.damontecres.wholphin.ui.SlimItemFields
|
||||
import com.github.damontecres.wholphin.ui.detail.ItemViewModel
|
||||
import com.github.damontecres.wholphin.ui.equalsNotNull
|
||||
|
|
@ -70,6 +72,8 @@ class SeriesViewModel
|
|||
private val peopleFavorites: PeopleFavorites,
|
||||
private val trailerService: TrailerService,
|
||||
private val extrasService: ExtrasService,
|
||||
val streamChoiceService: StreamChoiceService,
|
||||
private val userPreferencesService: UserPreferencesService,
|
||||
) : ItemViewModel(api) {
|
||||
private lateinit var seriesId: UUID
|
||||
private lateinit var prefs: UserPreferences
|
||||
|
|
@ -372,7 +376,12 @@ class SeriesViewModel
|
|||
chosenStreamsJob?.cancel()
|
||||
chosenStreamsJob =
|
||||
viewModelScope.launchIO {
|
||||
val result = itemPlaybackRepository.getSelectedTracks(itemId, item)
|
||||
val result =
|
||||
itemPlaybackRepository.getSelectedTracks(
|
||||
itemId,
|
||||
item,
|
||||
userPreferencesService.getCurrent(),
|
||||
)
|
||||
withContext(Dispatchers.Main) {
|
||||
chosenStreams.value = result
|
||||
}
|
||||
|
|
@ -384,10 +393,12 @@ class SeriesViewModel
|
|||
sourceId: UUID,
|
||||
) {
|
||||
viewModelScope.launchIO {
|
||||
val prefs = userPreferencesService.getCurrent()
|
||||
val plc = streamChoiceService.getPlaybackLanguageChoice(item.data)
|
||||
val result = itemPlaybackRepository.savePlayVersion(item.id, sourceId)
|
||||
val chosen =
|
||||
result?.let {
|
||||
itemPlaybackRepository.getChosenItemFromPlayback(item, result)
|
||||
itemPlaybackRepository.getChosenItemFromPlayback(item, result, plc, prefs)
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
chosenStreams.value = chosen
|
||||
|
|
@ -402,6 +413,8 @@ class SeriesViewModel
|
|||
type: MediaStreamType,
|
||||
) {
|
||||
viewModelScope.launchIO {
|
||||
val prefs = userPreferencesService.getCurrent()
|
||||
val plc = streamChoiceService.getPlaybackLanguageChoice(item.data)
|
||||
val result =
|
||||
itemPlaybackRepository.saveTrackSelection(
|
||||
item = item,
|
||||
|
|
@ -411,7 +424,7 @@ class SeriesViewModel
|
|||
)
|
||||
val chosen =
|
||||
result?.let {
|
||||
itemPlaybackRepository.getChosenItemFromPlayback(item, result)
|
||||
itemPlaybackRepository.getChosenItemFromPlayback(item, result, plc, prefs)
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
chosenStreams.value = chosen
|
||||
|
|
|
|||
|
|
@ -29,8 +29,6 @@ import com.github.damontecres.wholphin.data.model.Chapter
|
|||
import com.github.damontecres.wholphin.data.model.ItemPlayback
|
||||
import com.github.damontecres.wholphin.data.model.Playlist
|
||||
import com.github.damontecres.wholphin.data.model.TrackIndex
|
||||
import com.github.damontecres.wholphin.data.model.chooseSource
|
||||
import com.github.damontecres.wholphin.data.model.chooseStream
|
||||
import com.github.damontecres.wholphin.preferences.AppPreference
|
||||
import com.github.damontecres.wholphin.preferences.PlayerBackend
|
||||
import com.github.damontecres.wholphin.preferences.ShowNextUpWhen
|
||||
|
|
@ -43,6 +41,7 @@ import com.github.damontecres.wholphin.services.PlayerFactory
|
|||
import com.github.damontecres.wholphin.services.PlaylistCreationResult
|
||||
import com.github.damontecres.wholphin.services.PlaylistCreator
|
||||
import com.github.damontecres.wholphin.services.RefreshRateService
|
||||
import com.github.damontecres.wholphin.services.StreamChoiceService
|
||||
import com.github.damontecres.wholphin.ui.launchIO
|
||||
import com.github.damontecres.wholphin.ui.nav.Destination
|
||||
import com.github.damontecres.wholphin.ui.onMain
|
||||
|
|
@ -123,6 +122,7 @@ class PlaybackViewModel
|
|||
private val deviceInfo: DeviceInfo,
|
||||
private val deviceProfileService: DeviceProfileService,
|
||||
private val refreshRateService: RefreshRateService,
|
||||
val streamChoiceService: StreamChoiceService,
|
||||
) : ViewModel(),
|
||||
Player.Listener,
|
||||
AnalyticsListener {
|
||||
|
|
@ -338,7 +338,8 @@ class PlaybackViewModel
|
|||
}
|
||||
}
|
||||
}
|
||||
val mediaSource = chooseSource(base, playbackConfig)
|
||||
val mediaSource = streamChoiceService.chooseSource(base, playbackConfig)
|
||||
val plc = streamChoiceService.getPlaybackLanguageChoice(base)
|
||||
|
||||
if (mediaSource == null) {
|
||||
showToast(
|
||||
|
|
@ -362,12 +363,26 @@ class PlaybackViewModel
|
|||
.orEmpty()
|
||||
|
||||
val audioIndex =
|
||||
chooseStream(base, playbackConfig, MediaStreamType.AUDIO, preferences)
|
||||
?.index
|
||||
streamChoiceService
|
||||
.chooseStream(
|
||||
mediaSource,
|
||||
base.seriesId,
|
||||
playbackConfig,
|
||||
plc,
|
||||
MediaStreamType.AUDIO,
|
||||
preferences,
|
||||
)?.index
|
||||
|
||||
val subtitleIndex =
|
||||
chooseStream(base, playbackConfig, MediaStreamType.SUBTITLE, preferences)
|
||||
?.index
|
||||
streamChoiceService
|
||||
.chooseStream(
|
||||
mediaSource,
|
||||
base.seriesId,
|
||||
playbackConfig,
|
||||
plc,
|
||||
MediaStreamType.SUBTITLE,
|
||||
preferences,
|
||||
)?.index
|
||||
|
||||
Timber.d("Selected mediaSource=${mediaSource.id}, audioIndex=$audioIndex, subtitleIndex=$subtitleIndex")
|
||||
|
||||
|
|
@ -563,7 +578,7 @@ class PlaybackViewModel
|
|||
|
||||
else -> throw Exception("No supported playback method")
|
||||
}
|
||||
Timber.v("Playback decision: $transcodeType")
|
||||
Timber.i("Playback decision for $itemId: $transcodeType")
|
||||
|
||||
val externalSubtitleCount = source.externalSubtitlesCount
|
||||
|
||||
|
|
@ -605,21 +620,6 @@ class PlaybackViewModel
|
|||
liveStreamId = source.liveStreamId,
|
||||
mediaSourceInfo = source,
|
||||
)
|
||||
val itemPlayback =
|
||||
currentItemPlayback.copy(
|
||||
sourceId = source.id?.toUUIDOrNull(),
|
||||
audioIndex = audioIndex ?: TrackIndex.UNSPECIFIED,
|
||||
subtitleIndex = subtitleIndex ?: TrackIndex.DISABLED,
|
||||
)
|
||||
if (userInitiated) {
|
||||
viewModelScope.launchIO {
|
||||
Timber.v("Saving user initiated item playback: %s", itemPlayback)
|
||||
val updated = itemPlaybackRepository.saveItemPlayback(itemPlayback)
|
||||
withContext(Dispatchers.Main) {
|
||||
this@PlaybackViewModel.currentItemPlayback.value = updated
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (preferences.appPreferences.playbackPreferences.refreshRateSwitching) {
|
||||
source.mediaStreams?.firstOrNull { it.type == MediaStreamType.VIDEO }?.let {
|
||||
|
|
@ -638,14 +638,13 @@ class PlaybackViewModel
|
|||
api = api,
|
||||
player = player,
|
||||
playback = playback,
|
||||
itemPlayback = itemPlayback,
|
||||
itemPlayback = currentItemPlayback,
|
||||
)
|
||||
player.addListener(activityListener)
|
||||
this@PlaybackViewModel.activityListener = activityListener
|
||||
|
||||
loading.value = LoadingState.Success
|
||||
this@PlaybackViewModel.currentPlayback.update { playback }
|
||||
this@PlaybackViewModel.currentItemPlayback.value = itemPlayback
|
||||
player.setMediaItem(
|
||||
mediaItem,
|
||||
positionMs,
|
||||
|
|
@ -679,23 +678,41 @@ class PlaybackViewModel
|
|||
|
||||
fun changeAudioStream(index: Int) {
|
||||
viewModelScope.launchIO {
|
||||
Timber.d("Changing audio track to %s", index)
|
||||
val itemPlayback =
|
||||
itemPlaybackRepository.saveTrackSelection(
|
||||
item = item,
|
||||
itemPlayback = currentItemPlayback.value!!,
|
||||
trackIndex = index,
|
||||
type = MediaStreamType.AUDIO,
|
||||
)
|
||||
this@PlaybackViewModel.currentItemPlayback.setValueOnMain(itemPlayback)
|
||||
changeStreams(
|
||||
item,
|
||||
currentItemPlayback.value!!,
|
||||
itemPlayback,
|
||||
index,
|
||||
currentItemPlayback.value?.subtitleIndex,
|
||||
itemPlayback.subtitleIndex,
|
||||
onMain { player.currentPosition },
|
||||
true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun changeSubtitleStream(index: Int?): Job =
|
||||
fun changeSubtitleStream(index: Int): Job =
|
||||
viewModelScope.launchIO {
|
||||
Timber.d("Changing subtitle track to %s", index)
|
||||
val itemPlayback =
|
||||
itemPlaybackRepository.saveTrackSelection(
|
||||
item = item,
|
||||
itemPlayback = currentItemPlayback.value!!,
|
||||
trackIndex = index,
|
||||
type = MediaStreamType.SUBTITLE,
|
||||
)
|
||||
this@PlaybackViewModel.currentItemPlayback.setValueOnMain(itemPlayback)
|
||||
changeStreams(
|
||||
item,
|
||||
currentItemPlayback.value!!,
|
||||
currentItemPlayback.value?.audioIndex,
|
||||
itemPlayback,
|
||||
itemPlayback.audioIndex,
|
||||
index,
|
||||
onMain { player.currentPosition },
|
||||
true,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import androidx.lifecycle.viewModelScope
|
|||
import com.github.damontecres.wholphin.R
|
||||
import com.github.damontecres.wholphin.data.model.BaseItem
|
||||
import com.github.damontecres.wholphin.data.model.TrackIndex
|
||||
import com.github.damontecres.wholphin.data.model.chooseSource
|
||||
import com.github.damontecres.wholphin.ui.launchIO
|
||||
import com.github.damontecres.wholphin.ui.onMain
|
||||
import com.github.damontecres.wholphin.ui.setValueOnMain
|
||||
|
|
@ -101,7 +100,7 @@ fun PlaybackViewModel.downloadAndSwitchSubtitles(
|
|||
api.userLibraryApi.getItem(itemId = it.itemId).content,
|
||||
api,
|
||||
)
|
||||
val mediaSource = chooseSource(item.data, it)
|
||||
val mediaSource = streamChoiceService.chooseSource(item.data, it)
|
||||
if (mediaSource == null) {
|
||||
// This shouldn't happen, but just in case
|
||||
showToast(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue