From ed87a7b33a78fb24d97730ac17e9745e067a5344 Mon Sep 17 00:00:00 2001 From: Bnyro Date: Wed, 10 Aug 2022 15:49:31 +0200 Subject: [PATCH] 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