mirror of
https://github.com/libre-tube/LibreTube.git
synced 2025-04-27 15:30:31 +05:30
feat: smoother, frictionless transition between audio and video mode
This commit is contained in:
parent
b3e4a243a9
commit
caaa095faf
@ -14,7 +14,7 @@ object IntentData {
|
|||||||
const val timeStamp = "timeStamp"
|
const val timeStamp = "timeStamp"
|
||||||
const val playlistType = "playlistType"
|
const val playlistType = "playlistType"
|
||||||
const val downloading = "downloading"
|
const val downloading = "downloading"
|
||||||
const val openAudioPlayer = "openAudioPlayer"
|
const val maximizePlayer = "openAudioPlayer"
|
||||||
const val fragmentToOpen = "fragmentToOpen"
|
const val fragmentToOpen = "fragmentToOpen"
|
||||||
const val comment = "comment"
|
const val comment = "comment"
|
||||||
const val minimizeByDefault = "minimizeByDefault"
|
const val minimizeByDefault = "minimizeByDefault"
|
||||||
@ -60,4 +60,5 @@ object IntentData {
|
|||||||
const val alreadyStarted = "alreadyStarted"
|
const val alreadyStarted = "alreadyStarted"
|
||||||
const val showUpcoming = "showUpcoming"
|
const val showUpcoming = "showUpcoming"
|
||||||
const val customInstance = "customInstance"
|
const val customInstance = "customInstance"
|
||||||
|
const val audioOnly = "audioOnly"
|
||||||
}
|
}
|
||||||
|
@ -9,5 +9,6 @@ enum class PlayerCommand {
|
|||||||
SET_SUBTITLE,
|
SET_SUBTITLE,
|
||||||
SET_SB_AUTO_SKIP_ENABLED,
|
SET_SB_AUTO_SKIP_ENABLED,
|
||||||
PLAY_VIDEO_BY_ID,
|
PLAY_VIDEO_BY_ID,
|
||||||
SET_AUTOPLAY_COUNTDOWN_ENABLED
|
SET_AUTOPLAY_COUNTDOWN_ENABLED,
|
||||||
|
TOGGLE_AUDIO_ONLY_MODE
|
||||||
}
|
}
|
@ -18,7 +18,6 @@ import com.github.libretube.services.AbstractPlayerService
|
|||||||
import com.github.libretube.services.OfflinePlayerService
|
import com.github.libretube.services.OfflinePlayerService
|
||||||
import com.github.libretube.services.OnlinePlayerService
|
import com.github.libretube.services.OnlinePlayerService
|
||||||
import com.github.libretube.services.VideoOfflinePlayerService
|
import com.github.libretube.services.VideoOfflinePlayerService
|
||||||
import com.github.libretube.services.VideoOnlinePlayerService
|
|
||||||
import com.github.libretube.ui.activities.MainActivity
|
import com.github.libretube.ui.activities.MainActivity
|
||||||
import com.github.libretube.ui.activities.NoInternetActivity
|
import com.github.libretube.ui.activities.NoInternetActivity
|
||||||
import com.github.libretube.ui.fragments.DownloadTab
|
import com.github.libretube.ui.fragments.DownloadTab
|
||||||
@ -56,7 +55,7 @@ object BackgroundHelper {
|
|||||||
startMediaService(
|
startMediaService(
|
||||||
context,
|
context,
|
||||||
OnlinePlayerService::class.java,
|
OnlinePlayerService::class.java,
|
||||||
bundleOf(IntentData.playerData to playerData)
|
bundleOf(IntentData.playerData to playerData, IntentData.audioOnly to true)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,8 +66,7 @@ object BackgroundHelper {
|
|||||||
arrayOf(
|
arrayOf(
|
||||||
OnlinePlayerService::class.java,
|
OnlinePlayerService::class.java,
|
||||||
OfflinePlayerService::class.java,
|
OfflinePlayerService::class.java,
|
||||||
VideoOfflinePlayerService::class.java,
|
VideoOfflinePlayerService::class.java
|
||||||
VideoOnlinePlayerService::class.java
|
|
||||||
).forEach {
|
).forEach {
|
||||||
val intent = Intent(context, it)
|
val intent = Intent(context, it)
|
||||||
context.stopService(intent)
|
context.stopService(intent)
|
||||||
@ -117,7 +115,6 @@ object BackgroundHelper {
|
|||||||
context: Context,
|
context: Context,
|
||||||
serviceClass: Class<*>,
|
serviceClass: Class<*>,
|
||||||
arguments: Bundle = Bundle.EMPTY,
|
arguments: Bundle = Bundle.EMPTY,
|
||||||
sendStartCommand: Boolean = true,
|
|
||||||
onController: (MediaController) -> Unit = {}
|
onController: (MediaController) -> Unit = {}
|
||||||
) {
|
) {
|
||||||
val sessionToken =
|
val sessionToken =
|
||||||
@ -127,7 +124,7 @@ object BackgroundHelper {
|
|||||||
MediaController.Builder(context, sessionToken).buildAsync()
|
MediaController.Builder(context, sessionToken).buildAsync()
|
||||||
controllerFuture.addListener({
|
controllerFuture.addListener({
|
||||||
val controller = controllerFuture.get()
|
val controller = controllerFuture.get()
|
||||||
if (sendStartCommand) controller.sendCustomCommand(
|
if (!arguments.isEmpty) controller.sendCustomCommand(
|
||||||
AbstractPlayerService.startServiceCommand,
|
AbstractPlayerService.startServiceCommand,
|
||||||
arguments
|
arguments
|
||||||
)
|
)
|
||||||
|
@ -59,6 +59,7 @@ object NavigationHelper {
|
|||||||
channelId: String? = null,
|
channelId: String? = null,
|
||||||
keepQueue: Boolean = false,
|
keepQueue: Boolean = false,
|
||||||
timestamp: Long = 0,
|
timestamp: Long = 0,
|
||||||
|
alreadyStarted: Boolean = false,
|
||||||
forceVideo: Boolean = false
|
forceVideo: Boolean = false
|
||||||
) {
|
) {
|
||||||
if (videoUrlOrId == null) return
|
if (videoUrlOrId == null) return
|
||||||
@ -85,7 +86,10 @@ object NavigationHelper {
|
|||||||
|
|
||||||
val playerData =
|
val playerData =
|
||||||
PlayerData(videoUrlOrId.toID(), playlistId, channelId, keepQueue, timestamp)
|
PlayerData(videoUrlOrId.toID(), playlistId, channelId, keepQueue, timestamp)
|
||||||
val bundle = bundleOf(IntentData.playerData to playerData)
|
val bundle = bundleOf(
|
||||||
|
IntentData.playerData to playerData,
|
||||||
|
IntentData.alreadyStarted to alreadyStarted
|
||||||
|
)
|
||||||
activity.supportFragmentManager.commitNow {
|
activity.supportFragmentManager.commitNow {
|
||||||
replace<PlayerFragment>(R.id.container, args = bundle)
|
replace<PlayerFragment>(R.id.container, args = bundle)
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ import androidx.media3.common.ForwardingPlayer
|
|||||||
import androidx.media3.common.MediaMetadata
|
import androidx.media3.common.MediaMetadata
|
||||||
import androidx.media3.common.PlaybackException
|
import androidx.media3.common.PlaybackException
|
||||||
import androidx.media3.common.Player
|
import androidx.media3.common.Player
|
||||||
|
import androidx.media3.common.util.Log
|
||||||
import androidx.media3.common.util.UnstableApi
|
import androidx.media3.common.util.UnstableApi
|
||||||
import androidx.media3.exoplayer.ExoPlayer
|
import androidx.media3.exoplayer.ExoPlayer
|
||||||
import androidx.media3.exoplayer.trackselection.DefaultTrackSelector
|
import androidx.media3.exoplayer.trackselection.DefaultTrackSelector
|
||||||
@ -118,6 +119,13 @@ abstract class AbstractPlayerService : MediaLibraryService(), MediaLibrarySessio
|
|||||||
onServiceCreated(args)
|
onServiceCreated(args)
|
||||||
notificationProvider?.intentActivity = getIntentActivity()
|
notificationProvider?.intentActivity = getIntentActivity()
|
||||||
|
|
||||||
|
if (isAudioOnlyPlayer) {
|
||||||
|
trackSelector?.updateParameters {
|
||||||
|
setTrackTypeDisabled(C.TRACK_TYPE_VIDEO, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.e("custom start", "custom start")
|
||||||
if (::videoId.isInitialized) startPlayback()
|
if (::videoId.isInitialized) startPlayback()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -179,6 +187,13 @@ abstract class AbstractPlayerService : MediaLibraryService(), MediaLibrarySessio
|
|||||||
args.containsKey(PlayerCommand.PLAY_VIDEO_BY_ID.name) -> {
|
args.containsKey(PlayerCommand.PLAY_VIDEO_BY_ID.name) -> {
|
||||||
navigateVideo(args.getString(PlayerCommand.PLAY_VIDEO_BY_ID.name) ?: return)
|
navigateVideo(args.getString(PlayerCommand.PLAY_VIDEO_BY_ID.name) ?: return)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
args.containsKey(PlayerCommand.TOGGLE_AUDIO_ONLY_MODE.name) -> {
|
||||||
|
isAudioOnlyPlayer = args.getBoolean(PlayerCommand.TOGGLE_AUDIO_ONLY_MODE.name)
|
||||||
|
trackSelector?.updateParameters {
|
||||||
|
setTrackTypeDisabled(C.TRACK_TYPE_VIDEO, isAudioOnlyPlayer)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,7 +248,8 @@ abstract class AbstractPlayerService : MediaLibraryService(), MediaLibrarySessio
|
|||||||
}
|
}
|
||||||
|
|
||||||
abstract val isOfflinePlayer: Boolean
|
abstract val isOfflinePlayer: Boolean
|
||||||
abstract val isAudioOnlyPlayer: Boolean
|
abstract var isAudioOnlyPlayer: Boolean
|
||||||
|
open val maximizePlayer: Boolean = true
|
||||||
|
|
||||||
val watchPositionsEnabled get() =
|
val watchPositionsEnabled get() =
|
||||||
(PlayerHelper.watchPositionsAudio && isAudioOnlyPlayer) || (PlayerHelper.watchPositionsVideo && !isAudioOnlyPlayer)
|
(PlayerHelper.watchPositionsAudio && isAudioOnlyPlayer) || (PlayerHelper.watchPositionsVideo && !isAudioOnlyPlayer)
|
||||||
@ -246,7 +262,6 @@ abstract class AbstractPlayerService : MediaLibraryService(), MediaLibrarySessio
|
|||||||
|
|
||||||
notificationProvider = NowPlayingNotification(
|
notificationProvider = NowPlayingNotification(
|
||||||
this,
|
this,
|
||||||
backgroundOnly = isAudioOnlyPlayer,
|
|
||||||
offlinePlayer = isOfflinePlayer,
|
offlinePlayer = isOfflinePlayer,
|
||||||
)
|
)
|
||||||
setMediaNotificationProvider(notificationProvider!!)
|
setMediaNotificationProvider(notificationProvider!!)
|
||||||
@ -293,12 +308,6 @@ abstract class AbstractPlayerService : MediaLibraryService(), MediaLibrarySessio
|
|||||||
val trackSelector = DefaultTrackSelector(this)
|
val trackSelector = DefaultTrackSelector(this)
|
||||||
this.trackSelector = trackSelector
|
this.trackSelector = trackSelector
|
||||||
|
|
||||||
if (isAudioOnlyPlayer) {
|
|
||||||
trackSelector.updateParameters {
|
|
||||||
setTrackTypeDisabled(C.TRACK_TYPE_VIDEO, true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val player = PlayerHelper.createPlayer(this, trackSelector, true)
|
val player = PlayerHelper.createPlayer(this, trackSelector, true)
|
||||||
// prevent android from putting LibreTube to sleep when locked
|
// prevent android from putting LibreTube to sleep when locked
|
||||||
player.setWakeMode(if (isOfflinePlayer) C.WAKE_MODE_LOCAL else C.WAKE_MODE_NETWORK)
|
player.setWakeMode(if (isOfflinePlayer) C.WAKE_MODE_LOCAL else C.WAKE_MODE_NETWORK)
|
||||||
|
@ -33,7 +33,7 @@ import kotlin.io.path.exists
|
|||||||
@OptIn(UnstableApi::class)
|
@OptIn(UnstableApi::class)
|
||||||
open class OfflinePlayerService : AbstractPlayerService() {
|
open class OfflinePlayerService : AbstractPlayerService() {
|
||||||
override val isOfflinePlayer: Boolean = true
|
override val isOfflinePlayer: Boolean = true
|
||||||
override val isAudioOnlyPlayer: Boolean = true
|
override var isAudioOnlyPlayer: Boolean = true
|
||||||
private var noInternetService: Boolean = false
|
private var noInternetService: Boolean = false
|
||||||
|
|
||||||
private var downloadWithItems: DownloadWithItems? = null
|
private var downloadWithItems: DownloadWithItems? = null
|
||||||
|
@ -8,6 +8,7 @@ import androidx.media3.common.MediaItem
|
|||||||
import androidx.media3.common.MediaItem.SubtitleConfiguration
|
import androidx.media3.common.MediaItem.SubtitleConfiguration
|
||||||
import androidx.media3.common.MimeTypes
|
import androidx.media3.common.MimeTypes
|
||||||
import androidx.media3.common.Player
|
import androidx.media3.common.Player
|
||||||
|
import androidx.media3.common.util.Log
|
||||||
import androidx.media3.datasource.DefaultDataSource
|
import androidx.media3.datasource.DefaultDataSource
|
||||||
import androidx.media3.exoplayer.hls.HlsMediaSource
|
import androidx.media3.exoplayer.hls.HlsMediaSource
|
||||||
import com.github.libretube.R
|
import com.github.libretube.R
|
||||||
@ -45,7 +46,7 @@ import java.io.IOException
|
|||||||
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
|
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
|
||||||
open class OnlinePlayerService : AbstractPlayerService() {
|
open class OnlinePlayerService : AbstractPlayerService() {
|
||||||
override val isOfflinePlayer: Boolean = false
|
override val isOfflinePlayer: Boolean = false
|
||||||
override val isAudioOnlyPlayer: Boolean = true
|
override var isAudioOnlyPlayer: Boolean = false
|
||||||
|
|
||||||
// PlaylistId/ChannelId for autoplay
|
// PlaylistId/ChannelId for autoplay
|
||||||
private var playlistId: String? = null
|
private var playlistId: String? = null
|
||||||
@ -100,6 +101,7 @@ open class OnlinePlayerService : AbstractPlayerService() {
|
|||||||
stopSelf()
|
stopSelf()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
isAudioOnlyPlayer = args.getBoolean(IntentData.audioOnly)
|
||||||
|
|
||||||
// get the intent arguments
|
// get the intent arguments
|
||||||
setVideoId(playerData.videoId)
|
setVideoId(playerData.videoId)
|
||||||
@ -115,6 +117,8 @@ open class OnlinePlayerService : AbstractPlayerService() {
|
|||||||
override suspend fun startPlayback() {
|
override suspend fun startPlayback() {
|
||||||
super.startPlayback()
|
super.startPlayback()
|
||||||
|
|
||||||
|
Log.e("start", "playback")
|
||||||
|
|
||||||
val timestampMs = startTimestampSeconds?.times(1000) ?: 0L
|
val timestampMs = startTimestampSeconds?.times(1000) ?: 0L
|
||||||
startTimestampSeconds = null
|
startTimestampSeconds = null
|
||||||
|
|
||||||
@ -196,6 +200,8 @@ open class OnlinePlayerService : AbstractPlayerService() {
|
|||||||
this.streams = null
|
this.streams = null
|
||||||
this.sponsorBlockSegments = emptyList()
|
this.sponsorBlockSegments = emptyList()
|
||||||
|
|
||||||
|
Log.e("play next", "play next")
|
||||||
|
|
||||||
scope.launch {
|
scope.launch {
|
||||||
startPlayback()
|
startPlayback()
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ import kotlin.io.path.exists
|
|||||||
|
|
||||||
@OptIn(UnstableApi::class)
|
@OptIn(UnstableApi::class)
|
||||||
class VideoOfflinePlayerService: OfflinePlayerService() {
|
class VideoOfflinePlayerService: OfflinePlayerService() {
|
||||||
override val isAudioOnlyPlayer = false
|
override var isAudioOnlyPlayer = false
|
||||||
|
|
||||||
override fun setMediaItem(downloadWithItems: DownloadWithItems) {
|
override fun setMediaItem(downloadWithItems: DownloadWithItems) {
|
||||||
val downloadFiles = downloadWithItems.downloadItems.filter { it.path.exists() }
|
val downloadFiles = downloadWithItems.downloadItems.filter { it.path.exists() }
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
package com.github.libretube.services
|
|
||||||
|
|
||||||
import androidx.annotation.OptIn
|
|
||||||
import androidx.media3.common.util.UnstableApi
|
|
||||||
|
|
||||||
@OptIn(UnstableApi::class)
|
|
||||||
class VideoOnlinePlayerService : OnlinePlayerService() {
|
|
||||||
override val isAudioOnlyPlayer: Boolean = false
|
|
||||||
}
|
|
@ -433,7 +433,12 @@ class MainActivity : BaseActivity() {
|
|||||||
startActivity(nIntent)
|
startActivity(nIntent)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (intent?.getBooleanExtra(IntentData.openAudioPlayer, false) == true) {
|
if (intent?.getBooleanExtra(IntentData.maximizePlayer, false) == true) {
|
||||||
|
// attempt to open the current player fragment first before creating a new one
|
||||||
|
// TODO: handle this differently
|
||||||
|
if (runOnPlayerFragment { binding.playerMotionLayout.transitionToStart(); true }) return
|
||||||
|
if (runOnAudioPlayerFragment { binding.playerMotionLayout.transitionToStart(); true }) return
|
||||||
|
|
||||||
val offlinePlayer = intent!!.getBooleanExtra(IntentData.offlinePlayer, false)
|
val offlinePlayer = intent!!.getBooleanExtra(IntentData.offlinePlayer, false)
|
||||||
NavigationHelper.openAudioPlayerFragment(this, offlinePlayer = offlinePlayer)
|
NavigationHelper.openAudioPlayerFragment(this, offlinePlayer = offlinePlayer)
|
||||||
return
|
return
|
||||||
|
@ -18,7 +18,7 @@ class NoInternetActivity : BaseActivity() {
|
|||||||
override fun onNewIntent(intent: Intent) {
|
override fun onNewIntent(intent: Intent) {
|
||||||
super.onNewIntent(intent)
|
super.onNewIntent(intent)
|
||||||
|
|
||||||
if (intent.getBooleanExtra(IntentData.openAudioPlayer, false)) {
|
if (intent.getBooleanExtra(IntentData.maximizePlayer, false)) {
|
||||||
NavigationHelper.openAudioPlayerFragment(this, offlinePlayer = true)
|
NavigationHelper.openAudioPlayerFragment(this, offlinePlayer = true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ import com.github.libretube.api.JsonHelper
|
|||||||
import com.github.libretube.api.obj.ChapterSegment
|
import com.github.libretube.api.obj.ChapterSegment
|
||||||
import com.github.libretube.constants.IntentData
|
import com.github.libretube.constants.IntentData
|
||||||
import com.github.libretube.databinding.FragmentAudioPlayerBinding
|
import com.github.libretube.databinding.FragmentAudioPlayerBinding
|
||||||
|
import com.github.libretube.enums.PlayerCommand
|
||||||
import com.github.libretube.extensions.navigateVideo
|
import com.github.libretube.extensions.navigateVideo
|
||||||
import com.github.libretube.extensions.normalize
|
import com.github.libretube.extensions.normalize
|
||||||
import com.github.libretube.extensions.seekBy
|
import com.github.libretube.extensions.seekBy
|
||||||
@ -174,13 +175,17 @@ class AudioPlayerFragment : Fragment(R.layout.fragment_audio_player), AudioPlaye
|
|||||||
}
|
}
|
||||||
|
|
||||||
binding.openVideo.setOnClickListener {
|
binding.openVideo.setOnClickListener {
|
||||||
killFragment()
|
playerController?.sendCustomCommand(
|
||||||
|
AbstractPlayerService.runPlayerActionCommand,
|
||||||
|
bundleOf(PlayerCommand.TOGGLE_AUDIO_ONLY_MODE.name to false)
|
||||||
|
)
|
||||||
|
|
||||||
|
killFragment(false)
|
||||||
|
|
||||||
NavigationHelper.navigateVideo(
|
NavigationHelper.navigateVideo(
|
||||||
context = requireContext(),
|
context = requireContext(),
|
||||||
videoUrlOrId = PlayingQueue.getCurrent()?.url,
|
videoUrlOrId = PlayingQueue.getCurrent()?.url,
|
||||||
timestamp = playerController?.currentPosition?.div(1000) ?: 0,
|
alreadyStarted = true,
|
||||||
keepQueue = true,
|
|
||||||
forceVideo = true
|
forceVideo = true
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -209,7 +214,7 @@ class AudioPlayerFragment : Fragment(R.layout.fragment_audio_player), AudioPlaye
|
|||||||
}
|
}
|
||||||
|
|
||||||
binding.miniPlayerClose.setOnClickListener {
|
binding.miniPlayerClose.setOnClickListener {
|
||||||
killFragment()
|
killFragment(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
val listener = AudioPlayerThumbnailListener(requireContext(), this)
|
val listener = AudioPlayerThumbnailListener(requireContext(), this)
|
||||||
@ -267,8 +272,8 @@ class AudioPlayerFragment : Fragment(R.layout.fragment_audio_player), AudioPlaye
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun killFragment() {
|
private fun killFragment(stopPlayer: Boolean) {
|
||||||
playerController?.sendCustomCommand(AbstractPlayerService.stopServiceCommand, Bundle.EMPTY)
|
if (stopPlayer) playerController?.sendCustomCommand(AbstractPlayerService.stopServiceCommand, Bundle.EMPTY)
|
||||||
playerController?.release()
|
playerController?.release()
|
||||||
playerController = null
|
playerController = null
|
||||||
|
|
||||||
@ -439,6 +444,8 @@ class AudioPlayerFragment : Fragment(R.layout.fragment_audio_player), AudioPlaye
|
|||||||
_binding?.openChapters?.isVisible = !chapters.isNullOrEmpty()
|
_binding?.openChapters?.isVisible = !chapters.isNullOrEmpty()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
playerController?.mediaMetadata?.let { updateStreamInfo(it) }
|
||||||
|
|
||||||
initializeSeekBar()
|
initializeSeekBar()
|
||||||
|
|
||||||
if (isOffline) {
|
if (isOffline) {
|
||||||
|
@ -87,7 +87,7 @@ import com.github.libretube.obj.ShareData
|
|||||||
import com.github.libretube.obj.VideoResolution
|
import com.github.libretube.obj.VideoResolution
|
||||||
import com.github.libretube.parcelable.PlayerData
|
import com.github.libretube.parcelable.PlayerData
|
||||||
import com.github.libretube.services.AbstractPlayerService
|
import com.github.libretube.services.AbstractPlayerService
|
||||||
import com.github.libretube.services.VideoOnlinePlayerService
|
import com.github.libretube.services.OnlinePlayerService
|
||||||
import com.github.libretube.ui.activities.MainActivity
|
import com.github.libretube.ui.activities.MainActivity
|
||||||
import com.github.libretube.ui.adapters.VideosAdapter
|
import com.github.libretube.ui.adapters.VideosAdapter
|
||||||
import com.github.libretube.ui.base.BaseActivity
|
import com.github.libretube.ui.base.BaseActivity
|
||||||
@ -503,9 +503,8 @@ class PlayerFragment : Fragment(R.layout.fragment_player), OnlinePlayerOptions {
|
|||||||
private fun attachToPlayerService(playerData: PlayerData, startNewSession: Boolean) {
|
private fun attachToPlayerService(playerData: PlayerData, startNewSession: Boolean) {
|
||||||
BackgroundHelper.startMediaService(
|
BackgroundHelper.startMediaService(
|
||||||
requireContext(),
|
requireContext(),
|
||||||
VideoOnlinePlayerService::class.java,
|
OnlinePlayerService::class.java,
|
||||||
bundleOf(IntentData.playerData to playerData),
|
if (startNewSession) bundleOf(IntentData.playerData to playerData, IntentData.audioOnly to false) else Bundle.EMPTY,
|
||||||
sendStartCommand = startNewSession
|
|
||||||
) {
|
) {
|
||||||
if (_binding == null) {
|
if (_binding == null) {
|
||||||
playerController.sendCustomCommand(
|
playerController.sendCustomCommand(
|
||||||
@ -698,9 +697,6 @@ class PlayerFragment : Fragment(R.layout.fragment_player), OnlinePlayerOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
binding.relPlayerBackground.setOnClickListener {
|
binding.relPlayerBackground.setOnClickListener {
|
||||||
// pause the current player
|
|
||||||
if (::playerController.isInitialized) playerController.pause()
|
|
||||||
|
|
||||||
// start the background mode
|
// start the background mode
|
||||||
playOnBackground()
|
playOnBackground()
|
||||||
}
|
}
|
||||||
@ -782,19 +778,16 @@ class PlayerFragment : Fragment(R.layout.fragment_player), OnlinePlayerOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun playOnBackground() {
|
private fun playOnBackground() {
|
||||||
val currentPosition =
|
playerController.sendCustomCommand(
|
||||||
if (::playerController.isInitialized) playerController.currentPosition else 0
|
AbstractPlayerService.runPlayerActionCommand,
|
||||||
|
bundleOf(PlayerCommand.TOGGLE_AUDIO_ONLY_MODE.name to true)
|
||||||
BackgroundHelper.playOnBackground(
|
|
||||||
requireContext(),
|
|
||||||
videoId,
|
|
||||||
currentPosition,
|
|
||||||
playlistId,
|
|
||||||
channelId,
|
|
||||||
keepQueue = true,
|
|
||||||
keepVideoPlayerAlive = true
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
binding.player.player = null
|
||||||
|
|
||||||
|
playerController.release()
|
||||||
killPlayerFragment()
|
killPlayerFragment()
|
||||||
|
|
||||||
NavigationHelper.openAudioPlayerFragment(requireContext())
|
NavigationHelper.openAudioPlayerFragment(requireContext())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -942,7 +935,7 @@ class PlayerFragment : Fragment(R.layout.fragment_player), OnlinePlayerOptions {
|
|||||||
|
|
||||||
handler.removeCallbacksAndMessages(null)
|
handler.removeCallbacksAndMessages(null)
|
||||||
|
|
||||||
if (::playerController.isInitialized) {
|
if (::playerController.isInitialized && playerController.isConnected) {
|
||||||
playerController.removeListener(playerListener)
|
playerController.removeListener(playerListener)
|
||||||
playerController.pause()
|
playerController.pause()
|
||||||
|
|
||||||
@ -1303,7 +1296,8 @@ class PlayerFragment : Fragment(R.layout.fragment_player), OnlinePlayerOptions {
|
|||||||
subtitles.map { it.getDisplayName(requireContext()) },
|
subtitles.map { it.getDisplayName(requireContext()) },
|
||||||
preselectedItem = subtitles.firstOrNull {
|
preselectedItem = subtitles.firstOrNull {
|
||||||
val roleFlags = PlayerHelper.getSubtitleRoleFlags(it)
|
val roleFlags = PlayerHelper.getSubtitleRoleFlags(it)
|
||||||
val currentSubtitle = PlayerHelper.getCurrentPlayedCaptionFormat(playerController)
|
val currentSubtitle =
|
||||||
|
PlayerHelper.getCurrentPlayedCaptionFormat(playerController)
|
||||||
it.code == currentSubtitle?.language && currentSubtitle?.roleFlags == roleFlags
|
it.code == currentSubtitle?.language && currentSubtitle?.roleFlags == roleFlags
|
||||||
}
|
}
|
||||||
?.getDisplayName(requireContext()) ?: getString(R.string.none)
|
?.getDisplayName(requireContext()) ?: getString(R.string.none)
|
||||||
|
@ -21,7 +21,6 @@ import com.google.common.collect.ImmutableList
|
|||||||
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
|
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
|
||||||
class NowPlayingNotification(
|
class NowPlayingNotification(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
private val backgroundOnly: Boolean = false,
|
|
||||||
private val offlinePlayer: Boolean = false
|
private val offlinePlayer: Boolean = false
|
||||||
): MediaNotification.Provider {
|
): MediaNotification.Provider {
|
||||||
var intentActivity: Class<*> = MainActivity::class.java
|
var intentActivity: Class<*> = MainActivity::class.java
|
||||||
@ -38,11 +37,9 @@ class NowPlayingNotification(
|
|||||||
// is set to "singleTop" in the AndroidManifest (important!!!)
|
// is set to "singleTop" in the AndroidManifest (important!!!)
|
||||||
// that's the only way to launch back into the previous activity (e.g. the player view)
|
// that's the only way to launch back into the previous activity (e.g. the player view)
|
||||||
val intent = Intent(context, intentActivity).apply {
|
val intent = Intent(context, intentActivity).apply {
|
||||||
if (backgroundOnly) {
|
putExtra(IntentData.maximizePlayer, true)
|
||||||
putExtra(IntentData.openAudioPlayer, true)
|
putExtra(IntentData.offlinePlayer, offlinePlayer)
|
||||||
putExtra(IntentData.offlinePlayer, offlinePlayer)
|
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
||||||
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return PendingIntentCompat
|
return PendingIntentCompat
|
||||||
|
Loading…
x
Reference in New Issue
Block a user