Merge pull request #2180 from Bnyro/channel-share

Option to shar channels and play their latest videos
This commit is contained in:
Bnyro 2022-12-02 14:46:43 +01:00 committed by GitHub
commit 974ecb04a4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 154 additions and 20 deletions

View File

@ -22,7 +22,6 @@ import com.github.libretube.constants.PLAYER_NOTIFICATION_ID
import com.github.libretube.constants.PreferenceKeys import com.github.libretube.constants.PreferenceKeys
import com.github.libretube.db.DatabaseHolder.Companion.Database import com.github.libretube.db.DatabaseHolder.Companion.Database
import com.github.libretube.db.obj.WatchPosition import com.github.libretube.db.obj.WatchPosition
import com.github.libretube.enums.PlaylistType
import com.github.libretube.extensions.awaitQuery import com.github.libretube.extensions.awaitQuery
import com.github.libretube.extensions.query import com.github.libretube.extensions.query
import com.github.libretube.extensions.toID import com.github.libretube.extensions.toID
@ -51,10 +50,10 @@ class BackgroundMode : Service() {
private lateinit var videoId: String private lateinit var videoId: String
/** /**
*PlaylistId for autoplay * PlaylistId/ChannelId for autoplay
*/ */
private var playlistId: String? = null private var playlistId: String? = null
private var playlistType: PlaylistType? = null private var channelId: String? = null
/** /**
* The response that gets when called the Api. * The response that gets when called the Api.
@ -162,11 +161,14 @@ class BackgroundMode : Service() {
} }
// add the playlist video to the queue // add the playlist video to the queue
if (playlistId != null && PlayingQueue.isEmpty()) { if (PlayingQueue.isEmpty() && playlistId != null) {
streams?.toStreamItem(videoId) streams?.toStreamItem(videoId)?.let {
?.let { PlayingQueue.insertPlaylist(playlistId!!, it)
PlayingQueue.insertPlaylist(playlistId!!, it) }
} } else if (PlayingQueue.isEmpty() && channelId != null) {
streams?.toStreamItem(videoId)?.let {
PlayingQueue.insertChannel(channelId!!, it)
}
} else { } else {
streams?.toStreamItem(videoId)?.let { streams?.toStreamItem(videoId)?.let {
PlayingQueue.updateCurrent(it) PlayingQueue.updateCurrent(it)

View File

@ -5,6 +5,8 @@ import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.github.libretube.databinding.LegacySubscriptionChannelBinding import com.github.libretube.databinding.LegacySubscriptionChannelBinding
import com.github.libretube.extensions.toID import com.github.libretube.extensions.toID
import com.github.libretube.ui.base.BaseActivity
import com.github.libretube.ui.sheets.ChannelOptionsBottomSheet
import com.github.libretube.ui.viewholders.LegacySubscriptionViewHolder import com.github.libretube.ui.viewholders.LegacySubscriptionViewHolder
import com.github.libretube.util.ImageHelper import com.github.libretube.util.ImageHelper
import com.github.libretube.util.NavigationHelper import com.github.libretube.util.NavigationHelper
@ -36,6 +38,12 @@ class LegacySubscriptionAdapter(
subscription.url!!.toID() subscription.url!!.toID()
) )
} }
root.setOnLongClickListener {
ChannelOptionsBottomSheet(subscription.url!!.toID(), subscription.name)
.show((root.context as BaseActivity).supportFragmentManager)
true
}
} }
} }

View File

@ -17,6 +17,7 @@ import com.github.libretube.ui.base.BaseActivity
import com.github.libretube.ui.extensions.setFormattedDuration import com.github.libretube.ui.extensions.setFormattedDuration
import com.github.libretube.ui.extensions.setWatchProgressLength import com.github.libretube.ui.extensions.setWatchProgressLength
import com.github.libretube.ui.extensions.setupSubscriptionButton import com.github.libretube.ui.extensions.setupSubscriptionButton
import com.github.libretube.ui.sheets.ChannelOptionsBottomSheet
import com.github.libretube.ui.sheets.PlaylistOptionsBottomSheet import com.github.libretube.ui.sheets.PlaylistOptionsBottomSheet
import com.github.libretube.ui.sheets.VideoOptionsBottomSheet import com.github.libretube.ui.sheets.VideoOptionsBottomSheet
import com.github.libretube.ui.viewholders.SearchViewHolder import com.github.libretube.ui.viewholders.SearchViewHolder
@ -127,6 +128,12 @@ class SearchAdapter(
NavigationHelper.navigateChannel(root.context, item.url) NavigationHelper.navigateChannel(root.context, item.url)
} }
root.setOnLongClickListener {
ChannelOptionsBottomSheet(item.url!!.toID(), item.name)
.show((root.context as BaseActivity).supportFragmentManager)
true
}
binding.searchSubButton.setupSubscriptionButton(item.url?.toID(), item.name?.toID()) binding.searchSubButton.setupSubscriptionButton(item.url?.toID(), item.name?.toID())
} }
} }

View File

@ -6,7 +6,9 @@ import androidx.recyclerview.widget.RecyclerView
import com.github.libretube.api.obj.Subscription import com.github.libretube.api.obj.Subscription
import com.github.libretube.databinding.ChannelSubscriptionRowBinding import com.github.libretube.databinding.ChannelSubscriptionRowBinding
import com.github.libretube.extensions.toID import com.github.libretube.extensions.toID
import com.github.libretube.ui.base.BaseActivity
import com.github.libretube.ui.extensions.setupSubscriptionButton import com.github.libretube.ui.extensions.setupSubscriptionButton
import com.github.libretube.ui.sheets.ChannelOptionsBottomSheet
import com.github.libretube.ui.viewholders.SubscriptionChannelViewHolder import com.github.libretube.ui.viewholders.SubscriptionChannelViewHolder
import com.github.libretube.util.ImageHelper import com.github.libretube.util.ImageHelper
import com.github.libretube.util.NavigationHelper import com.github.libretube.util.NavigationHelper
@ -36,6 +38,12 @@ class SubscriptionChannelAdapter(
root.setOnClickListener { root.setOnClickListener {
NavigationHelper.navigateChannel(root.context, subscription.url) NavigationHelper.navigateChannel(root.context, subscription.url)
} }
root.setOnLongClickListener {
ChannelOptionsBottomSheet(subscription.url!!.toID(), subscription.name)
.show((root.context as BaseActivity).supportFragmentManager)
true
}
subscriptionSubscribe.setupSubscriptionButton( subscriptionSubscribe.setupSubscriptionButton(
subscription.url?.toID(), subscription.url?.toID(),
subscription.name, subscription.name,

View File

@ -127,6 +127,7 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
*/ */
private var videoId: String? = null private var videoId: String? = null
private var playlistId: String? = null private var playlistId: String? = null
private var channelId: String? = null
private var isLive = false private var isLive = false
private lateinit var streams: Streams private lateinit var streams: Streams
@ -172,6 +173,7 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
arguments?.let { arguments?.let {
videoId = it.getString(IntentData.videoId)!!.toID() videoId = it.getString(IntentData.videoId)!!.toID()
playlistId = it.getString(IntentData.playlistId) playlistId = it.getString(IntentData.playlistId)
channelId = it.getString(IntentData.channelId)
} }
} }
@ -399,7 +401,8 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
requireContext(), requireContext(),
videoId!!, videoId!!,
exoPlayer.currentPosition, exoPlayer.currentPosition,
playlistId playlistId,
channelId
) )
} }
@ -593,6 +596,8 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
CoroutineScope(Dispatchers.IO).launch { CoroutineScope(Dispatchers.IO).launch {
if (playlistId != null) { if (playlistId != null) {
PlayingQueue.insertPlaylist(playlistId!!, streams.toStreamItem(videoId!!)) PlayingQueue.insertPlaylist(playlistId!!, streams.toStreamItem(videoId!!))
} else if (channelId != null) {
PlayingQueue.insertChannel(channelId!!, streams.toStreamItem(videoId!!))
} else { } else {
PlayingQueue.updateCurrent(streams.toStreamItem(videoId!!)) PlayingQueue.updateCurrent(streams.toStreamItem(videoId!!))
if (PlayerHelper.autoInsertRelatedVideos) { if (PlayerHelper.autoInsertRelatedVideos) {

View File

@ -0,0 +1,77 @@
package com.github.libretube.ui.sheets
import android.os.Bundle
import android.util.Log
import com.github.libretube.R
import com.github.libretube.api.RetrofitInstance
import com.github.libretube.enums.ShareObjectType
import com.github.libretube.extensions.TAG
import com.github.libretube.extensions.toID
import com.github.libretube.obj.ShareData
import com.github.libretube.ui.dialogs.ShareDialog
import com.github.libretube.util.BackgroundHelper
import com.github.libretube.util.NavigationHelper
import kotlinx.coroutines.runBlocking
/**
* Dialog with different options for a selected video.
*
* Needs the [videoId] to load the content from the right video.
*/
class ChannelOptionsBottomSheet(
private val channelId: String,
private val channelName: String?
) : BaseBottomSheet() {
private val shareData = ShareData(currentChannel = channelName)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// List that stores the different menu options. In the future could be add more options here.
val optionsList = mutableListOf(
getString(R.string.share),
getString(R.string.play_latest_videos),
getString(R.string.playOnBackground)
)
setSimpleItems(optionsList) { which ->
when (optionsList[which]) {
getString(R.string.share) -> {
ShareDialog(channelId, ShareObjectType.CHANNEL, shareData)
.show(parentFragmentManager, null)
}
getString(R.string.play_latest_videos) -> {
try {
val channel = runBlocking {
RetrofitInstance.api.getChannel(channelId)
}
channel.relatedStreams?.firstOrNull()?.url?.toID()?.let {
NavigationHelper.navigateVideo(
requireContext(),
it,
channelId = channelId
)
}
} catch (e: Exception) {
Log.e(TAG(), e.toString())
}
}
getString(R.string.playOnBackground) -> {
try {
val channel = runBlocking {
RetrofitInstance.api.getChannel(channelId)
}
channel.relatedStreams?.firstOrNull()?.url?.toID()?.let {
BackgroundHelper.playOnBackground(
requireContext(),
videoId = it,
channelId = channelId
)
}
} catch (e: Exception) {
Log.e(TAG(), e.toString())
}
}
}
}
}
}

View File

@ -20,13 +20,15 @@ object BackgroundHelper {
context: Context, context: Context,
videoId: String, videoId: String,
position: Long? = null, position: Long? = null,
playlistId: String? = null playlistId: String? = null,
channelId: String? = null
) { ) {
// create an intent for the background mode service // create an intent for the background mode service
val intent = Intent(context, BackgroundMode::class.java) val intent = Intent(context, BackgroundMode::class.java)
intent.putExtra(IntentData.videoId, videoId) intent.putExtra(IntentData.videoId, videoId)
if (playlistId != null) intent.putExtra(IntentData.playlistId, playlistId) intent.putExtra(IntentData.playlistId, playlistId)
if (position != null) intent.putExtra("position", position) intent.putExtra(IntentData.channelId, channelId)
intent.putExtra("position", position)
// start the background mode as foreground service // start the background mode as foreground service
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O) {

View File

@ -48,13 +48,16 @@ object NavigationHelper {
fun navigateVideo( fun navigateVideo(
context: Context, context: Context,
videoId: String?, videoId: String?,
playlistId: String? = null playlistId: String? = null,
channelId: String? = null
) { ) {
if (videoId == null) return if (videoId == null) return
val bundle = Bundle() val bundle = Bundle()
bundle.putString(IntentData.videoId, videoId.toID()) bundle.putString(IntentData.videoId, videoId.toID())
if (playlistId != null) bundle.putString(IntentData.playlistId, playlistId) bundle.putString(IntentData.playlistId, playlistId)
bundle.putString(IntentData.channelId, channelId)
val frag = PlayerFragment() val frag = PlayerFragment()
frag.arguments = bundle frag.arguments = bundle
val activity = context as AppCompatActivity val activity = context as AppCompatActivity

View File

@ -110,13 +110,8 @@ object PlayingQueue {
fun insertPlaylist(playlistId: String, newCurrentStream: StreamItem) { fun insertPlaylist(playlistId: String, newCurrentStream: StreamItem) {
CoroutineScope(Dispatchers.IO).launch { CoroutineScope(Dispatchers.IO).launch {
try { try {
val playlistType = PlaylistsHelper.getPrivatePlaylistType(playlistId)
val playlist = PlaylistsHelper.getPlaylist(playlistId) val playlist = PlaylistsHelper.getPlaylist(playlistId)
add( add(*playlist.relatedStreams.orEmpty().toTypedArray())
*playlist.relatedStreams
.orEmpty()
.toTypedArray()
)
updateCurrent(newCurrentStream) updateCurrent(newCurrentStream)
if (playlist.nextpage == null) return@launch if (playlist.nextpage == null) return@launch
fetchMoreFromPlaylist(playlistId, playlist.nextpage) fetchMoreFromPlaylist(playlistId, playlist.nextpage)
@ -126,6 +121,32 @@ object PlayingQueue {
} }
} }
private fun fetchMoreFromChannel(channelId: String, nextPage: String?) {
var channelNextPage: String? = nextPage
CoroutineScope(Dispatchers.IO).launch {
while (channelNextPage != null) {
RetrofitInstance.api.getChannelNextPage(channelId, nextPage!!).apply {
add(*relatedStreams.orEmpty().toTypedArray())
channelNextPage = this.nextpage
}
}
}
}
fun insertChannel(channelId: String, newCurrentStream: StreamItem) {
CoroutineScope(Dispatchers.IO).launch {
try {
val channel = RetrofitInstance.api.getChannel(channelId)
add(*channel.relatedStreams.orEmpty().toTypedArray())
updateCurrent(newCurrentStream)
if (channel.nextpage == null) return@launch
fetchMoreFromChannel(channelId, channel.nextpage)
} catch (e: Exception) {
e.printStackTrace()
}
}
}
fun onQueueItemSelected(index: Int) { fun onQueueItemSelected(index: Int) {
try { try {
val streamItem = queue[index] val streamItem = queue[index]

View File

@ -414,6 +414,7 @@
<string name="privacy_alert">Privacy alert</string> <string name="privacy_alert">Privacy alert</string>
<string name="username_email">Proceed with an e-mail address that isn\'t recommended\?</string> <string name="username_email">Proceed with an e-mail address that isn\'t recommended\?</string>
<string name="proceed">Proceed</string> <string name="proceed">Proceed</string>
<string name="play_latest_videos">Play latest videos</string>
<!-- Notification channel strings --> <!-- Notification channel strings -->
<string name="download_channel_name">Download Service</string> <string name="download_channel_name">Download Service</string>