diff --git a/CHANGELOG.md b/CHANGELOG.md index b5a162ca34..05c2f37df3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,11 @@ The format is a modified version of [Keep a Changelog](https://keepachangelog.co - `Other` - for technical stuff. ## [Unreleased] +### Improved +- Don't start playing until external tracks are loaded and ready ([@Secozzi](https://github.com/Secozzi)) ([#160](https://github.com/quickdesh/Animiru/pull/160)) + +### Fixed +- Fix tracks not being selected when switching episodes ([@Secozzi](https://github.com/Secozzi)) ([#160](https://github.com/quickdesh/Animiru/pull/160)) ## [v0.19.7.5] - 2026-06-08 ### Improved diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/player/PlayerActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/player/PlayerActivity.kt index 1c3f381e17..60002b0ea3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/player/PlayerActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/player/PlayerActivity.kt @@ -943,7 +943,12 @@ class PlayerActivity : BaseActivity() { } } - val videoOptions = video.mpvArgs.joinToString(",") { (option, value) -> + // We handle selecting these in the viewmodel + val mpvOpts = listOf( + Pair("sid", "no"), + Pair("aid", "no"), + ) + val videoOptions = (video.mpvArgs + mpvOpts).joinToString(",") { (option, value) -> "$option=\"$value\"" } @@ -1112,8 +1117,7 @@ class PlayerActivity : BaseActivity() { setMpvMediaTitle() setupPlayerOrientation() setupChapters() - viewModel.setPausedState() - viewModel.updateIsLoadingEpisode(false) + viewModel.checkFileLoaded() // aniSkip stuff viewModel.viewModelScope.launchIO { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/player/PlayerViewModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/player/PlayerViewModel.kt index 935771b730..9d23076d5c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/player/PlayerViewModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/player/PlayerViewModel.kt @@ -217,6 +217,8 @@ class PlayerViewModel @JvmOverloads constructor( val isLoading = MutableStateFlow(true) val hasLoadedTracks = MutableStateFlow(false) + val hasLoadedSubs = MutableStateFlow(false) + val hasLoadedAudio = MutableStateFlow(false) private val _externalSubtitleTracks = MutableStateFlow>(emptyList()) val externalSubtitleTracks = _externalSubtitleTracks.asStateFlow() @@ -485,6 +487,8 @@ class PlayerViewModel @JvmOverloads constructor( updateSubtitleTrackAt(idx) { it.copy(id = track.id, state = TrackState.Loaded) } + hasLoadedSubs.update { _ -> true } + checkFileLoaded() selectSubById(track.id) } @@ -500,6 +504,8 @@ class PlayerViewModel @JvmOverloads constructor( updateAudioTrackAt(idx) { it.copy(id = track.id, state = TrackState.Loaded) } + hasLoadedAudio.update { _ -> true } + checkFileLoaded() selectAudioById(track.id, false) } } @@ -522,16 +528,20 @@ class PlayerViewModel @JvmOverloads constructor( tracks = embeddedSubs.map { VideoTrack.Internal(it) } + externalSubs, subtitle = true, ) - preferredSubtitle?.let { - selectSub(it) + if (preferredSubtitle == null) { + hasLoadedSubs.update { _ -> true } + } else { + selectSub(preferredSubtitle) } val preferredAudio = trackSelect.getPreferredTrackIndex( tracks = embeddedAudio.map { VideoTrack.Internal(it) } + externalAudio, subtitle = false, ) - preferredAudio?.let { - selectAudio(it, true) + if (preferredAudio == null) { + hasLoadedAudio.update { _ -> true } + } else { + selectAudio(preferredAudio, true) } } @@ -577,10 +587,14 @@ class PlayerViewModel @JvmOverloads constructor( ) } } else { + hasLoadedSubs.update { _ -> true } + checkFileLoaded() selectSubById(track.id) } } is VideoTrack.Internal -> { + hasLoadedSubs.update { _ -> true } + checkFileLoaded() selectSubById(track.data.id) } } @@ -602,10 +616,14 @@ class PlayerViewModel @JvmOverloads constructor( ) } } else { + hasLoadedAudio.update { _ -> true } + checkFileLoaded() selectAudioById(track.id, force) } } is VideoTrack.Internal -> { + hasLoadedAudio.update { _ -> true } + checkFileLoaded() selectAudioById(track.data.id, force) } } @@ -619,6 +637,8 @@ class PlayerViewModel @JvmOverloads constructor( updateSubtitleTrackAt(subtitleIdx) { it.copy(state = TrackState.Error) } + hasLoadedSubs.update { _ -> true } + checkFileLoaded() } val audioIdx = externalAudioTracks.value.indexOfFirst { it.data.url == url @@ -627,6 +647,8 @@ class PlayerViewModel @JvmOverloads constructor( updateAudioTrackAt(audioIdx) { it.copy(state = TrackState.Error) } + hasLoadedAudio.update { _ -> true } + checkFileLoaded() } } @@ -717,14 +739,22 @@ class PlayerViewModel @JvmOverloads constructor( } } - fun setPausedState() { - pausedState.value?.let { - if (it) { - pause() - } else { - unpause() + /** + * Check when file has loaded and see if the player can be (un)paused. + * + * If external subs/audio tracks was selected, wait until mpv has fetched them. + */ + fun checkFileLoaded() { + if (isLoadingEpisode.value && hasLoadedSubs.value && hasLoadedAudio.value) { + _isLoadingEpisode.update { _ -> false } + pausedState.value?.let { + if (it) { + pause() + } else { + unpause() + } + _pausedState.update { _ -> null } } - _pausedState.update { _ -> null } } }