Player: add auto play next episode

This commit is contained in:
Jannik 2020-11-13 15:36:12 +01:00
parent 353ae6937a
commit 23713fc1e6
Signed by: Seil0
GPG Key ID: E8459F3723C52C24
6 changed files with 83 additions and 19 deletions

View File

@ -8,6 +8,7 @@ import android.util.Log
import android.view.*
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.GestureDetectorCompat
import androidx.core.view.isVisible
import com.google.android.exoplayer2.ExoPlayer
import com.google.android.exoplayer2.MediaItem
import com.google.android.exoplayer2.Player
@ -19,6 +20,7 @@ import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory
import com.google.android.exoplayer2.util.Util
import kotlinx.android.synthetic.main.activity_player.*
import kotlinx.android.synthetic.main.player_controls.*
import kotlinx.coroutines.*
import org.mosad.teapod.parser.AoDParser
import org.mosad.teapod.preferences.Preferences
import org.mosad.teapod.util.DataTypes.MediaType
@ -33,8 +35,6 @@ class PlayerActivity : AppCompatActivity() {
private lateinit var controller: StyledPlayerControlView
private lateinit var gestureDetector: GestureDetectorCompat
private var streamUrl = ""
private var mediaId = 0
private var episodeId = 0
@ -119,19 +119,13 @@ class PlayerActivity : AppCompatActivity() {
initExoPlayer()
initVideoView()
initController()
initTimeUpdates()
}
private fun initMedia() {
media = AoDParser.getMediaById(mediaId)
currentEpisode = media.episodes.first { it.id == episodeId }
streamUrlFromEp(currentEpisode) // get current stream
// get next episode if present
val nextEpIndex = media.episodes.indexOfFirst { it.id == episodeId } + 1
if (nextEpIndex < (media.episodes.size - 1)) {
println("has next episode")
nextEpisode = media.episodes[nextEpIndex]
}
nextEpisode = selectNextEpisode()
}
private fun initExoPlayer() {
@ -140,7 +134,7 @@ class PlayerActivity : AppCompatActivity() {
controller = video_view.findViewById(R.id.exo_controller)
val mediaSource = HlsMediaSource.Factory(dataSourceFactory)
.createMediaSource(MediaItem.fromUri(Uri.parse(streamUrl)))
.createMediaSource(MediaItem.fromUri(Uri.parse(selectStream(currentEpisode))))
player.playWhenReady = playWhenReady
player.setMediaSource(mediaSource)
@ -162,6 +156,11 @@ class PlayerActivity : AppCompatActivity() {
View.VISIBLE -> View.INVISIBLE
else -> View.VISIBLE
}
if (state == ExoPlayer.STATE_ENDED && nextEpisode != null) {
playNextEpisode()
}
}
})
}
@ -198,6 +197,7 @@ class PlayerActivity : AppCompatActivity() {
} else {
getString(R.string.time_hour_min_sec, hours, minutes, seconds)
}
}
exo_text_title.text = currentEpisode.title // set media title
@ -207,6 +207,26 @@ class PlayerActivity : AppCompatActivity() {
exo_close_player.setOnClickListener { this.finish() }
exo_rew_10.setOnClickListener { rewind() }
exo_ffwd_10.setOnClickListener { forward() }
button_next_ep.setOnClickListener { playNextEpisode() }
}
private fun initTimeUpdates() = GlobalScope.launch {
while (true) {
val remainingTime = withContext(Dispatchers.Main) {
player.duration - player.currentPosition
}
if (remainingTime in 0..20000) {
withContext(Dispatchers.Main) {
// if the next ep button is not visible, make it visible
if (!button_next_ep.isVisible) {
button_next_ep.visibility = View.VISIBLE // TODO animation
}
}
}
delay(1000)
}
}
private fun releasePlayer(){
@ -226,11 +246,23 @@ class PlayerActivity : AppCompatActivity() {
player.seekTo(player.currentPosition + fwdTime)
}
@Suppress("unused")
private fun playNextEpisode() {
nextEpisode?.let { streamUrlFromEp(it) }
// TODO play
// TODO set next episode if present
nextEpisode?.let { nextEp ->
currentEpisode = nextEp // set current ep to next ep
episodeId = nextEp.id
// update the gui
exo_text_title.text = nextEp.title
button_next_ep.visibility = View.GONE // TODO animation
player.clearMediaItems() //remove previous item
val mediaSource = HlsMediaSource.Factory(dataSourceFactory)
.createMediaSource(MediaItem.fromUri(Uri.parse(selectStream(nextEp))))
player.setMediaSource(mediaSource)
player.prepare()
nextEpisode = selectNextEpisode()
}
}
/**
@ -238,18 +270,30 @@ class PlayerActivity : AppCompatActivity() {
* use the secondary stream. Else, if the primary stream is set use the primary stream.
* If no stream is present, close the activity.
*/
private fun streamUrlFromEp(episode: Episode) {
streamUrl = if ((Preferences.preferSecondary || episode.priStreamUrl.isEmpty()) && episode.secStreamOmU) {
private fun selectStream(episode: Episode): String {
return if ((Preferences.preferSecondary || episode.priStreamUrl.isEmpty()) && episode.secStreamOmU) {
episode.secStreamUrl
} else if (episode.priStreamUrl.isNotEmpty()) {
episode.priStreamUrl
} else {
Log.e(javaClass.name, "No stream url set.")
this.finish()
return
""
}
}
/**
* Based on the current episodeId, get the next episode. If there is no next
* episode, return null
*/
private fun selectNextEpisode(): Episode? {
val nextEpIndex = media.episodes.indexOfFirst { it.id == currentEpisode.id } + 1
return if (nextEpIndex < (media.episodes.size)) {
media.episodes[nextEpIndex]
} else {
null
}
}
/**
* hide the status and navigation bar

View File

@ -73,6 +73,7 @@ object AoDParser {
val resLogin = Jsoup.connect(baseUrl + loginPath)
.method(Connection.Method.POST)
.timeout(60000) // login can take some time
.data(data)
.postDataCharset("UTF-8")
.cookies(authCookies)

View File

@ -17,7 +17,6 @@ import kotlinx.android.synthetic.main.fragment_media.*
import org.mosad.teapod.MainActivity
import org.mosad.teapod.R
import org.mosad.teapod.parser.AoDParser
import org.mosad.teapod.preferences.Preferences
import org.mosad.teapod.util.DataTypes.MediaType
import org.mosad.teapod.util.Episode
import org.mosad.teapod.util.Media

View File

@ -24,6 +24,23 @@
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_gravity="center"
app:indicatorColor="@color/exo_white"
tools:visibility="visible" />
<com.google.android.material.button.MaterialButton
android:id="@+id/button_next_ep"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_marginEnd="12dp"
android:layout_marginBottom="70dp"
android:gravity="center"
android:text="@string/next_episode"
android:textAllCaps="false"
android:textColor="@android:color/primary_text_light"
android:textSize="16sp"
android:visibility="gone"
app:backgroundTint="@color/exo_white"
app:iconGravity="textStart" />
</FrameLayout>

View File

@ -35,6 +35,8 @@
<string name="rewind_10">10 Sekunden zurück</string>
<string name="play_pause">Abspielen/Pause</string>
<string name="forward_10">10 Sekunden vorwärts</string>
<string name="next_episode">Nächste Episode</string>
<!-- dialogs -->
<string name="save">speichern</string>
<string name="cancel">@android:string/cancel</string>

View File

@ -46,6 +46,7 @@
<string name="forward_10">forward 10 seconds</string>
<string name="time_min_sec" translatable="false">%1$02d:%2$02d</string>
<string name="time_hour_min_sec" translatable="false">%1$d:%2$02d:%3$02d</string>
<string name="next_episode">Next Episode</string>
<!-- dialogs -->
<string name="save">save</string>