Merge pull request #4916 from Bnyro/master

fix: conflicts between chapters and video highlight
This commit is contained in:
Bnyro 2023-10-06 17:36:51 +02:00 committed by GitHub
commit bc048e015b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 53 additions and 37 deletions

View File

@ -330,7 +330,10 @@ object PlayerHelper {
)
fun shouldPlayNextVideo(isPlaylist: Boolean = false): Boolean {
return autoPlayEnabled || (isPlaylist && PreferenceHelper.getBoolean(PreferenceKeys.AUTOPLAY_PLAYLISTS, false))
return autoPlayEnabled || (isPlaylist && PreferenceHelper.getBoolean(
PreferenceKeys.AUTOPLAY_PLAYLISTS,
false
))
}
private val handleAudioFocus
@ -442,7 +445,11 @@ object PlayerHelper {
* Create a basic player, that is used for all types of playback situations inside the app
*/
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
fun createPlayer(context: Context, trackSelector: DefaultTrackSelector, isBackgroundMode: Boolean): ExoPlayer {
fun createPlayer(
context: Context,
trackSelector: DefaultTrackSelector,
isBackgroundMode: Boolean
): ExoPlayer {
val cronetDataSourceFactory = CronetDataSource.Factory(
CronetHelper.cronetEngine,
Executors.newCachedThreadPool()
@ -579,15 +586,16 @@ object PlayerHelper {
fun getCurrentChapterIndex(currentPositionMs: Long, chapters: List<ChapterSegment>): Int? {
val currentPositionSeconds = currentPositionMs / 1000
return chapters
.filter {
it.highlightDrawable == null ||
// remove the video highlight if it's already longer ago than [ChapterSegment.HIGHLIGHT_LENGTH],
// otherwise the SponsorBlock highlight would be shown from its starting point to the end
(currentPositionSeconds - it.start) < ChapterSegment.HIGHLIGHT_LENGTH
}
.sortedBy { it.start }
.indexOfLast { currentPositionSeconds >= it.start }
.takeIf { it >= 0 }
?.takeIf { index ->
val chapter = chapters[index]
// remove the video highlight if it's already longer ago than [ChapterSegment.HIGHLIGHT_LENGTH],
// otherwise the SponsorBlock highlight would be shown from its starting point to the end
val isWithinMaxHighlightDuration = (currentPositionSeconds - chapter.start) < ChapterSegment.HIGHLIGHT_LENGTH
chapter.highlightDrawable == null || isWithinMaxHighlightDuration
}
}
fun getPosition(videoId: String, duration: Long?): Long? {

View File

@ -13,7 +13,7 @@ import com.github.libretube.helpers.ThemeHelper
import com.github.libretube.ui.viewholders.ChaptersViewHolder
class ChaptersAdapter(
private val chapters: List<ChapterSegment>,
var chapters: List<ChapterSegment>,
private val videoDuration: Long,
private val seekTo: (Long) -> Unit
) : RecyclerView.Adapter<ChaptersViewHolder>() {

View File

@ -191,7 +191,7 @@ class AudioPlayerFragment : Fragment(), AudioPlayerOptions {
binding.chapters.setOnClickListener {
val playerService = playerService ?: return@setOnClickListener
viewModel.chapters = playerService.streams?.chapters.orEmpty().toMutableList()
viewModel.chaptersLiveData.value = playerService.streams?.chapters.orEmpty()
ChaptersBottomSheet()
.show(childFragmentManager)

View File

@ -15,6 +15,7 @@ import android.os.Looper
import android.os.PowerManager
import android.text.format.DateUtils
import android.text.util.Linkify
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@ -44,11 +45,9 @@ import androidx.media3.common.MediaItem.SubtitleConfiguration
import androidx.media3.common.MimeTypes
import androidx.media3.common.PlaybackException
import androidx.media3.common.Player
import androidx.media3.datasource.DefaultDataSource
import androidx.media3.datasource.cronet.CronetDataSource
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.exoplayer.hls.HlsMediaSource
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory
import androidx.media3.exoplayer.trackselection.DefaultTrackSelector
import androidx.recyclerview.widget.LinearLayoutManager
import com.github.libretube.R
@ -90,7 +89,6 @@ import com.github.libretube.helpers.PlayerHelper.SPONSOR_HIGHLIGHT_CATEGORY
import com.github.libretube.helpers.PlayerHelper.checkForSegments
import com.github.libretube.helpers.PlayerHelper.getVideoStats
import com.github.libretube.helpers.PlayerHelper.isInSegment
import com.github.libretube.helpers.PlayerHelper.loadPlaybackParams
import com.github.libretube.helpers.PreferenceHelper
import com.github.libretube.helpers.ProxyHelper
import com.github.libretube.obj.PlayerNotificationData
@ -922,7 +920,7 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
playerBinding.exoTitle.text = streams.title
// init the chapters recyclerview
viewModel.chapters = streams.chapters.toMutableList()
viewModel.chaptersLiveData.value = streams.chapters
// Listener for play and pause icon change
exoPlayer.addListener(object : Player.Listener {
@ -1212,16 +1210,18 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
private suspend fun initializeHighlight(highlight: Segment) {
val frameReceiver = OnlineTimeFrameReceiver(requireContext(), streams.previewFrames)
val highlightStart = highlight.segmentStartAndEnd.first.toLong()
val frame = withContext(Dispatchers.IO) {
frameReceiver.getFrameAtTime(highlight.segmentStartAndEnd.first.toLong() * 1000)
frameReceiver.getFrameAtTime(highlightStart * 1000)
}
val highlightChapter = ChapterSegment(
title = getString(R.string.chapters_videoHighlight),
start = highlight.segmentStartAndEnd.first.toLong(),
start = highlightStart,
highlightDrawable = frame?.toDrawable(requireContext().resources)
)
viewModel.chapters.add(highlightChapter)
viewModel.chapters.sortBy { it.start }
viewModel.chaptersLiveData.postValue(
viewModel.chapters.plus(highlightChapter).sortedBy { it.start }
)
withContext(Dispatchers.Main) {
setCurrentChapterName()

View File

@ -17,5 +17,7 @@ class PlayerViewModel : ViewModel() {
var maxSheetHeightPx = 0
var chapters: MutableList<ChapterSegment> = mutableListOf()
val chaptersLiveData = MutableLiveData<List<ChapterSegment>>()
val chapters get() = chaptersLiveData.value.orEmpty()
}

View File

@ -1,5 +1,6 @@
package com.github.libretube.ui.sheets
import android.annotation.SuppressLint
import android.os.Bundle
import android.os.Handler
import android.os.Looper
@ -10,7 +11,6 @@ import androidx.core.view.isVisible
import androidx.fragment.app.activityViewModels
import androidx.recyclerview.widget.LinearLayoutManager
import com.github.libretube.R
import com.github.libretube.api.obj.ChapterSegment
import com.github.libretube.databinding.BottomSheetBinding
import com.github.libretube.helpers.PlayerHelper
import com.github.libretube.ui.adapters.ChaptersAdapter
@ -19,14 +19,9 @@ import com.github.libretube.ui.models.PlayerViewModel
class ChaptersBottomSheet : UndimmedBottomSheet() {
private var _binding: BottomSheetBinding? = null
private val binding get() = _binding!!
private val handler = Handler(Looper.getMainLooper())
private val playerViewModel: PlayerViewModel by activityViewModels()
private lateinit var chapters: List<ChapterSegment>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
chapters = playerViewModel.chapters
}
override fun onCreateView(
inflater: LayoutInflater,
@ -37,11 +32,28 @@ class ChaptersBottomSheet : UndimmedBottomSheet() {
return binding.root
}
private val updatePosition = object : Runnable {
override fun run() {
val binding = _binding ?: return
handler.postDelayed(this, 200)
val player = playerViewModel.player ?: return
val currentIndex = PlayerHelper.getCurrentChapterIndex(
player.currentPosition,
playerViewModel.chapters
) ?: return
val adapter = binding.optionsRecycler.adapter as ChaptersAdapter
adapter.updateSelectedPosition(currentIndex)
}
}
@SuppressLint("NotifyDataSetChanged")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.optionsRecycler.layoutManager = LinearLayoutManager(context)
val adapter = ChaptersAdapter(chapters, playerViewModel.player?.duration ?: 0) {
val adapter = ChaptersAdapter(playerViewModel.chapters, playerViewModel.player?.duration ?: 0) {
playerViewModel.player?.seekTo(it)
}
binding.optionsRecycler.adapter = adapter
@ -49,17 +61,11 @@ class ChaptersBottomSheet : UndimmedBottomSheet() {
binding.bottomSheetTitle.text = context?.getString(R.string.chapters)
binding.bottomSheetTitleLayout.isVisible = true
val handler = Handler(Looper.getMainLooper())
val updatePosition = object : Runnable {
override fun run() {
if (_binding == null) return
handler.postDelayed(this, 200)
val player = playerViewModel.player ?: return
val currentIndex = PlayerHelper.getCurrentChapterIndex(player.currentPosition, chapters) ?: return
adapter.updateSelectedPosition(currentIndex)
}
playerViewModel.chaptersLiveData.observe(viewLifecycleOwner) {
adapter.chapters = it
adapter.notifyDataSetChanged()
}
updatePosition.run()
}