mirror of
https://github.com/videolan/vlc-android
synced 2024-11-23 09:56:36 +08:00
Add support for jumping to chapters and bookmarks in podcast mode
This commit is contained in:
parent
31077e2b89
commit
ef65d49c7e
@ -50,10 +50,13 @@ import org.videolan.tools.retrieveParent
|
||||
import org.videolan.vlc.gui.helpers.MediaComparators
|
||||
import org.videolan.vlc.media.MediaSessionBrowser
|
||||
import org.videolan.vlc.util.PlaybackAction
|
||||
import org.videolan.vlc.util.TextUtils
|
||||
import org.videolan.vlc.util.VoiceSearchParams
|
||||
import org.videolan.vlc.util.awaitMedialibraryStarted
|
||||
import org.videolan.vlc.util.mergeSorted
|
||||
import java.security.SecureRandom
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.absoluteValue
|
||||
import kotlin.math.min
|
||||
|
||||
private const val TAG = "VLC/MediaSessionCallback"
|
||||
@ -116,8 +119,8 @@ internal class MediaSessionCallback(private val playbackService: PlaybackService
|
||||
if (!prevActionSeek) {
|
||||
val enabledActions = playbackService.enabledActions
|
||||
when (keyEvent.keyCode) {
|
||||
KeyEvent.KEYCODE_MEDIA_NEXT -> if (enabledActions.contains(PlaybackAction.ACTION_SKIP_TO_NEXT)) onSkipToNext()
|
||||
KeyEvent.KEYCODE_MEDIA_PREVIOUS -> if (enabledActions.contains(PlaybackAction.ACTION_SKIP_TO_PREVIOUS)) onSkipToPrevious()
|
||||
KeyEvent.KEYCODE_MEDIA_NEXT -> onSkipToNext()
|
||||
KeyEvent.KEYCODE_MEDIA_PREVIOUS -> onSkipToPrevious()
|
||||
}
|
||||
}
|
||||
prevActionSeek = false
|
||||
@ -128,6 +131,52 @@ internal class MediaSessionCallback(private val playbackService: PlaybackService
|
||||
return super.onMediaButtonEvent(mediaButtonEvent)
|
||||
}
|
||||
|
||||
private fun jumpToTimelineEntry(previous: Boolean) {
|
||||
val ctx = playbackService.applicationContext
|
||||
playbackService.lifecycleScope.launch {
|
||||
val currentTime = playbackService.getTime()
|
||||
val entryList = getChapterList().toMutableList().apply {
|
||||
mergeSorted(getBookmarkList()) { it.time }
|
||||
}
|
||||
if (entryList.isEmpty()) {
|
||||
playbackService.displaySubtitleMessage(ctx.getString(R.string.no_bookmark))
|
||||
return@launch
|
||||
}
|
||||
val index = entryList.binarySearchBy(currentTime) { it.time }
|
||||
var eIndex = when {
|
||||
index >= 0 -> index + if (previous) -1 else 1
|
||||
else -> -index - if (previous) 2 else 1
|
||||
}.coerceIn(entryList.indices)
|
||||
// Point to the previous element if the time difference is less than 5 seconds
|
||||
if (previous && (currentTime - entryList[eIndex].time) < 5_000L) {
|
||||
eIndex = (eIndex - 1).coerceIn(entryList.indices)
|
||||
}
|
||||
// Ignore button press if within 2 seconds of the first or last entry
|
||||
if ((eIndex == 0 || eIndex == entryList.size - 1) && (currentTime - entryList[eIndex].time).absoluteValue <= 2_000L)
|
||||
return@launch
|
||||
// Seek to the correct time
|
||||
if ((!previous && entryList[eIndex].time >= currentTime) || (previous && entryList[eIndex].time <= currentTime)) {
|
||||
seek(entryList[eIndex].time)
|
||||
playbackService.displaySubtitleMessage("${ctx.getString(R.string.jump_to)} ${entryList[eIndex].name}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getChapterList(): List<TimelineEntry> {
|
||||
val ctx = playbackService.applicationContext
|
||||
return playbackService.getChapters(-1)?.mapIndexed { index, item ->
|
||||
TimelineEntry(0, item.timeOffset, TextUtils.formatChapterTitle(ctx, index + 1, item.name))
|
||||
} ?: emptyList()
|
||||
}
|
||||
|
||||
private fun getBookmarkList(): List<TimelineEntry> {
|
||||
return playbackService.currentMediaWrapper?.bookmarks?.map { bookmark ->
|
||||
TimelineEntry(1, bookmark.time, bookmark.title)
|
||||
} ?: emptyList()
|
||||
}
|
||||
|
||||
data class TimelineEntry(val type: Int, val time: Long, val name: String)
|
||||
|
||||
/**
|
||||
* The following two functions are based on the following KeyEvent captures. They may need to be updated if the behavior changes in the future.
|
||||
*
|
||||
@ -378,9 +427,17 @@ internal class MediaSessionCallback(private val playbackService: PlaybackService
|
||||
|
||||
override fun onStop() = playbackService.stop()
|
||||
|
||||
override fun onSkipToNext() = playbackService.next()
|
||||
override fun onSkipToNext() = when {
|
||||
playbackService.isPodcastMode -> jumpToTimelineEntry(false)
|
||||
playbackService.hasNext() -> playbackService.next()
|
||||
else -> {}
|
||||
}
|
||||
|
||||
override fun onSkipToPrevious() = playbackService.previous(false)
|
||||
override fun onSkipToPrevious() = when {
|
||||
playbackService.isPodcastMode -> jumpToTimelineEntry(true)
|
||||
playbackService.hasPrevious() -> playbackService.previous(false)
|
||||
else -> {}
|
||||
}
|
||||
|
||||
override fun onSeekTo(pos: Long) = seek(if (pos < 0) playbackService.getTime() + pos else pos)
|
||||
|
||||
@ -398,4 +455,4 @@ internal class MediaSessionCallback(private val playbackService: PlaybackService
|
||||
|
||||
override fun onSetPlaybackSpeed(speed: Float) = playbackService.setRate(speed.coerceIn(0.5f, 2.0f), false)
|
||||
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user