diff --git a/app/src/main/java/org/mosad/teapod/PlayerActivity.kt b/app/src/main/java/org/mosad/teapod/PlayerActivity.kt
index cacaf31..35e65b1 100644
--- a/app/src/main/java/org/mosad/teapod/PlayerActivity.kt
+++ b/app/src/main/java/org/mosad/teapod/PlayerActivity.kt
@@ -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
diff --git a/app/src/main/java/org/mosad/teapod/parser/AoDParser.kt b/app/src/main/java/org/mosad/teapod/parser/AoDParser.kt
index c625aed..588e930 100644
--- a/app/src/main/java/org/mosad/teapod/parser/AoDParser.kt
+++ b/app/src/main/java/org/mosad/teapod/parser/AoDParser.kt
@@ -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)
diff --git a/app/src/main/java/org/mosad/teapod/ui/fragments/MediaFragment.kt b/app/src/main/java/org/mosad/teapod/ui/fragments/MediaFragment.kt
index ea77f36..6ffd51c 100644
--- a/app/src/main/java/org/mosad/teapod/ui/fragments/MediaFragment.kt
+++ b/app/src/main/java/org/mosad/teapod/ui/fragments/MediaFragment.kt
@@ -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
diff --git a/app/src/main/res/layout/activity_player.xml b/app/src/main/res/layout/activity_player.xml
index b550802..c814052 100644
--- a/app/src/main/res/layout/activity_player.xml
+++ b/app/src/main/res/layout/activity_player.xml
@@ -24,6 +24,23 @@
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_gravity="center"
+ app:indicatorColor="@color/exo_white"
tools:visibility="visible" />
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values-de-rDE/strings.xml b/app/src/main/res/values-de-rDE/strings.xml
index 6da3fdf..c28e8e6 100644
--- a/app/src/main/res/values-de-rDE/strings.xml
+++ b/app/src/main/res/values-de-rDE/strings.xml
@@ -35,6 +35,8 @@
10 Sekunden zurück
Abspielen/Pause
10 Sekunden vorwärts
+ Nächste Episode
+
speichern
@android:string/cancel
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 430fde1..2ccc748 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -46,6 +46,7 @@
forward 10 seconds
%1$02d:%2$02d
%1$d:%2$02d:%3$02d
+ Next Episode
save