playback queue

This commit is contained in:
Bnyro 2022-08-10 15:49:31 +02:00
parent c4d9de3566
commit ed87a7b33a
6 changed files with 71 additions and 32 deletions

View File

@ -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<String>()
}

View File

@ -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()

View File

@ -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<String>()
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()
}

View File

@ -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
}
}

View File

@ -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<String>()
private var playlistNextPage: String? = null
suspend fun getNextPlaylistVideoId(currentVideoId: String): String? {
suspend fun getNextVideoId(
currentVideoId: String,
relatedStreams: List<StreamItem>
): 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<StreamItem>): 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

View File

@ -297,4 +297,5 @@
<string name="history_size">Maximum history size</string>
<string name="unlimited">Unlimited</string>
<string name="background_mode">Background mode</string>
<string name="add_to_queue">Add to queue</string>
</resources>