mirror of
https://github.com/libre-tube/LibreTube.git
synced 2025-04-29 16:30:31 +05:30
fix: autoplay countdown continues although other video selected
This commit is contained in:
parent
9458b5597b
commit
40c885316d
@ -7,8 +7,10 @@ import android.os.Looper
|
|||||||
import android.view.KeyEvent
|
import android.view.KeyEvent
|
||||||
import androidx.annotation.OptIn
|
import androidx.annotation.OptIn
|
||||||
import androidx.core.app.ServiceCompat
|
import androidx.core.app.ServiceCompat
|
||||||
|
import androidx.core.os.bundleOf
|
||||||
import androidx.core.os.postDelayed
|
import androidx.core.os.postDelayed
|
||||||
import androidx.media3.common.C
|
import androidx.media3.common.C
|
||||||
|
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.UnstableApi
|
import androidx.media3.common.util.UnstableApi
|
||||||
@ -22,6 +24,7 @@ import androidx.media3.session.SessionCommand
|
|||||||
import androidx.media3.session.SessionResult
|
import androidx.media3.session.SessionResult
|
||||||
import com.github.libretube.R
|
import com.github.libretube.R
|
||||||
import com.github.libretube.api.obj.Subtitle
|
import com.github.libretube.api.obj.Subtitle
|
||||||
|
import com.github.libretube.constants.IntentData
|
||||||
import com.github.libretube.enums.PlayerCommand
|
import com.github.libretube.enums.PlayerCommand
|
||||||
import com.github.libretube.enums.PlayerEvent
|
import com.github.libretube.enums.PlayerEvent
|
||||||
import com.github.libretube.extensions.parcelable
|
import com.github.libretube.extensions.parcelable
|
||||||
@ -47,6 +50,8 @@ abstract class AbstractPlayerService : MediaLibraryService(), MediaLibrarySessio
|
|||||||
var trackSelector: DefaultTrackSelector? = null
|
var trackSelector: DefaultTrackSelector? = null
|
||||||
|
|
||||||
lateinit var videoId: String
|
lateinit var videoId: String
|
||||||
|
private set
|
||||||
|
|
||||||
var isTransitioning = true
|
var isTransitioning = true
|
||||||
|
|
||||||
val handler = Handler(Looper.getMainLooper())
|
val handler = Handler(Looper.getMainLooper())
|
||||||
@ -170,7 +175,7 @@ abstract class AbstractPlayerService : MediaLibraryService(), MediaLibrarySessio
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun navigateVideo(videoId: String) {
|
private fun navigateVideo(videoId: String) {
|
||||||
this.videoId = videoId
|
setVideoId(videoId)
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
startPlayback()
|
startPlayback()
|
||||||
@ -185,6 +190,28 @@ abstract class AbstractPlayerService : MediaLibraryService(), MediaLibrarySessio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the [videoId] to the new videoId and change the playlist metadata
|
||||||
|
* to reflect that videoId change
|
||||||
|
*/
|
||||||
|
protected fun setVideoId(videoId: String) {
|
||||||
|
this.videoId = videoId
|
||||||
|
|
||||||
|
updatePlaylistMetadata {
|
||||||
|
setExtras(bundleOf(IntentData.videoId to videoId))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun updatePlaylistMetadata(updateAction: MediaMetadata.Builder.() -> Unit) {
|
||||||
|
handler.post {
|
||||||
|
exoPlayer?.playlistMetadata = MediaMetadata.Builder()
|
||||||
|
.apply(updateAction)
|
||||||
|
// send a unique timestamp to notify that the metadata changed, even if playing the same video twice
|
||||||
|
.setTrackNumber(System.currentTimeMillis().mod(Int.MAX_VALUE))
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun handlePlayerAction(event: PlayerEvent) {
|
private fun handlePlayerAction(event: PlayerEvent) {
|
||||||
if (PlayerHelper.handlePlayerAction(exoPlayer ?: return, event)) return
|
if (PlayerHelper.handlePlayerAction(exoPlayer ?: return, event)) return
|
||||||
|
|
||||||
@ -303,7 +330,7 @@ abstract class AbstractPlayerService : MediaLibraryService(), MediaLibrarySessio
|
|||||||
*/
|
*/
|
||||||
abstract suspend fun startPlayback()
|
abstract suspend fun startPlayback()
|
||||||
|
|
||||||
fun saveWatchPosition() {
|
private fun saveWatchPosition() {
|
||||||
if (isTransitioning || !PlayerHelper.watchPositionsVideo) return
|
if (isTransitioning || !PlayerHelper.watchPositionsVideo) return
|
||||||
|
|
||||||
exoPlayer?.let { PlayerHelper.saveWatchPosition(it, videoId) }
|
exoPlayer?.let { PlayerHelper.saveWatchPosition(it, videoId) }
|
||||||
|
@ -56,13 +56,14 @@ open class OfflinePlayerService : AbstractPlayerService() {
|
|||||||
shuffle = args.getBoolean(IntentData.shuffle, false)
|
shuffle = args.getBoolean(IntentData.shuffle, false)
|
||||||
noInternetService = args.getBoolean(IntentData.noInternet, false)
|
noInternetService = args.getBoolean(IntentData.noInternet, false)
|
||||||
|
|
||||||
videoId = if (shuffle) {
|
val videoId = if (shuffle) {
|
||||||
runBlocking(Dispatchers.IO) {
|
runBlocking(Dispatchers.IO) {
|
||||||
Database.downloadDao().getRandomVideoIdByFileType(FileType.AUDIO)
|
Database.downloadDao().getRandomVideoIdByFileType(FileType.AUDIO)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
args.getString(IntentData.videoId)
|
args.getString(IntentData.videoId)
|
||||||
} ?: return
|
} ?: return
|
||||||
|
setVideoId(videoId)
|
||||||
|
|
||||||
PlayingQueue.clear()
|
PlayingQueue.clear()
|
||||||
|
|
||||||
@ -131,9 +132,7 @@ open class OfflinePlayerService : AbstractPlayerService() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun playNextVideo(videoId: String) {
|
private fun playNextVideo(videoId: String) {
|
||||||
saveWatchPosition()
|
setVideoId(videoId)
|
||||||
|
|
||||||
this.videoId = videoId
|
|
||||||
|
|
||||||
scope.launch {
|
scope.launch {
|
||||||
startPlayback()
|
startPlayback()
|
||||||
|
@ -6,7 +6,6 @@ import androidx.core.net.toUri
|
|||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
import androidx.media3.common.MediaItem
|
import androidx.media3.common.MediaItem
|
||||||
import androidx.media3.common.MediaItem.SubtitleConfiguration
|
import androidx.media3.common.MediaItem.SubtitleConfiguration
|
||||||
import androidx.media3.common.MediaMetadata
|
|
||||||
import androidx.media3.common.MimeTypes
|
import androidx.media3.common.MimeTypes
|
||||||
import androidx.media3.common.Player
|
import androidx.media3.common.Player
|
||||||
import androidx.media3.datasource.cronet.CronetDataSource
|
import androidx.media3.datasource.cronet.CronetDataSource
|
||||||
@ -106,7 +105,7 @@ open class OnlinePlayerService : AbstractPlayerService() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get the intent arguments
|
// get the intent arguments
|
||||||
videoId = playerData.videoId
|
setVideoId(playerData.videoId)
|
||||||
playlistId = playerData.playlistId
|
playlistId = playerData.playlistId
|
||||||
channelId = playerData.channelId
|
channelId = playerData.channelId
|
||||||
startTimestamp = playerData.timestamp
|
startTimestamp = playerData.timestamp
|
||||||
@ -178,8 +177,6 @@ open class OnlinePlayerService : AbstractPlayerService() {
|
|||||||
* Plays the next video from the queue
|
* Plays the next video from the queue
|
||||||
*/
|
*/
|
||||||
private fun playNextVideo(nextId: String? = null) {
|
private fun playNextVideo(nextId: String? = null) {
|
||||||
saveWatchPosition()
|
|
||||||
|
|
||||||
if (nextId == null) {
|
if (nextId == null) {
|
||||||
if (PlayingQueue.repeatMode == Player.REPEAT_MODE_ONE) {
|
if (PlayingQueue.repeatMode == Player.REPEAT_MODE_ONE) {
|
||||||
exoPlayer?.seekTo(0)
|
exoPlayer?.seekTo(0)
|
||||||
@ -192,7 +189,7 @@ open class OnlinePlayerService : AbstractPlayerService() {
|
|||||||
val nextVideo = nextId ?: PlayingQueue.getNext() ?: return
|
val nextVideo = nextId ?: PlayingQueue.getNext() ?: return
|
||||||
|
|
||||||
// play new video on background
|
// play new video on background
|
||||||
this.videoId = nextVideo
|
setVideoId(nextVideo)
|
||||||
this.streams = null
|
this.streams = null
|
||||||
this.sponsorBlockSegments = emptyList()
|
this.sponsorBlockSegments = emptyList()
|
||||||
|
|
||||||
@ -214,9 +211,9 @@ open class OnlinePlayerService : AbstractPlayerService() {
|
|||||||
).segments
|
).segments
|
||||||
|
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
exoPlayer?.playlistMetadata = MediaMetadata.Builder()
|
updatePlaylistMetadata {
|
||||||
.setExtras(bundleOf(IntentData.segments to ArrayList(sponsorBlockSegments)))
|
setExtras(bundleOf(IntentData.segments to ArrayList(sponsorBlockSegments)))
|
||||||
.build()
|
}
|
||||||
|
|
||||||
checkForSegments()
|
checkForSegments()
|
||||||
}
|
}
|
||||||
|
@ -305,16 +305,6 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
|||||||
override fun onMediaMetadataChanged(mediaMetadata: MediaMetadata) {
|
override fun onMediaMetadataChanged(mediaMetadata: MediaMetadata) {
|
||||||
super.onMediaMetadataChanged(mediaMetadata)
|
super.onMediaMetadataChanged(mediaMetadata)
|
||||||
|
|
||||||
mediaMetadata.extras?.getString(IntentData.videoId)?.let {
|
|
||||||
videoId = it
|
|
||||||
// fix: if the fragment is recreated, play the current video, and not the initial one
|
|
||||||
arguments?.run {
|
|
||||||
val playerData =
|
|
||||||
parcelable<PlayerData>(IntentData.playerData)!!.copy(videoId = videoId)
|
|
||||||
putParcelable(IntentData.playerData, playerData)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val maybeStreams: Streams? = mediaMetadata.extras?.parcelable(IntentData.streams)
|
val maybeStreams: Streams? = mediaMetadata.extras?.parcelable(IntentData.streams)
|
||||||
maybeStreams?.let { streams ->
|
maybeStreams?.let { streams ->
|
||||||
this@PlayerFragment.streams = streams
|
this@PlayerFragment.streams = streams
|
||||||
@ -327,6 +317,18 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
|||||||
override fun onPlaylistMetadataChanged(mediaMetadata: MediaMetadata) {
|
override fun onPlaylistMetadataChanged(mediaMetadata: MediaMetadata) {
|
||||||
super.onPlaylistMetadataChanged(mediaMetadata)
|
super.onPlaylistMetadataChanged(mediaMetadata)
|
||||||
|
|
||||||
|
mediaMetadata.extras?.getString(IntentData.videoId)?.let {
|
||||||
|
videoId = it
|
||||||
|
_binding?.autoplayCountdown?.cancelAndHideCountdown()
|
||||||
|
|
||||||
|
// fix: if the fragment is recreated, play the current video, and not the initial one
|
||||||
|
arguments?.run {
|
||||||
|
val playerData =
|
||||||
|
parcelable<PlayerData>(IntentData.playerData)!!.copy(videoId = videoId)
|
||||||
|
putParcelable(IntentData.playerData, playerData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val segments: List<Segment>? = mediaMetadata.extras?.parcelableList(IntentData.segments)
|
val segments: List<Segment>? = mediaMetadata.extras?.parcelableList(IntentData.segments)
|
||||||
viewModel.segments.postValue(segments.orEmpty())
|
viewModel.segments.postValue(segments.orEmpty())
|
||||||
}
|
}
|
||||||
|
@ -34,8 +34,7 @@ class AutoplayCountdownView(
|
|||||||
|
|
||||||
init {
|
init {
|
||||||
binding.cancel.setOnClickListener {
|
binding.cancel.setOnClickListener {
|
||||||
handler.removeCallbacksAndMessages(TIMER_RUNNABLE_TOKEN)
|
cancelAndHideCountdown()
|
||||||
hideSelf.invoke()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,6 +77,11 @@ class AutoplayCountdownView(
|
|||||||
handler.postDelayed(1000, TIMER_RUNNABLE_TOKEN, this::updateCountdown)
|
handler.postDelayed(1000, TIMER_RUNNABLE_TOKEN, this::updateCountdown)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun cancelAndHideCountdown() {
|
||||||
|
handler.removeCallbacksAndMessages(TIMER_RUNNABLE_TOKEN)
|
||||||
|
hideSelf.invoke()
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val COUNTDOWN_SECONDS = 5
|
private const val COUNTDOWN_SECONDS = 5
|
||||||
private const val TIMER_RUNNABLE_TOKEN = "timer_runnable"
|
private const val TIMER_RUNNABLE_TOKEN = "timer_runnable"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user