From ed87a7b33a78fb24d97730ac17e9745e067a5344 Mon Sep 17 00:00:00 2001 From: Bnyro Date: Wed, 10 Aug 2022 15:49:31 +0200 Subject: [PATCH 1/3] playback queue --- .../main/java/com/github/libretube/Globals.kt | 3 ++ .../libretube/dialogs/VideoOptionsDialog.kt | 19 +++++++- .../libretube/fragments/PlayerFragment.kt | 32 +++---------- .../libretube/services/BackgroundMode.kt | 2 +- .../github/libretube/util/AutoPlayHelper.kt | 46 +++++++++++++++++-- app/src/main/res/values/strings.xml | 1 + 6 files changed, 71 insertions(+), 32 deletions(-) diff --git a/app/src/main/java/com/github/libretube/Globals.kt b/app/src/main/java/com/github/libretube/Globals.kt index 6d3b43a11..bfb98c573 100644 --- a/app/src/main/java/com/github/libretube/Globals.kt +++ b/app/src/main/java/com/github/libretube/Globals.kt @@ -16,4 +16,7 @@ object Globals { // for playlists var SELECTED_PLAYLIST_ID: String? = null + + // history of played videos in the current lifecycle + val videoIds = mutableListOf() } diff --git a/app/src/main/java/com/github/libretube/dialogs/VideoOptionsDialog.kt b/app/src/main/java/com/github/libretube/dialogs/VideoOptionsDialog.kt index a90e270cf..e86b2984c 100644 --- a/app/src/main/java/com/github/libretube/dialogs/VideoOptionsDialog.kt +++ b/app/src/main/java/com/github/libretube/dialogs/VideoOptionsDialog.kt @@ -1,10 +1,14 @@ package com.github.libretube.dialogs import android.app.Dialog +import android.app.NotificationManager +import android.content.Context import android.os.Bundle import android.widget.ArrayAdapter import android.widget.Toast import androidx.fragment.app.DialogFragment +import com.github.libretube.Globals +import com.github.libretube.PLAYER_NOTIFICATION_ID import com.github.libretube.R import com.github.libretube.preferences.PreferenceHelper import com.github.libretube.util.BackgroundHelper @@ -27,12 +31,22 @@ class VideoOptionsDialog( /** * List that stores the different menu options. In the future could be add more options here. */ - val optionsList = listOf( + val optionsList = mutableListOf( context?.getString(R.string.playOnBackground), context?.getString(R.string.addToPlaylist), context?.getString(R.string.share) ) + /** + * Check whether the player is running by observing the notification + */ + val notificationManager = context?.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + notificationManager.activeNotifications.forEach { + if (it.id == PLAYER_NOTIFICATION_ID) { + optionsList += context?.getString(R.string.add_to_queue) + } + } + return MaterialAlertDialogBuilder(requireContext()) .setNegativeButton(R.string.cancel, null) .setAdapter( @@ -68,6 +82,9 @@ class VideoOptionsDialog( // using parentFragmentManager is important here shareDialog.show(parentFragmentManager, ShareDialog::class.java.name) } + context?.getString(R.string.add_to_queue) -> { + Globals.videoIds += videoId + } } } .show() diff --git a/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt b/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt index d29c500e4..27c703581 100644 --- a/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt +++ b/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt @@ -27,7 +27,6 @@ import androidx.constraintlayout.motion.widget.MotionLayout import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.net.toUri import androidx.core.os.bundleOf -import androidx.core.os.postDelayed import androidx.core.view.isVisible import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.GridLayoutManager @@ -176,11 +175,6 @@ class PlayerFragment : BaseFragment() { */ private lateinit var nowPlayingNotification: NowPlayingNotification - /** - * history of played videos in the current lifecycle - */ - val videoIds = mutableListOf() - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) arguments?.let { @@ -754,7 +748,7 @@ class PlayerFragment : BaseFragment() { } } } - videoIds += videoId!! + Globals.videoIds += videoId!! } run() } @@ -763,24 +757,10 @@ class PlayerFragment : BaseFragment() { * set the videoId of the next stream for autoplay */ private fun setNextStream() { - // don't play a video if it got played before already - var index = 0 - while (nextStreamId == null || nextStreamId == videoId!! || - ( - videoIds.contains(nextStreamId) && - videoIds.indexOf(videoId) > videoIds.indexOf(nextStreamId) - ) - ) { - nextStreamId = streams.relatedStreams!![index].url.toID() - if (index + 1 < streams.relatedStreams!!.size) index += 1 - else break - } - if (playlistId == null) return - if (!this::autoPlayHelper.isInitialized) autoPlayHelper = AutoPlayHelper(playlistId!!) + if (!this::autoPlayHelper.isInitialized) autoPlayHelper = AutoPlayHelper(playlistId) // search for the next videoId in the playlist lifecycleScope.launchWhenCreated { - val nextId = autoPlayHelper.getNextPlaylistVideoId(videoId!!) - if (nextId != null) nextStreamId = nextId + nextStreamId = autoPlayHelper.getNextVideoId(videoId!!, streams.relatedStreams!!) } } @@ -1073,13 +1053,13 @@ class PlayerFragment : BaseFragment() { // next and previous buttons playerBinding.skipPrev.visibility = if ( - skipButtonsEnabled && videoIds.indexOf(videoId!!) != 0 + skipButtonsEnabled && Globals.videoIds.indexOf(videoId!!) != 0 ) View.VISIBLE else View.INVISIBLE playerBinding.skipNext.visibility = if (skipButtonsEnabled) View.VISIBLE else View.INVISIBLE playerBinding.skipPrev.setOnClickListener { - val index = videoIds.indexOf(videoId!!) - 1 - videoId = videoIds[index] + val index = Globals.videoIds.indexOf(videoId!!) - 1 + videoId = Globals.videoIds[index] playVideo() } diff --git a/app/src/main/java/com/github/libretube/services/BackgroundMode.kt b/app/src/main/java/com/github/libretube/services/BackgroundMode.kt index c3ae20dac..a4c37e96d 100644 --- a/app/src/main/java/com/github/libretube/services/BackgroundMode.kt +++ b/app/src/main/java/com/github/libretube/services/BackgroundMode.kt @@ -217,7 +217,7 @@ class BackgroundMode : Service() { if (!this::autoPlayHelper.isInitialized) autoPlayHelper = AutoPlayHelper(playlistId!!) // search for the next videoId in the playlist CoroutineScope(Dispatchers.IO).launch { - val nextId = autoPlayHelper.getNextPlaylistVideoId(videoId) + val nextId = autoPlayHelper.getNextVideoId(videoId) if (nextId != null) nextStreamId = nextId } } diff --git a/app/src/main/java/com/github/libretube/util/AutoPlayHelper.kt b/app/src/main/java/com/github/libretube/util/AutoPlayHelper.kt index ca48fd1d2..e7072c4d6 100644 --- a/app/src/main/java/com/github/libretube/util/AutoPlayHelper.kt +++ b/app/src/main/java/com/github/libretube/util/AutoPlayHelper.kt @@ -1,17 +1,55 @@ package com.github.libretube.util +import com.github.libretube.Globals +import com.github.libretube.obj.StreamItem import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext class AutoPlayHelper( - private val playlistId: String + private val playlistId: String? ) { private val TAG = "AutoPlayHelper" private val playlistStreamIds = mutableListOf() private var playlistNextPage: String? = null - suspend fun getNextPlaylistVideoId(currentVideoId: String): String? { + suspend fun getNextVideoId( + currentVideoId: String, + relatedStreams: List + ): String? { + val currentVideoIndex = Globals.videoIds.indexOf(currentVideoId) + return if (Globals.videoIds.size > currentVideoIndex + 1) { + Globals.videoIds[currentVideoIndex + 1] + } else if (playlistId == null) getNextTrendingVideoId( + currentVideoId, + relatedStreams + ) else { + getNextPlaylistVideoId( + currentVideoId + ) + } + } + + private fun getNextTrendingVideoId(videoId: String, relatedStreams: List): String? { + // don't play a video if it got played before already + var index = 0 + var nextStreamId: String? = null + while (nextStreamId == null || + ( + Globals.videoIds.contains(nextStreamId) && + Globals.videoIds.indexOf(videoId) > Globals.videoIds.indexOf( + nextStreamId + ) + ) + ) { + nextStreamId = relatedStreams[index].url.toID() + if (index + 1 < relatedStreams.size) index += 1 + else break + } + return nextStreamId + } + + private suspend fun getNextPlaylistVideoId(currentVideoId: String): String? { // if the playlists contain the video, then save the next video as next stream if (playlistStreamIds.contains(currentVideoId)) { val index = playlistStreamIds.indexOf(currentVideoId) @@ -24,9 +62,9 @@ class AutoPlayHelper( return withContext(Dispatchers.IO) { // fetch the playlists or its nextPage's videos val playlist = - if (playlistNextPage == null) RetrofitInstance.authApi.getPlaylist(playlistId) + if (playlistNextPage == null) RetrofitInstance.authApi.getPlaylist(playlistId!!) else RetrofitInstance.authApi.getPlaylistNextPage( - playlistId, + playlistId!!, playlistNextPage!! ) // save the playlist urls to the list diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index cc4981bce..6cc64f7a6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -297,4 +297,5 @@ Maximum history size Unlimited Background mode + Add to queue From 103376eb6bfe957ab05491794df94df888862f59 Mon Sep 17 00:00:00 2001 From: Bnyro Date: Wed, 10 Aug 2022 15:53:34 +0200 Subject: [PATCH 2/3] same for background mode --- app/src/main/java/com/github/libretube/Globals.kt | 2 +- .../libretube/dialogs/VideoOptionsDialog.kt | 2 +- .../github/libretube/fragments/PlayerFragment.kt | 11 +++++++---- .../github/libretube/services/BackgroundMode.kt | 15 ++++++++++----- .../com/github/libretube/util/AutoPlayHelper.kt | 10 +++++----- 5 files changed, 24 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/github/libretube/Globals.kt b/app/src/main/java/com/github/libretube/Globals.kt index bfb98c573..5db9eabea 100644 --- a/app/src/main/java/com/github/libretube/Globals.kt +++ b/app/src/main/java/com/github/libretube/Globals.kt @@ -18,5 +18,5 @@ object Globals { var SELECTED_PLAYLIST_ID: String? = null // history of played videos in the current lifecycle - val videoIds = mutableListOf() + val playingQueue = mutableListOf() } diff --git a/app/src/main/java/com/github/libretube/dialogs/VideoOptionsDialog.kt b/app/src/main/java/com/github/libretube/dialogs/VideoOptionsDialog.kt index e86b2984c..f10d1d254 100644 --- a/app/src/main/java/com/github/libretube/dialogs/VideoOptionsDialog.kt +++ b/app/src/main/java/com/github/libretube/dialogs/VideoOptionsDialog.kt @@ -83,7 +83,7 @@ class VideoOptionsDialog( shareDialog.show(parentFragmentManager, ShareDialog::class.java.name) } context?.getString(R.string.add_to_queue) -> { - Globals.videoIds += videoId + Globals.playingQueue += videoId } } } diff --git a/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt b/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt index 27c703581..068706132 100644 --- a/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt +++ b/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt @@ -201,6 +201,9 @@ class PlayerFragment : BaseFragment() { super.onViewCreated(view, savedInstanceState) context?.hideKeyboard(view) + // clear the playing queue + Globals.playingQueue.clear() + setUserPrefs() if (autoplayEnabled) playerBinding.autoplayIV.setImageResource(R.drawable.ic_toggle_on) @@ -748,7 +751,7 @@ class PlayerFragment : BaseFragment() { } } } - Globals.videoIds += videoId!! + Globals.playingQueue += videoId!! } run() } @@ -1053,13 +1056,13 @@ class PlayerFragment : BaseFragment() { // next and previous buttons playerBinding.skipPrev.visibility = if ( - skipButtonsEnabled && Globals.videoIds.indexOf(videoId!!) != 0 + skipButtonsEnabled && Globals.playingQueue.indexOf(videoId!!) != 0 ) View.VISIBLE else View.INVISIBLE playerBinding.skipNext.visibility = if (skipButtonsEnabled) View.VISIBLE else View.INVISIBLE playerBinding.skipPrev.setOnClickListener { - val index = Globals.videoIds.indexOf(videoId!!) - 1 - videoId = Globals.videoIds[index] + val index = Globals.playingQueue.indexOf(videoId!!) - 1 + videoId = Globals.playingQueue[index] playVideo() } diff --git a/app/src/main/java/com/github/libretube/services/BackgroundMode.kt b/app/src/main/java/com/github/libretube/services/BackgroundMode.kt index a4c37e96d..0c2fd9bb0 100644 --- a/app/src/main/java/com/github/libretube/services/BackgroundMode.kt +++ b/app/src/main/java/com/github/libretube/services/BackgroundMode.kt @@ -12,6 +12,7 @@ import android.os.Looper import android.widget.Toast import com.fasterxml.jackson.databind.ObjectMapper import com.github.libretube.BACKGROUND_CHANNEL_ID +import com.github.libretube.Globals import com.github.libretube.PLAYER_NOTIFICATION_ID import com.github.libretube.R import com.github.libretube.obj.Segment @@ -78,7 +79,7 @@ class BackgroundMode : Service() { /** * The [videoId] of the next stream for autoplay */ - private lateinit var nextStreamId: String + private var nextStreamId: String? = null /** * Helper for finding the next video in the playlist @@ -111,6 +112,9 @@ class BackgroundMode : Service() { */ override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { try { + // clear the playing queue + Globals.playingQueue.clear() + // get the intent arguments videoId = intent?.getStringExtra("videoId")!! playlistId = intent.getStringExtra("playlistId") @@ -135,6 +139,8 @@ class BackgroundMode : Service() { videoId: String, seekToPosition: Long = 0 ) { + // append the video to the playing queue + Globals.playingQueue += videoId runBlocking { val job = launch { streams = RetrofitInstance.api.getStreams(videoId) @@ -217,8 +223,7 @@ class BackgroundMode : Service() { if (!this::autoPlayHelper.isInitialized) autoPlayHelper = AutoPlayHelper(playlistId!!) // search for the next videoId in the playlist CoroutineScope(Dispatchers.IO).launch { - val nextId = autoPlayHelper.getNextVideoId(videoId) - if (nextId != null) nextStreamId = nextId + nextStreamId = autoPlayHelper.getNextVideoId(videoId, streams!!.relatedStreams!!) } } @@ -226,10 +231,10 @@ class BackgroundMode : Service() { * Plays the first related video to the current (used when the playback of the current video ended) */ private fun playNextVideo() { - if (!this::nextStreamId.isInitialized || nextStreamId == videoId) return + if (nextStreamId == null || nextStreamId == videoId) return // play new video on background - this.videoId = nextStreamId + this.videoId = nextStreamId!! this.segmentData = null playAudio(videoId) } diff --git a/app/src/main/java/com/github/libretube/util/AutoPlayHelper.kt b/app/src/main/java/com/github/libretube/util/AutoPlayHelper.kt index e7072c4d6..043af6f72 100644 --- a/app/src/main/java/com/github/libretube/util/AutoPlayHelper.kt +++ b/app/src/main/java/com/github/libretube/util/AutoPlayHelper.kt @@ -17,9 +17,9 @@ class AutoPlayHelper( currentVideoId: String, relatedStreams: List ): String? { - val currentVideoIndex = Globals.videoIds.indexOf(currentVideoId) - return if (Globals.videoIds.size > currentVideoIndex + 1) { - Globals.videoIds[currentVideoIndex + 1] + val currentVideoIndex = Globals.playingQueue.indexOf(currentVideoId) + return if (Globals.playingQueue.size > currentVideoIndex + 1) { + Globals.playingQueue[currentVideoIndex + 1] } else if (playlistId == null) getNextTrendingVideoId( currentVideoId, relatedStreams @@ -36,8 +36,8 @@ class AutoPlayHelper( var nextStreamId: String? = null while (nextStreamId == null || ( - Globals.videoIds.contains(nextStreamId) && - Globals.videoIds.indexOf(videoId) > Globals.videoIds.indexOf( + Globals.playingQueue.contains(nextStreamId) && + Globals.playingQueue.indexOf(videoId) > Globals.playingQueue.indexOf( nextStreamId ) ) From ffb3dd6743e0d262ec4ebef39886cfe2c07177f9 Mon Sep 17 00:00:00 2001 From: Bnyro Date: Wed, 10 Aug 2022 16:23:57 +0200 Subject: [PATCH 3/3] final touches --- .../libretube/fragments/PlayerFragment.kt | 69 +++++++++---------- .../libretube/services/BackgroundMode.kt | 16 +++-- .../github/libretube/util/AutoPlayHelper.kt | 21 ++++-- 3 files changed, 57 insertions(+), 49 deletions(-) diff --git a/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt b/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt index 068706132..f8413534b 100644 --- a/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt +++ b/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt @@ -716,44 +716,39 @@ class PlayerFragment : BaseFragment() { } private fun playVideo() { - fun run() { - lifecycleScope.launchWhenCreated { - streams = try { - RetrofitInstance.api.getStreams(videoId!!) - } catch (e: IOException) { - println(e) - Log.e(TAG, "IOException, you might not have internet connection") - Toast.makeText(context, R.string.unknown_error, Toast.LENGTH_SHORT).show() - return@launchWhenCreated - } catch (e: HttpException) { - Log.e(TAG, "HttpException, unexpected response") - Toast.makeText(context, R.string.server_error, Toast.LENGTH_SHORT).show() - return@launchWhenCreated - } - - runOnUiThread { - // set media sources for the player - setResolutionAndSubtitles(streams) - prepareExoPlayerView() - initializePlayerView(streams) - if (!isLive) seekToWatchPosition() - exoPlayer.prepare() - exoPlayer.play() - exoPlayerView.useController = true - initializePlayerNotification() - if (sponsorBlockEnabled) fetchSponsorBlockSegments() - // show comments if related streams disabled - if (!relatedStreamsEnabled) toggleComments() - // prepare for autoplay - if (autoplayEnabled) setNextStream() - if (watchHistoryEnabled) { - PreferenceHelper.addToWatchHistory(videoId!!, streams) - } - } + Globals.playingQueue += videoId!! + lifecycleScope.launchWhenCreated { + streams = try { + RetrofitInstance.api.getStreams(videoId!!) + } catch (e: IOException) { + println(e) + Log.e(TAG, "IOException, you might not have internet connection") + Toast.makeText(context, R.string.unknown_error, Toast.LENGTH_SHORT).show() + return@launchWhenCreated + } catch (e: HttpException) { + Log.e(TAG, "HttpException, unexpected response") + Toast.makeText(context, R.string.server_error, Toast.LENGTH_SHORT).show() + return@launchWhenCreated + } + + runOnUiThread { + // set media sources for the player + setResolutionAndSubtitles(streams) + prepareExoPlayerView() + initializePlayerView(streams) + if (!isLive) seekToWatchPosition() + exoPlayer.prepare() + exoPlayer.play() + exoPlayerView.useController = true + initializePlayerNotification() + if (sponsorBlockEnabled) fetchSponsorBlockSegments() + // show comments if related streams disabled + if (!relatedStreamsEnabled) toggleComments() + // prepare for autoplay + if (autoplayEnabled) setNextStream() + if (watchHistoryEnabled) PreferenceHelper.addToWatchHistory(videoId!!, streams) } - Globals.playingQueue += videoId!! } - run() } /** @@ -828,6 +823,8 @@ class PlayerFragment : BaseFragment() { private fun playNextVideo() { if (nextStreamId == null) return // check whether there is a new video in the queue + val nextQueueVideo = autoPlayHelper.getNextPlayingQueueVideoId(videoId!!) + if (nextQueueVideo != null) nextStreamId = nextQueueVideo // by making sure that the next and the current video aren't the same saveWatchPosition() // forces the comments to reload for the new video diff --git a/app/src/main/java/com/github/libretube/services/BackgroundMode.kt b/app/src/main/java/com/github/libretube/services/BackgroundMode.kt index 0c2fd9bb0..0ad0f53b8 100644 --- a/app/src/main/java/com/github/libretube/services/BackgroundMode.kt +++ b/app/src/main/java/com/github/libretube/services/BackgroundMode.kt @@ -30,7 +30,6 @@ import com.google.android.exoplayer2.ExoPlayer import com.google.android.exoplayer2.MediaItem import com.google.android.exoplayer2.Player import com.google.android.exoplayer2.audio.AudioAttributes -import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -87,7 +86,12 @@ class BackgroundMode : Service() { private lateinit var autoPlayHelper: AutoPlayHelper /** - * Setting the required [notification] for running as a foreground service + * Autoplay Preference + */ + private val autoplay = PreferenceHelper.getBoolean(PreferenceKeys.AUTO_PLAY, true) + + /** + * Setting the required [Notification] for running as a foreground service */ override fun onCreate() { super.onCreate() @@ -174,7 +178,7 @@ class BackgroundMode : Service() { fetchSponsorBlockSegments() - setNextStream() + if (autoplay) setNextStream() } } @@ -200,7 +204,6 @@ class BackgroundMode : Service() { override fun onPlaybackStateChanged(@Player.State state: Int) { when (state) { Player.STATE_ENDED -> { - val autoplay = PreferenceHelper.getBoolean(PreferenceKeys.AUTO_PLAY, true) if (autoplay) playNextVideo() } Player.STATE_IDLE -> { @@ -232,6 +235,8 @@ class BackgroundMode : Service() { */ private fun playNextVideo() { if (nextStreamId == null || nextStreamId == videoId) return + val nextQueueVideo = autoPlayHelper.getNextPlayingQueueVideoId(videoId) + if (nextQueueVideo != null) nextStreamId = nextQueueVideo // play new video on background this.videoId = nextStreamId!! @@ -240,8 +245,7 @@ class BackgroundMode : Service() { } /** - * Sets the [MediaItem] with the [streams] into the [player]. Also creates a [MediaSessionConnector] - * with the [mediaSession] and attach it to the [player]. + * Sets the [MediaItem] with the [streams] into the [player] */ private fun setMediaItem() { streams?.let { diff --git a/app/src/main/java/com/github/libretube/util/AutoPlayHelper.kt b/app/src/main/java/com/github/libretube/util/AutoPlayHelper.kt index 043af6f72..d747681ea 100644 --- a/app/src/main/java/com/github/libretube/util/AutoPlayHelper.kt +++ b/app/src/main/java/com/github/libretube/util/AutoPlayHelper.kt @@ -17,17 +17,15 @@ class AutoPlayHelper( currentVideoId: String, relatedStreams: List ): String? { - val currentVideoIndex = Globals.playingQueue.indexOf(currentVideoId) - return if (Globals.playingQueue.size > currentVideoIndex + 1) { + return if (Globals.playingQueue.last() != currentVideoId) { + val currentVideoIndex = Globals.playingQueue.indexOf(currentVideoId) Globals.playingQueue[currentVideoIndex + 1] } else if (playlistId == null) getNextTrendingVideoId( currentVideoId, relatedStreams - ) else { - getNextPlaylistVideoId( - currentVideoId - ) - } + ) else getNextPlaylistVideoId( + currentVideoId + ) } private fun getNextTrendingVideoId(videoId: String, relatedStreams: List): String? { @@ -77,4 +75,13 @@ class AutoPlayHelper( // return null when no nextPage is found return null } + + fun getNextPlayingQueueVideoId( + currentVideoId: String + ): String? { + return if (Globals.playingQueue.last() != currentVideoId) { + val currentVideoIndex = Globals.playingQueue.indexOf(currentVideoId) + Globals.playingQueue[currentVideoIndex + 1] + } else null + } }