mirror of
https://github.com/libre-tube/LibreTube.git
synced 2025-04-28 07:50:31 +05:30
commit
0357b736a2
@ -93,6 +93,7 @@ object PreferenceKeys {
|
|||||||
* Background mode
|
* Background mode
|
||||||
*/
|
*/
|
||||||
const val BACKGROUND_PLAYBACK_SPEED = "background_playback_speed"
|
const val BACKGROUND_PLAYBACK_SPEED = "background_playback_speed"
|
||||||
|
const val AUDIO_ONLY_MODE = "audio_only_mode"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifications
|
* Notifications
|
||||||
|
@ -10,6 +10,7 @@ import android.os.Build
|
|||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
|
import android.util.Log
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.core.app.ServiceCompat
|
import androidx.core.app.ServiceCompat
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
@ -24,6 +25,7 @@ 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.extensions.TAG
|
||||||
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
|
||||||
@ -127,7 +129,7 @@ class BackgroundMode : Service() {
|
|||||||
*/
|
*/
|
||||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||||
try {
|
try {
|
||||||
// clear the playing queue
|
// reset the playing queue listeners
|
||||||
PlayingQueue.resetToDefaults()
|
PlayingQueue.resetToDefaults()
|
||||||
|
|
||||||
// get the intent arguments
|
// get the intent arguments
|
||||||
@ -145,6 +147,7 @@ class BackgroundMode : Service() {
|
|||||||
|
|
||||||
if (PlayerHelper.watchPositionsEnabled) updateWatchPosition()
|
if (PlayerHelper.watchPositionsEnabled) updateWatchPosition()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG(), e.toString())
|
||||||
onDestroy()
|
onDestroy()
|
||||||
}
|
}
|
||||||
return super.onStartCommand(intent, flags, startId)
|
return super.onStartCommand(intent, flags, startId)
|
||||||
@ -177,23 +180,23 @@ class BackgroundMode : Service() {
|
|||||||
RetrofitInstance.api.getStreams(videoId)
|
RetrofitInstance.api.getStreams(videoId)
|
||||||
}.getOrNull() ?: return@launch
|
}.getOrNull() ?: return@launch
|
||||||
|
|
||||||
|
// clear the queue if it shouldn't be kept explicitly
|
||||||
|
if (!keepQueue) PlayingQueue.clear()
|
||||||
|
|
||||||
|
if (PlayingQueue.isEmpty()) updateQueue()
|
||||||
|
|
||||||
// save the current stream to the queue
|
// save the current stream to the queue
|
||||||
streams?.toStreamItem(videoId)?.let {
|
streams?.toStreamItem(videoId)?.let {
|
||||||
PlayingQueue.updateCurrent(it)
|
PlayingQueue.updateCurrent(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
// add the playlist video to the queue
|
|
||||||
if (PlayingQueue.isEmpty() && !keepQueue) updateQueue()
|
|
||||||
|
|
||||||
handler.post {
|
handler.post {
|
||||||
playAudio(seekToPosition)
|
playAudio(seekToPosition)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun playAudio(
|
private fun playAudio(seekToPosition: Long) {
|
||||||
seekToPosition: Long
|
|
||||||
) {
|
|
||||||
initializePlayer()
|
initializePlayer()
|
||||||
setMediaItem()
|
setMediaItem()
|
||||||
|
|
||||||
|
@ -41,6 +41,7 @@ import com.github.libretube.ui.models.SearchViewModel
|
|||||||
import com.github.libretube.ui.models.SubscriptionsViewModel
|
import com.github.libretube.ui.models.SubscriptionsViewModel
|
||||||
import com.github.libretube.ui.tools.BreakReminder
|
import com.github.libretube.ui.tools.BreakReminder
|
||||||
import com.github.libretube.util.NavBarHelper
|
import com.github.libretube.util.NavBarHelper
|
||||||
|
import com.github.libretube.util.NavigationHelper
|
||||||
import com.github.libretube.util.NetworkHelper
|
import com.github.libretube.util.NetworkHelper
|
||||||
import com.github.libretube.util.PreferenceHelper
|
import com.github.libretube.util.PreferenceHelper
|
||||||
import com.github.libretube.util.ThemeHelper
|
import com.github.libretube.util.ThemeHelper
|
||||||
@ -58,6 +59,8 @@ class MainActivity : BaseActivity() {
|
|||||||
lateinit var searchView: SearchView
|
lateinit var searchView: SearchView
|
||||||
private lateinit var searchItem: MenuItem
|
private lateinit var searchItem: MenuItem
|
||||||
|
|
||||||
|
private val handler = Handler(Looper.getMainLooper())
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
@ -381,7 +384,7 @@ class MainActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (intent?.getBooleanExtra(IntentData.openAudioPlayer, false) == true) {
|
if (intent?.getBooleanExtra(IntentData.openAudioPlayer, false) == true) {
|
||||||
navController.navigate(R.id.audioPlayerFragment)
|
NavigationHelper.startAudioPlayer(this)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -404,7 +407,11 @@ class MainActivity : BaseActivity() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
intent?.getStringExtra(IntentData.videoId)?.let {
|
intent?.getStringExtra(IntentData.videoId)?.let {
|
||||||
loadVideo(it, intent?.getLongExtra(IntentData.timeStamp, 0L))
|
NavigationHelper.navigateVideo(
|
||||||
|
context = this,
|
||||||
|
videoId = it,
|
||||||
|
timeStamp = intent?.getLongExtra(IntentData.timeStamp, 0L)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
when (intent?.getStringExtra("fragmentToOpen")) {
|
when (intent?.getStringExtra("fragmentToOpen")) {
|
||||||
@ -419,32 +426,6 @@ class MainActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadVideo(videoId: String, timeStamp: Long?) {
|
|
||||||
val bundle = Bundle()
|
|
||||||
|
|
||||||
bundle.putString(IntentData.videoId, videoId)
|
|
||||||
if (timeStamp != null) bundle.putLong(IntentData.timeStamp, timeStamp)
|
|
||||||
|
|
||||||
val frag = PlayerFragment()
|
|
||||||
frag.arguments = bundle
|
|
||||||
|
|
||||||
supportFragmentManager.beginTransaction()
|
|
||||||
.remove(PlayerFragment())
|
|
||||||
.commit()
|
|
||||||
supportFragmentManager.beginTransaction()
|
|
||||||
.replace(R.id.container, frag)
|
|
||||||
.commitNow()
|
|
||||||
Handler(Looper.getMainLooper()).postDelayed({
|
|
||||||
supportFragmentManager.fragments.forEach { fragment ->
|
|
||||||
(fragment as? PlayerFragment)
|
|
||||||
?.binding?.playerMotionLayout?.apply {
|
|
||||||
transitionToEnd()
|
|
||||||
transitionToStart()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, 300)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun minimizePlayer() {
|
private fun minimizePlayer() {
|
||||||
binding.mainMotionLayout.transitionToEnd()
|
binding.mainMotionLayout.transitionToEnd()
|
||||||
supportFragmentManager.fragments.forEach { fragment ->
|
supportFragmentManager.fragments.forEach { fragment ->
|
||||||
|
@ -86,6 +86,7 @@ import com.github.libretube.util.BackgroundHelper
|
|||||||
import com.github.libretube.util.DashHelper
|
import com.github.libretube.util.DashHelper
|
||||||
import com.github.libretube.util.DataSaverMode
|
import com.github.libretube.util.DataSaverMode
|
||||||
import com.github.libretube.util.ImageHelper
|
import com.github.libretube.util.ImageHelper
|
||||||
|
import com.github.libretube.util.NavigationHelper
|
||||||
import com.github.libretube.util.NowPlayingNotification
|
import com.github.libretube.util.NowPlayingNotification
|
||||||
import com.github.libretube.util.PlayerHelper
|
import com.github.libretube.util.PlayerHelper
|
||||||
import com.github.libretube.util.PlayingQueue
|
import com.github.libretube.util.PlayingQueue
|
||||||
@ -349,7 +350,7 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
|
|||||||
BackgroundHelper.stopBackgroundPlay(requireContext())
|
BackgroundHelper.stopBackgroundPlay(requireContext())
|
||||||
}
|
}
|
||||||
playerBinding.closeImageButton.setOnClickListener {
|
playerBinding.closeImageButton.setOnClickListener {
|
||||||
killFragment()
|
killPlayerFragment()
|
||||||
}
|
}
|
||||||
playerBinding.autoPlay.visibility = View.VISIBLE
|
playerBinding.autoPlay.visibility = View.VISIBLE
|
||||||
|
|
||||||
@ -476,8 +477,8 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
|
|||||||
true
|
true
|
||||||
)
|
)
|
||||||
handler.postDelayed({
|
handler.postDelayed({
|
||||||
(activity as MainActivity).navController.navigate(R.id.audioPlayerFragment)
|
NavigationHelper.startAudioPlayer(requireContext())
|
||||||
killFragment()
|
killPlayerFragment()
|
||||||
}, 500)
|
}, 500)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1530,7 +1531,7 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
|
|||||||
return exoPlayer.isPlaying && !backgroundModeRunning
|
return exoPlayer.isPlaying && !backgroundModeRunning
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun killFragment() {
|
private fun killPlayerFragment() {
|
||||||
viewModel.isFullscreen.value = false
|
viewModel.isFullscreen.value = false
|
||||||
binding.playerMotionLayout.transitionToEnd()
|
binding.playerMotionLayout.transitionToEnd()
|
||||||
val mainActivity = activity as MainActivity
|
val mainActivity = activity as MainActivity
|
||||||
|
@ -6,10 +6,13 @@ import android.content.ContextWrapper
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
import com.github.libretube.R
|
import com.github.libretube.R
|
||||||
import com.github.libretube.constants.IntentData
|
import com.github.libretube.constants.IntentData
|
||||||
|
import com.github.libretube.constants.PreferenceKeys
|
||||||
import com.github.libretube.enums.PlaylistType
|
import com.github.libretube.enums.PlaylistType
|
||||||
import com.github.libretube.extensions.toID
|
import com.github.libretube.extensions.toID
|
||||||
import com.github.libretube.ui.activities.MainActivity
|
import com.github.libretube.ui.activities.MainActivity
|
||||||
@ -17,6 +20,8 @@ import com.github.libretube.ui.fragments.PlayerFragment
|
|||||||
import com.github.libretube.ui.views.SingleViewTouchableMotionLayout
|
import com.github.libretube.ui.views.SingleViewTouchableMotionLayout
|
||||||
|
|
||||||
object NavigationHelper {
|
object NavigationHelper {
|
||||||
|
private val handler = Handler(Looper.getMainLooper())
|
||||||
|
|
||||||
fun navigateChannel(
|
fun navigateChannel(
|
||||||
context: Context,
|
context: Context,
|
||||||
channelId: String?
|
channelId: String?
|
||||||
@ -45,20 +50,35 @@ object NavigationHelper {
|
|||||||
return correctContext as MainActivity
|
return correctContext as MainActivity
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Navigate to the given video using the other provided parameters as well
|
||||||
|
* If the audio only mode is enabled, play it in the background, else as a normal video
|
||||||
|
*/
|
||||||
fun navigateVideo(
|
fun navigateVideo(
|
||||||
context: Context,
|
context: Context,
|
||||||
videoId: String?,
|
videoId: String?,
|
||||||
playlistId: String? = null,
|
playlistId: String? = null,
|
||||||
channelId: String? = null,
|
channelId: String? = null,
|
||||||
keepQueue: Boolean = false
|
keepQueue: Boolean = false,
|
||||||
|
timeStamp: Long? = null
|
||||||
) {
|
) {
|
||||||
if (videoId == null) return
|
if (videoId == null) return
|
||||||
|
|
||||||
|
if (PreferenceHelper.getBoolean(PreferenceKeys.AUDIO_ONLY_MODE, false)) {
|
||||||
|
BackgroundHelper.stopBackgroundPlay(context)
|
||||||
|
BackgroundHelper.playOnBackground(context, videoId.toID(), timeStamp, playlistId, channelId, keepQueue)
|
||||||
|
handler.postDelayed({
|
||||||
|
startAudioPlayer(context)
|
||||||
|
}, 500)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
val bundle = Bundle().apply {
|
val bundle = Bundle().apply {
|
||||||
putString(IntentData.videoId, videoId.toID())
|
putString(IntentData.videoId, videoId.toID())
|
||||||
putString(IntentData.playlistId, playlistId)
|
putString(IntentData.playlistId, playlistId)
|
||||||
putString(IntentData.channelId, channelId)
|
putString(IntentData.channelId, channelId)
|
||||||
putBoolean(IntentData.keepQueue, keepQueue)
|
putBoolean(IntentData.keepQueue, keepQueue)
|
||||||
|
timeStamp?.let { putLong(IntentData.timeStamp, it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
val activity = context as AppCompatActivity
|
val activity = context as AppCompatActivity
|
||||||
@ -89,6 +109,14 @@ object NavigationHelper {
|
|||||||
activity.navController.navigate(R.id.playlistFragment, bundle)
|
activity.navController.navigate(R.id.playlistFragment, bundle)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start the audio player fragment
|
||||||
|
*/
|
||||||
|
fun startAudioPlayer(context: Context) {
|
||||||
|
val activity = unwrap(context)
|
||||||
|
activity.navController.navigate(R.id.audioPlayerFragment)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Needed due to different MainActivity Aliases because of the app icons
|
* Needed due to different MainActivity Aliases because of the app icons
|
||||||
*/
|
*/
|
||||||
|
@ -25,6 +25,8 @@ object PlayingQueue {
|
|||||||
private val onTrackChangedListeners: MutableList<(StreamItem) -> Unit> = mutableListOf()
|
private val onTrackChangedListeners: MutableList<(StreamItem) -> Unit> = mutableListOf()
|
||||||
var repeatQueue: Boolean = false
|
var repeatQueue: Boolean = false
|
||||||
|
|
||||||
|
fun clear() = queue.clear()
|
||||||
|
|
||||||
fun add(vararg streamItem: StreamItem) {
|
fun add(vararg streamItem: StreamItem) {
|
||||||
streamItem.forEach {
|
streamItem.forEach {
|
||||||
if (currentStream != it) {
|
if (currentStream != it) {
|
||||||
@ -72,7 +74,7 @@ object PlayingQueue {
|
|||||||
it.invoke(streamItem)
|
it.invoke(streamItem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!contains(streamItem)) queue.add(streamItem)
|
if (!contains(streamItem)) queue.add(0, streamItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isNotEmpty() = queue.isNotEmpty()
|
fun isNotEmpty() = queue.isNotEmpty()
|
||||||
@ -190,6 +192,5 @@ object PlayingQueue {
|
|||||||
repeatQueue = false
|
repeatQueue = false
|
||||||
onQueueTapListener = {}
|
onQueueTapListener = {}
|
||||||
onTrackChangedListeners.clear()
|
onTrackChangedListeners.clear()
|
||||||
queue.clear()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -431,6 +431,8 @@
|
|||||||
<string name="alternative_pip_controls">Alternative PiP controls</string>
|
<string name="alternative_pip_controls">Alternative PiP controls</string>
|
||||||
<string name="alternative_pip_controls_summary">Show audio only and skip controls in PiP instead of forward and rewind</string>
|
<string name="alternative_pip_controls_summary">Show audio only and skip controls in PiP instead of forward and rewind</string>
|
||||||
<string name="audio_player">Audio player</string>
|
<string name="audio_player">Audio player</string>
|
||||||
|
<string name="audio_only_mode">Audio only mode</string>
|
||||||
|
<string name="audio_only_mode_summary">Turn LibreTube into a music player.</string>
|
||||||
|
|
||||||
<!-- Notification channel strings -->
|
<!-- Notification channel strings -->
|
||||||
<string name="download_channel_name">Download Service</string>
|
<string name="download_channel_name">Download Service</string>
|
||||||
|
@ -23,6 +23,13 @@
|
|||||||
|
|
||||||
<PreferenceCategory app:title="@string/customization">
|
<PreferenceCategory app:title="@string/customization">
|
||||||
|
|
||||||
|
<SwitchPreferenceCompat
|
||||||
|
android:defaultValue="false"
|
||||||
|
android:icon="@drawable/ic_headphones"
|
||||||
|
android:summary="@string/audio_only_mode_summary"
|
||||||
|
android:title="@string/audio_only_mode"
|
||||||
|
app:key="audio_only_mode" />
|
||||||
|
|
||||||
<SwitchPreferenceCompat
|
<SwitchPreferenceCompat
|
||||||
android:defaultValue="false"
|
android:defaultValue="false"
|
||||||
android:icon="@drawable/ic_screen_rotation"
|
android:icon="@drawable/ic_screen_rotation"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user