Player: load media async and use playhead for initial episode

This commit is contained in:
Jannik 2022-01-29 19:56:39 +01:00
parent 1e54bc7983
commit f65497e06a
Signed by: Seil0
GPG Key ID: E8459F3723C52C24
2 changed files with 35 additions and 28 deletions

View File

@ -80,7 +80,7 @@ class PlayerActivity : AppCompatActivity() {
setContentView(R.layout.activity_player) setContentView(R.layout.activity_player)
hideBars() // Initial hide the bars hideBars() // Initial hide the bars
model.loadMedia( model.loadMediaAsync(
intent.getStringExtra(getString(R.string.intent_season_id)) ?: "", intent.getStringExtra(getString(R.string.intent_season_id)) ?: "",
intent.getStringExtra(getString(R.string.intent_episode_id)) ?: "" intent.getStringExtra(getString(R.string.intent_episode_id)) ?: ""
) )
@ -143,7 +143,7 @@ class PlayerActivity : AppCompatActivity() {
// when the intent changed, load the new media and play it // when the intent changed, load the new media and play it
intent?.let { intent?.let {
model.loadMedia( model.loadMediaAsync(
it.getStringExtra(getString(R.string.intent_season_id)) ?: "", it.getStringExtra(getString(R.string.intent_season_id)) ?: "",
it.getStringExtra(getString(R.string.intent_episode_id)) ?: "" it.getStringExtra(getString(R.string.intent_episode_id)) ?: ""
) )
@ -194,11 +194,6 @@ class PlayerActivity : AppCompatActivity() {
} }
private fun initPlayer() { private fun initPlayer() {
if (model.currentEpisode == NoneEpisode) {
Log.e(javaClass.name, "No media was set.")
this.finish()
}
initVideoView() initVideoView()
initTimeUpdates() initTimeUpdates()
@ -234,9 +229,10 @@ class PlayerActivity : AppCompatActivity() {
} }
} }
}) })
// revert back to the old behaviour (blocking init) in case there are any issues with async init
// start playing the current episode, after all needed player components have been initialized // start playing the current episode, after all needed player components have been initialized
model.playCurrentMedia() //model.playCurrentMedia(model.currentPlayhead)
} }
@SuppressLint("ClickableViewAccessibility") @SuppressLint("ClickableViewAccessibility")
@ -353,9 +349,16 @@ class PlayerActivity : AppCompatActivity() {
} }
/** /**
* update title text and next ep button visibility, set ignoreNextStateEnded * This methode is called, if the current episode has changed.
* Update title text and next ep button visibility.
* If the currentEpisode changed to NoneEpisode, exit the activity.
*/ */
private fun onMediaChanged() { private fun onMediaChanged() {
if (model.currentEpisode == NoneEpisode) {
Log.e(javaClass.name, "No media was set.")
this.finish()
}
exo_text_title.text = model.getMediaTitle() exo_text_title.text = model.getMediaTitle()
// hide the next episode button, if there is none // hide the next episode button, if there is none

View File

@ -36,6 +36,8 @@ import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector
import com.google.android.exoplayer2.source.hls.HlsMediaSource import com.google.android.exoplayer2.source.hls.HlsMediaSource
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory
import com.google.android.exoplayer2.util.Util import com.google.android.exoplayer2.util.Util
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.joinAll
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import org.mosad.teapod.R import org.mosad.teapod.R
@ -49,7 +51,6 @@ import org.mosad.teapod.util.Meta
import org.mosad.teapod.util.TVShowMeta import org.mosad.teapod.util.TVShowMeta
import org.mosad.teapod.util.tmdb.TMDBTVSeason import org.mosad.teapod.util.tmdb.TMDBTVSeason
import java.util.* import java.util.*
import kotlin.collections.ArrayList
/** /**
* PlayerViewModel handles all stuff related to media/episodes. * PlayerViewModel handles all stuff related to media/episodes.
@ -64,6 +65,7 @@ class PlayerViewModel(application: Application) : AndroidViewModel(application)
val currentEpisodeChangedListener = ArrayList<() -> Unit>() val currentEpisodeChangedListener = ArrayList<() -> Unit>()
private val preferredLanguage = if (Preferences.preferSecondary) Locale.JAPANESE else Locale.GERMAN private val preferredLanguage = if (Preferences.preferSecondary) Locale.JAPANESE else Locale.GERMAN
private var currentPlayhead: Long = 0
// tmdb/meta data TODO currently not implemented for cr // tmdb/meta data TODO currently not implemented for cr
var mediaMeta: Meta? = null var mediaMeta: Meta? = null
@ -124,19 +126,11 @@ class PlayerViewModel(application: Application) : AndroidViewModel(application)
mediaSession.isActive = true mediaSession.isActive = true
} }
fun loadMedia(seasonId: String, episodeId: String) { fun loadMediaAsync(seasonId: String, episodeId: String) = viewModelScope.launch {
runBlocking { episodes = Crunchyroll.episodes(seasonId)
episodes = Crunchyroll.episodes(seasonId)
//mediaMeta = loadMediaMeta(media.aodId) // can be done blocking, since it should be cached
// TODO replace this with setCurrentEpisode setCurrentEpisode(episodeId)
currentEpisode = episodes.items.find { episode -> playCurrentMedia(currentPlayhead)
episode.id == episodeId
} ?: NoneEpisode
println("loading playback ${currentEpisode.playback}")
currentPlayback = Crunchyroll.playback(currentEpisode.playback)
}
// TODO reimplement for cr // TODO reimplement for cr
// run async as it should be loaded by the time the episodes a // run async as it should be loaded by the time the episodes a
@ -183,10 +177,23 @@ class PlayerViewModel(application: Application) : AndroidViewModel(application)
episode.id == episodeId episode.id == episodeId
} ?: NoneEpisode } ?: NoneEpisode
// TODO don't run blocking // update player gui (title, next ep button) after currentEpisode has changed
currentEpisodeChangedListener.forEach { it() }
// needs to be blocking, currentPlayback must be present when calling playCurrentMedia()
runBlocking { runBlocking {
currentPlayback = Crunchyroll.playback(currentEpisode.playback) joinAll(
viewModelScope.launch(Dispatchers.IO) {
currentPlayback = Crunchyroll.playback(currentEpisode.playback)
},
viewModelScope.launch(Dispatchers.IO) {
Crunchyroll.playheads(listOf(currentEpisode.id))[currentEpisode.id]?.let {
currentPlayhead = (it.playhead.times(1000)).toLong()
}
}
)
} }
println("loaded playback ${currentEpisode.playback}")
// TODO update metadata and language (it should not be needed to update the language here!) // TODO update metadata and language (it should not be needed to update the language here!)
@ -201,9 +208,6 @@ class PlayerViewModel(application: Application) : AndroidViewModel(application)
* @param seekPosition The seek position for the episode (default = 0). * @param seekPosition The seek position for the episode (default = 0).
*/ */
fun playCurrentMedia(seekPosition: Long = 0) { fun playCurrentMedia(seekPosition: Long = 0) {
// update player gui (title, next ep button) after nextEpisodeId has been set
currentEpisodeChangedListener.forEach { it() }
// get preferred stream url, set current language if it differs from the preferred one // get preferred stream url, set current language if it differs from the preferred one
val preferredLocale = currentLanguage val preferredLocale = currentLanguage
val fallbackLocal = Locale.US val fallbackLocal = Locale.US