From 02d4321a2dc1ecd2ac57d489dd1d7a0a4d30edfc Mon Sep 17 00:00:00 2001 From: Bnyro Date: Sun, 23 Oct 2022 14:43:47 +0200 Subject: [PATCH] Replace the autoPlayHelper with the PlayingQueue --- .../libretube/services/BackgroundMode.kt | 48 +++---------- .../ui/adapters/PlayingQueueAdapter.kt | 14 ++-- .../libretube/ui/fragments/HomeFragment.kt | 1 - .../libretube/ui/fragments/PlayerFragment.kt | 47 +++++-------- .../libretube/ui/sheets/PlayingQueueSheet.kt | 5 +- .../github/libretube/util/AutoPlayHelper.kt | 68 ------------------- .../com/github/libretube/util/PlayingQueue.kt | 42 +++++++++++- 7 files changed, 74 insertions(+), 151 deletions(-) delete mode 100644 app/src/main/java/com/github/libretube/util/AutoPlayHelper.kt 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 f6b617682..3faab91e9 100644 --- a/app/src/main/java/com/github/libretube/services/BackgroundMode.kt +++ b/app/src/main/java/com/github/libretube/services/BackgroundMode.kt @@ -24,9 +24,7 @@ import com.github.libretube.constants.PreferenceKeys import com.github.libretube.db.DatabaseHelper import com.github.libretube.db.DatabaseHolder import com.github.libretube.extensions.awaitQuery -import com.github.libretube.extensions.toID import com.github.libretube.extensions.toStreamItem -import com.github.libretube.util.AutoPlayHelper import com.github.libretube.util.NowPlayingNotification import com.github.libretube.util.PlayerHelper import com.github.libretube.util.PlayingQueue @@ -81,16 +79,6 @@ class BackgroundMode : Service() { */ private lateinit var nowPlayingNotification: NowPlayingNotification - /** - * The [videoId] of the next stream for autoplay - */ - private var nextStreamId: String? = null - - /** - * Helper for finding the next video in the playlist - */ - private lateinit var autoPlayHelper: AutoPlayHelper - /** * Autoplay Preference */ @@ -133,9 +121,6 @@ class BackgroundMode : Service() { playlistId = intent.getStringExtra(IntentData.playlistId) val position = intent.getLongExtra(IntentData.position, 0L) - // initialize the playlist autoPlay Helper - autoPlayHelper = AutoPlayHelper(playlistId) - // play the audio in the background loadAudio(videoId, position) @@ -169,7 +154,12 @@ class BackgroundMode : Service() { return@launch } - PlayingQueue.updateCurrent(streams.toStreamItem(videoId)) + // add the playlist video to the queue + if (playlistId != null && PlayingQueue.isEmpty()) { + PlayingQueue.insertPlaylist(playlistId!!, streams.toStreamItem(videoId)) + } else { + PlayingQueue.updateCurrent(streams.toStreamItem(videoId)) + } handler.post { playAudio(seekToPosition) @@ -221,8 +211,6 @@ class BackgroundMode : Service() { player?.setPlaybackSpeed(playbackSpeed) fetchSponsorBlockSegments() - - if (PlayerHelper.autoPlayEnabled) setNextStream() } /** @@ -271,32 +259,16 @@ class BackgroundMode : Service() { }) } - /** - * set the videoId of the next stream for autoplay - */ - private fun setNextStream() { - if (streams!!.relatedStreams!!.isNotEmpty()) { - nextStreamId = streams?.relatedStreams!![0].url!!.toID() - } - - if (playlistId == null) return - if (!this::autoPlayHelper.isInitialized) autoPlayHelper = AutoPlayHelper(playlistId!!) - // search for the next videoId in the playlist - CoroutineScope(Dispatchers.IO).launch { - nextStreamId = autoPlayHelper.getNextVideoId(videoId) - } - } - /** * Plays the first related video to the current (used when the playback of the current video ended) */ private fun playNextVideo() { - if (nextStreamId == null || nextStreamId == videoId) return - val nextQueueVideo = PlayingQueue.getNext() - if (nextQueueVideo != null) nextStreamId = nextQueueVideo + val nextVideo = PlayingQueue.getNext() // play new video on background - this.videoId = nextStreamId!! + if (nextVideo != null) { + this.videoId = nextVideo + } this.segmentData = null loadAudio(videoId) } diff --git a/app/src/main/java/com/github/libretube/ui/adapters/PlayingQueueAdapter.kt b/app/src/main/java/com/github/libretube/ui/adapters/PlayingQueueAdapter.kt index 83363a80b..fae141ffc 100644 --- a/app/src/main/java/com/github/libretube/ui/adapters/PlayingQueueAdapter.kt +++ b/app/src/main/java/com/github/libretube/ui/adapters/PlayingQueueAdapter.kt @@ -4,14 +4,12 @@ import android.text.format.DateUtils import android.view.LayoutInflater import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView -import com.github.libretube.api.obj.StreamItem import com.github.libretube.databinding.QueueRowBinding import com.github.libretube.ui.viewholders.PlayingQueueViewHolder import com.github.libretube.util.ImageHelper +import com.github.libretube.util.PlayingQueue -class PlayingQueueAdapter( - private val items: List -) : RecyclerView.Adapter() { +class PlayingQueueAdapter() : RecyclerView.Adapter() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PlayingQueueViewHolder { val binding = QueueRowBinding.inflate( LayoutInflater.from(parent.context), @@ -22,16 +20,18 @@ class PlayingQueueAdapter( } override fun getItemCount(): Int { - return items.size + return PlayingQueue.size() } override fun onBindViewHolder(holder: PlayingQueueViewHolder, position: Int) { - val streamItem = items[position] + val streamItem = PlayingQueue.getStreams()[position] holder.binding.apply { ImageHelper.loadImage(streamItem.thumbnail, thumbnail) title.text = streamItem.title uploader.text = streamItem.uploaderName - duration.text = streamItem.duration?.let { DateUtils.formatElapsedTime(it) } + duration.text = streamItem.duration?.let { + DateUtils.formatElapsedTime(it) + } } } } diff --git a/app/src/main/java/com/github/libretube/ui/fragments/HomeFragment.kt b/app/src/main/java/com/github/libretube/ui/fragments/HomeFragment.kt index 38dc23e3f..c5a7566cf 100644 --- a/app/src/main/java/com/github/libretube/ui/fragments/HomeFragment.kt +++ b/app/src/main/java/com/github/libretube/ui/fragments/HomeFragment.kt @@ -20,7 +20,6 @@ import com.github.libretube.ui.adapters.ChannelAdapter import com.github.libretube.ui.adapters.TrendingAdapter import com.github.libretube.ui.base.BaseFragment import com.github.libretube.util.LocaleHelper -import com.github.libretube.util.PlayingQueue import com.github.libretube.util.PreferenceHelper import com.google.android.material.snackbar.Snackbar import retrofit2.HttpException diff --git a/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt b/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt index fa360bbb5..b0ad5a07f 100644 --- a/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt +++ b/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt @@ -67,7 +67,6 @@ import com.github.libretube.ui.dialogs.DownloadDialog import com.github.libretube.ui.dialogs.ShareDialog import com.github.libretube.ui.sheets.PlayingQueueSheet import com.github.libretube.ui.views.BottomSheet -import com.github.libretube.util.AutoPlayHelper import com.github.libretube.util.BackgroundHelper import com.github.libretube.util.ImageHelper import com.github.libretube.util.NowPlayingNotification @@ -155,12 +154,6 @@ class PlayerFragment : BaseFragment() { private var token = PreferenceHelper.getToken() private var videoShownInExternalPlayer = false - /** - * for autoplay - */ - private var nextStreamId: String? = null - private lateinit var autoPlayHelper: AutoPlayHelper - /** * for the player notification */ @@ -649,11 +642,20 @@ class PlayerFragment : BaseFragment() { return@launchWhenCreated } - PlayingQueue.updateCurrent(streams.toStreamItem(videoId!!)) - - if (PlayingQueue.size() <= 1) PlayingQueue.add( - *streams.relatedStreams.orEmpty().toTypedArray() - ) + if (PlayingQueue.size() == 0) { + CoroutineScope(Dispatchers.IO).launch { + if (playlistId != null) { + PlayingQueue.insertPlaylist(playlistId!!, streams.toStreamItem(videoId!!)) + } else { + PlayingQueue.updateCurrent(streams.toStreamItem(videoId!!)) + PlayingQueue.add( + *streams.relatedStreams.orEmpty().toTypedArray() + ) + } + } + } else { + PlayingQueue.updateCurrent(streams.toStreamItem(videoId!!)) + } runOnUiThread { // hide the button to skip SponsorBlock segments manually @@ -678,8 +680,6 @@ class PlayerFragment : BaseFragment() { if (PlayerHelper.sponsorBlockEnabled) fetchSponsorBlockSegments() // show comments if related streams disabled if (!PlayerHelper.relatedStreamsEnabled) toggleComments() - // prepare for autoplay - if (binding.player.autoplayEnabled) setNextStream() // add the video to the watch history if (PlayerHelper.watchHistoryEnabled) { @@ -692,17 +692,6 @@ class PlayerFragment : BaseFragment() { } } - /** - * set the videoId of the next stream for autoplay - */ - private fun setNextStream() { - if (!this::autoPlayHelper.isInitialized) autoPlayHelper = AutoPlayHelper(playlistId) - // search for the next videoId in the playlist - lifecycleScope.launchWhenCreated { - nextStreamId = autoPlayHelper.getNextVideoId(videoId!!) - } - } - /** * fetch the segments for SponsorBlock */ @@ -768,17 +757,14 @@ class PlayerFragment : BaseFragment() { // used for autoplay and skipping to next video private fun playNextVideo() { - if (nextStreamId == null) return - // check whether there is a new video in the queue - val nextQueueVideo = PlayingQueue.getNext() - if (nextQueueVideo != null) nextStreamId = nextQueueVideo + val nextVideo = PlayingQueue.getNext() // by making sure that the next and the current video aren't the same saveWatchPosition() // forces the comments to reload for the new video commentsLoaded = false binding.commentsRecView.adapter = null // save the id of the next stream as videoId and load the next video - videoId = nextStreamId + videoId = nextVideo playVideo() } @@ -876,7 +862,6 @@ class PlayerFragment : BaseFragment() { @Suppress("DEPRECATION") if ( playbackState == Player.STATE_ENDED && - nextStreamId != null && !transitioning && binding.player.autoplayEnabled ) { diff --git a/app/src/main/java/com/github/libretube/ui/sheets/PlayingQueueSheet.kt b/app/src/main/java/com/github/libretube/ui/sheets/PlayingQueueSheet.kt index 87d6c8c8b..fa09f5913 100644 --- a/app/src/main/java/com/github/libretube/ui/sheets/PlayingQueueSheet.kt +++ b/app/src/main/java/com/github/libretube/ui/sheets/PlayingQueueSheet.kt @@ -7,7 +7,6 @@ import android.view.ViewGroup import androidx.recyclerview.widget.LinearLayoutManager import com.github.libretube.databinding.BottomSheetBinding import com.github.libretube.ui.adapters.PlayingQueueAdapter -import com.github.libretube.util.PlayingQueue import com.google.android.material.bottomsheet.BottomSheetDialogFragment class PlayingQueueSheet : BottomSheetDialogFragment() { @@ -26,8 +25,6 @@ class PlayingQueueSheet : BottomSheetDialogFragment() { super.onViewCreated(view, savedInstanceState) binding.optionsRecycler.layoutManager = LinearLayoutManager(context) - binding.optionsRecycler.adapter = PlayingQueueAdapter( - PlayingQueue.getStreams() - ) + binding.optionsRecycler.adapter = PlayingQueueAdapter() } } diff --git a/app/src/main/java/com/github/libretube/util/AutoPlayHelper.kt b/app/src/main/java/com/github/libretube/util/AutoPlayHelper.kt deleted file mode 100644 index 645d58fa9..000000000 --- a/app/src/main/java/com/github/libretube/util/AutoPlayHelper.kt +++ /dev/null @@ -1,68 +0,0 @@ -package com.github.libretube.util - -import com.github.libretube.api.RetrofitInstance -import com.github.libretube.extensions.toID -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext - -class AutoPlayHelper( - private val playlistId: String? -) { - - private val playlistStreamIds = mutableListOf() - private var playlistNextPage: String? = null - - /** - * get the id of the next video to be played - */ - suspend fun getNextVideoId( - currentVideoId: String - ): String? { - return if (playlistId == null) { - null - } else { - getNextPlaylistVideoId( - currentVideoId - ) - } - } - - /** - * get the videoId of the next video in a playlist - */ - 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) - // check whether there's a next video - return if (index + 1 < playlistStreamIds.size) { - playlistStreamIds[index + 1] - } else if (playlistNextPage == null) { - null - } else { - getNextPlaylistVideoId(currentVideoId) - } - } else if (playlistStreamIds.isEmpty() || playlistNextPage != null) { - // fetch the next page of the playlist - return withContext(Dispatchers.IO) { - // fetch the playlists or its nextPage's videos - val playlist = - if (playlistNextPage == null) { - RetrofitInstance.authApi.getPlaylist(playlistId!!) - } else { - RetrofitInstance.authApi.getPlaylistNextPage( - playlistId!!, - playlistNextPage!! - ) - } - // save the playlist urls to the list - playlistStreamIds += playlist.relatedStreams!!.map { it.url!!.toID() } - // save playlistNextPage for usage if video is not contained - playlistNextPage = playlist.nextpage - return@withContext getNextPlaylistVideoId(currentVideoId) - } - } - // return null when no nextPage is found - return null - } -} diff --git a/app/src/main/java/com/github/libretube/util/PlayingQueue.kt b/app/src/main/java/com/github/libretube/util/PlayingQueue.kt index cb827f89d..2c12ceddc 100644 --- a/app/src/main/java/com/github/libretube/util/PlayingQueue.kt +++ b/app/src/main/java/com/github/libretube/util/PlayingQueue.kt @@ -1,7 +1,11 @@ package com.github.libretube.util +import com.github.libretube.api.RetrofitInstance import com.github.libretube.api.obj.StreamItem import com.github.libretube.extensions.toID +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch object PlayingQueue { private val queue = mutableListOf() @@ -44,7 +48,7 @@ object PlayingQueue { fun updateCurrent(streamItem: StreamItem) { currentStream = streamItem - queue.add(streamItem) + if (!contains(streamItem)) queue.add(streamItem) } fun isNotEmpty() = queue.isNotEmpty() @@ -57,7 +61,41 @@ object PlayingQueue { private fun currentIndex() = queue.indexOf(currentStream) - fun contains(streamItem: StreamItem) = queue.contains(streamItem) + fun contains(streamItem: StreamItem) = queue.any { it.url?.toID() == streamItem.url?.toID() } fun getStreams() = queue + + private fun fetchMoreFromPlaylist(playlistId: String, nextPage: String?) { + var playlistNextPage: String? = nextPage + CoroutineScope(Dispatchers.IO).launch { + while (playlistNextPage != null) { + RetrofitInstance.authApi.getPlaylistNextPage( + playlistId, + playlistNextPage!! + ).apply { + add( + *this.relatedStreams.orEmpty().toTypedArray() + ) + playlistNextPage = this.nextpage + } + } + } + } + + fun insertPlaylist(playlistId: String, newCurrentStream: StreamItem) { + CoroutineScope(Dispatchers.IO).launch { + try { + val response = RetrofitInstance.authApi.getPlaylist(playlistId) + add( + *response.relatedStreams + .orEmpty() + .toTypedArray() + ) + updateCurrent(newCurrentStream) + fetchMoreFromPlaylist(playlistId, response.nextpage) + } catch (e: Exception) { + e.printStackTrace() + } + } + } }