Add functionality

This commit is contained in:
Bnyro 2022-10-23 13:39:15 +02:00
parent afe25fc67a
commit 41162fafac
8 changed files with 95 additions and 63 deletions

View File

@ -0,0 +1,22 @@
package com.github.libretube.extensions
import com.github.libretube.api.obj.StreamItem
import com.github.libretube.api.obj.Streams
fun Streams?.toStreamItem(videoId: String): StreamItem {
if (this == null) return StreamItem()
return StreamItem(
url = videoId,
title = title,
thumbnail = thumbnailUrl,
uploaderName = uploader,
uploaderUrl = uploaderUrl,
uploaderAvatar = uploaderAvatar,
uploadedDate = uploadDate,
uploaded = null,
duration = duration,
views = views,
uploaderVerified = uploaderVerified,
shortDescription = description
)
}

View File

@ -25,6 +25,7 @@ import com.github.libretube.db.DatabaseHelper
import com.github.libretube.db.DatabaseHolder import com.github.libretube.db.DatabaseHolder
import com.github.libretube.extensions.awaitQuery import com.github.libretube.extensions.awaitQuery
import com.github.libretube.extensions.toID import com.github.libretube.extensions.toID
import com.github.libretube.extensions.toStreamItem
import com.github.libretube.util.AutoPlayHelper import com.github.libretube.util.AutoPlayHelper
import com.github.libretube.util.NowPlayingNotification import com.github.libretube.util.NowPlayingNotification
import com.github.libretube.util.PlayerHelper import com.github.libretube.util.PlayerHelper
@ -146,7 +147,9 @@ class BackgroundMode : Service() {
} }
private fun updateWatchPosition() { private fun updateWatchPosition() {
player?.currentPosition?.let { DatabaseHelper.saveWatchPosition(videoId, it) } player?.currentPosition?.let {
DatabaseHelper.saveWatchPosition(videoId, it)
}
handler.postDelayed(this::updateWatchPosition, 500) handler.postDelayed(this::updateWatchPosition, 500)
} }
@ -158,7 +161,7 @@ class BackgroundMode : Service() {
seekToPosition: Long = 0 seekToPosition: Long = 0
) { ) {
// append the video to the playing queue // append the video to the playing queue
PlayingQueue.add(videoId) PlayingQueue.add(streams.toStreamItem(videoId))
CoroutineScope(Dispatchers.IO).launch { CoroutineScope(Dispatchers.IO).launch {
try { try {
streams = RetrofitInstance.api.getStreams(videoId) streams = RetrofitInstance.api.getStreams(videoId)
@ -166,6 +169,8 @@ class BackgroundMode : Service() {
return@launch return@launch
} }
PlayingQueue.updateCurrent(streams.toStreamItem(videoId))
handler.post { handler.post {
playAudio(seekToPosition) playAudio(seekToPosition)
} }
@ -175,8 +180,6 @@ class BackgroundMode : Service() {
private fun playAudio( private fun playAudio(
seekToPosition: Long seekToPosition: Long
) { ) {
PlayingQueue.updateCurrent(videoId)
initializePlayer() initializePlayer()
setMediaItem() setMediaItem()
@ -280,7 +283,7 @@ class BackgroundMode : Service() {
if (!this::autoPlayHelper.isInitialized) autoPlayHelper = AutoPlayHelper(playlistId!!) if (!this::autoPlayHelper.isInitialized) autoPlayHelper = AutoPlayHelper(playlistId!!)
// search for the next videoId in the playlist // search for the next videoId in the playlist
CoroutineScope(Dispatchers.IO).launch { CoroutineScope(Dispatchers.IO).launch {
nextStreamId = autoPlayHelper.getNextVideoId(videoId, streams!!.relatedStreams!!) nextStreamId = autoPlayHelper.getNextVideoId(videoId)
} }
} }

View File

@ -81,8 +81,6 @@ class HomeFragment : BaseFragment() {
} finally { } finally {
binding.homeRefresh.isRefreshing = false binding.homeRefresh.isRefreshing = false
} }
// TODO() REMOVE TESTING
PlayingQueue.streams = response
runOnUiThread { runOnUiThread {
binding.progressBar.visibility = View.GONE binding.progressBar.visibility = View.GONE

View File

@ -52,6 +52,7 @@ import com.github.libretube.extensions.formatShort
import com.github.libretube.extensions.hideKeyboard import com.github.libretube.extensions.hideKeyboard
import com.github.libretube.extensions.query import com.github.libretube.extensions.query
import com.github.libretube.extensions.toID import com.github.libretube.extensions.toID
import com.github.libretube.extensions.toStreamItem
import com.github.libretube.models.PlayerViewModel import com.github.libretube.models.PlayerViewModel
import com.github.libretube.models.interfaces.PlayerOptionsInterface import com.github.libretube.models.interfaces.PlayerOptionsInterface
import com.github.libretube.services.BackgroundMode import com.github.libretube.services.BackgroundMode
@ -635,8 +636,6 @@ class PlayerFragment : BaseFragment() {
private fun playVideo() { private fun playVideo() {
lifecycleScope.launchWhenCreated { lifecycleScope.launchWhenCreated {
PlayingQueue.updateCurrent(videoId!!)
streams = try { streams = try {
RetrofitInstance.api.getStreams(videoId!!) RetrofitInstance.api.getStreams(videoId!!)
} catch (e: IOException) { } catch (e: IOException) {
@ -650,6 +649,12 @@ class PlayerFragment : BaseFragment() {
return@launchWhenCreated return@launchWhenCreated
} }
PlayingQueue.updateCurrent(streams.toStreamItem(videoId!!))
if (PlayingQueue.size() <= 1) PlayingQueue.add(
*streams.relatedStreams.orEmpty().toTypedArray()
)
runOnUiThread { runOnUiThread {
// hide the button to skip SponsorBlock segments manually // hide the button to skip SponsorBlock segments manually
binding.sbSkipBtn.visibility = View.GONE binding.sbSkipBtn.visibility = View.GONE
@ -694,7 +699,7 @@ class PlayerFragment : BaseFragment() {
if (!this::autoPlayHelper.isInitialized) autoPlayHelper = AutoPlayHelper(playlistId) if (!this::autoPlayHelper.isInitialized) autoPlayHelper = AutoPlayHelper(playlistId)
// search for the next videoId in the playlist // search for the next videoId in the playlist
lifecycleScope.launchWhenCreated { lifecycleScope.launchWhenCreated {
nextStreamId = autoPlayHelper.getNextVideoId(videoId!!, streams.relatedStreams) nextStreamId = autoPlayHelper.getNextVideoId(videoId!!)
} }
} }

View File

@ -27,7 +27,7 @@ class PlayingQueueSheet : BottomSheetDialogFragment() {
binding.optionsRecycler.layoutManager = LinearLayoutManager(context) binding.optionsRecycler.layoutManager = LinearLayoutManager(context)
binding.optionsRecycler.adapter = PlayingQueueAdapter( binding.optionsRecycler.adapter = PlayingQueueAdapter(
PlayingQueue.streams PlayingQueue.getStreams()
) )
} }
} }

View File

@ -3,8 +3,10 @@ package com.github.libretube.ui.sheets
import android.os.Bundle import android.os.Bundle
import android.widget.Toast import android.widget.Toast
import com.github.libretube.R import com.github.libretube.R
import com.github.libretube.api.RetrofitInstance
import com.github.libretube.constants.IntentData import com.github.libretube.constants.IntentData
import com.github.libretube.constants.ShareObjectType import com.github.libretube.constants.ShareObjectType
import com.github.libretube.extensions.toStreamItem
import com.github.libretube.ui.dialogs.AddToPlaylistDialog import com.github.libretube.ui.dialogs.AddToPlaylistDialog
import com.github.libretube.ui.dialogs.DownloadDialog import com.github.libretube.ui.dialogs.DownloadDialog
import com.github.libretube.ui.dialogs.ShareDialog import com.github.libretube.ui.dialogs.ShareDialog
@ -12,6 +14,9 @@ import com.github.libretube.ui.views.BottomSheet
import com.github.libretube.util.BackgroundHelper import com.github.libretube.util.BackgroundHelper
import com.github.libretube.util.PlayingQueue import com.github.libretube.util.PlayingQueue
import com.github.libretube.util.PreferenceHelper import com.github.libretube.util.PreferenceHelper
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
/** /**
* Dialog with different options for a selected video. * Dialog with different options for a selected video.
@ -79,10 +84,28 @@ class VideoOptionsBottomSheet(
shareDialog.show(parentFragmentManager, ShareDialog::class.java.name) shareDialog.show(parentFragmentManager, ShareDialog::class.java.name)
} }
context?.getString(R.string.play_next) -> { context?.getString(R.string.play_next) -> {
PlayingQueue.addAsNext(videoId) CoroutineScope(Dispatchers.IO).launch {
try {
PlayingQueue.addAsNext(
RetrofitInstance.api.getStreams(videoId)
.toStreamItem(videoId)
)
} catch (e: Exception) {
e.printStackTrace()
}
}
} }
context?.getString(R.string.add_to_queue) -> { context?.getString(R.string.add_to_queue) -> {
PlayingQueue.add(videoId) CoroutineScope(Dispatchers.IO).launch {
try {
PlayingQueue.add(
RetrofitInstance.api.getStreams(videoId)
.toStreamItem(videoId)
)
} catch (e: Exception) {
e.printStackTrace()
}
}
} }
} }
} }

View File

@ -16,13 +16,10 @@ class AutoPlayHelper(
* get the id of the next video to be played * get the id of the next video to be played
*/ */
suspend fun getNextVideoId( suspend fun getNextVideoId(
currentVideoId: String, currentVideoId: String
relatedStreams: List<com.github.libretube.api.obj.StreamItem>?
): String? { ): String? {
return if (playlistId == null) { return if (playlistId == null) {
getNextTrendingVideoId( null
relatedStreams
)
} else { } else {
getNextPlaylistVideoId( getNextPlaylistVideoId(
currentVideoId currentVideoId
@ -30,27 +27,6 @@ class AutoPlayHelper(
} }
} }
/**
* get the id of the next related video
*/
private fun getNextTrendingVideoId(
relatedStreams: List<com.github.libretube.api.obj.StreamItem>?
): String? {
// don't play a video if it got played before already
if (relatedStreams == null || relatedStreams.isEmpty()) return null
var index = 0
var nextStreamId: String? = null
while (nextStreamId == null || PlayingQueue.containsBeforeCurrent(nextStreamId)) {
nextStreamId = relatedStreams[index].url!!.toID()
if (index + 1 < relatedStreams.size) {
index += 1
} else {
break
}
}
return nextStreamId
}
/** /**
* get the videoId of the next video in a playlist * get the videoId of the next video in a playlist
*/ */

View File

@ -1,58 +1,63 @@
package com.github.libretube.util package com.github.libretube.util
import com.github.libretube.api.obj.StreamItem import com.github.libretube.api.obj.StreamItem
import com.github.libretube.extensions.toID
object PlayingQueue { object PlayingQueue {
private val queue = mutableListOf<String>() private val queue = mutableListOf<StreamItem>()
private var currentVideoId: String? = null private var currentStream: StreamItem? = null
var streams: List<StreamItem> = listOf()
fun add(videoId: String) { fun add(vararg streamItem: StreamItem) {
if (currentVideoId == videoId) return streamItem.forEach {
if (queue.contains(videoId)) queue.remove(videoId) if (currentStream != it) {
queue.add(videoId) if (queue.contains(it)) queue.remove(it)
queue.add(it)
}
}
} }
fun addAsNext(videoId: String) { fun addAsNext(streamItem: StreamItem) {
if (currentVideoId == videoId) return if (currentStream == streamItem) return
if (queue.contains(videoId)) queue.remove(videoId) if (queue.contains(streamItem)) queue.remove(streamItem)
queue.add( queue.add(
queue.indexOf(currentVideoId) + 1, currentIndex() + 1,
videoId streamItem
) )
} }
fun getNext(): String? { fun getNext(): String? {
return try { return try {
queue[currentIndex() + 1] queue[currentIndex() + 1].url?.toID()
} catch (e: Exception) { } catch (e: Exception) {
null null
} }
} }
fun getPrev(): String? { fun getPrev(): String? {
val index = queue.indexOf(currentVideoId) val index = queue.indexOf(currentStream)
return if (index > 0) queue[index - 1] else null return if (index > 0) queue[index - 1].url?.toID() else null
} }
fun hasPrev(): Boolean { fun hasPrev(): Boolean {
return queue.indexOf(currentVideoId) > 0 return queue.indexOf(currentStream) > 0
} }
fun updateCurrent(videoId: String) { fun updateCurrent(streamItem: StreamItem) {
currentVideoId = videoId currentStream = streamItem
queue.add(videoId) queue.add(streamItem)
} }
fun isNotEmpty() = queue.isNotEmpty() fun isNotEmpty() = queue.isNotEmpty()
fun isEmpty() = queue.isEmpty()
fun clear() = queue.clear() fun clear() = queue.clear()
fun currentIndex() = queue.indexOf(currentVideoId) fun size() = queue.size
fun contains(videoId: String) = queue.contains(videoId) private fun currentIndex() = queue.indexOf(currentStream)
fun containsBeforeCurrent(videoId: String): Boolean { fun contains(streamItem: StreamItem) = queue.contains(streamItem)
return queue.contains(videoId) && queue.indexOf(videoId) < currentIndex()
} fun getStreams() = queue
} }