diff --git a/app/src/main/java/com/github/libretube/constants/PreferenceKeys.kt b/app/src/main/java/com/github/libretube/constants/PreferenceKeys.kt index f97ceb533..bcf4ed66a 100644 --- a/app/src/main/java/com/github/libretube/constants/PreferenceKeys.kt +++ b/app/src/main/java/com/github/libretube/constants/PreferenceKeys.kt @@ -65,7 +65,6 @@ object PreferenceKeys { const val SYSTEM_CAPTION_STYLE = "system_caption_style" const val CAPTION_SETTINGS = "caption_settings" const val SEEK_INCREMENT = "seek_increment" - const val PLAYER_VIDEO_FORMAT = "player_video_format" const val DEFAULT_RESOLUTION = "default_res" const val DEFAULT_RESOLUTION_MOBILE = "default_res_mobile" const val BUFFERING_GOAL = "buffering_goal" diff --git a/app/src/main/java/com/github/libretube/helpers/PlayerHelper.kt b/app/src/main/java/com/github/libretube/helpers/PlayerHelper.kt index ad7d6d747..0022cca5f 100644 --- a/app/src/main/java/com/github/libretube/helpers/PlayerHelper.kt +++ b/app/src/main/java/com/github/libretube/helpers/PlayerHelper.kt @@ -9,10 +9,12 @@ import android.content.pm.ActivityInfo import android.graphics.drawable.Icon import android.os.Build import android.view.accessibility.CaptioningManager +import android.widget.Toast import androidx.annotation.RequiresApi import androidx.annotation.StringRes import com.github.libretube.R import com.github.libretube.api.obj.PipedStream +import com.github.libretube.api.obj.Segment import com.github.libretube.constants.PreferenceKeys import com.github.libretube.enums.AudioQuality import com.github.libretube.enums.PlayerEvent @@ -214,12 +216,6 @@ object PlayerHelper { true ) - val videoFormatPreference: String - get() = PreferenceHelper.getString( - PreferenceKeys.PLAYER_VIDEO_FORMAT, - "webm" - ) - private val bufferingGoal: Int get() = PreferenceHelper.getString( PreferenceKeys.BUFFERING_GOAL, @@ -232,7 +228,7 @@ object PlayerHelper { true ) - val sponsorBlockNotifications: Boolean + private val sponsorBlockNotifications: Boolean get() = PreferenceHelper.getBoolean( "sb_notifications_key", true @@ -481,4 +477,32 @@ object PlayerHelper { ) return this } + + /** + * Check for SponsorBlock segments matching the current player position + * @param context A main dispatcher context + * @param segments List of the SponsorBlock segments + * @param skipManually Whether the event gets handled by the function caller + * @return If segment found and [skipManually] is true, the end position of the segment in ms, otherwise null + */ + fun ExoPlayer.checkForSegments(context: Context, segments: List, skipManually: Boolean = false): Long? { + segments.forEach { segment -> + val segmentStart = (segment.segment[0] * 1000f).toLong() + val segmentEnd = (segment.segment[1] * 1000f).toLong() + if (currentPosition in segmentStart until segmentEnd) { + if (!skipManually) { + if (sponsorBlockNotifications) { + runCatching { + Toast.makeText(context, R.string.segment_skipped, Toast.LENGTH_SHORT) + .show() + } + } + seekTo(segmentEnd) + } else { + return segmentEnd + } + } + } + return null + } } diff --git a/app/src/main/java/com/github/libretube/services/BackgroundMode.kt b/app/src/main/java/com/github/libretube/services/BackgroundMode.kt index 8b0557eb1..690a74ba0 100644 --- a/app/src/main/java/com/github/libretube/services/BackgroundMode.kt +++ b/app/src/main/java/com/github/libretube/services/BackgroundMode.kt @@ -17,7 +17,7 @@ import androidx.lifecycle.lifecycleScope import com.github.libretube.R import com.github.libretube.api.JsonHelper import com.github.libretube.api.RetrofitInstance -import com.github.libretube.api.obj.SegmentData +import com.github.libretube.api.obj.Segment import com.github.libretube.api.obj.Streams import com.github.libretube.constants.BACKGROUND_CHANNEL_ID import com.github.libretube.constants.IntentData @@ -30,6 +30,7 @@ import com.github.libretube.extensions.query import com.github.libretube.extensions.toID import com.github.libretube.extensions.toStreamItem import com.github.libretube.helpers.PlayerHelper +import com.github.libretube.helpers.PlayerHelper.checkForSegments import com.github.libretube.helpers.PlayerHelper.loadPlaybackParams import com.github.libretube.util.NowPlayingNotification import com.github.libretube.util.PlayingQueue @@ -71,7 +72,7 @@ class BackgroundMode : LifecycleService() { /** * SponsorBlock Segment data */ - private var segmentData: SegmentData? = null + private var segments: List = listOf() /** * [Notification] for the player @@ -223,7 +224,7 @@ class BackgroundMode : LifecycleService() { } } - fetchSponsorBlockSegments() + if (PlayerHelper.sponsorBlockEnabled) fetchSponsorBlockSegments() } /** @@ -284,7 +285,7 @@ class BackgroundMode : LifecycleService() { // play new video on background this.videoId = nextVideo this.streams = null - this.segmentData = null + this.segments = emptyList() loadAudio(videoId, keepQueue = true) } @@ -315,10 +316,10 @@ class BackgroundMode : LifecycleService() { runCatching { val categories = PlayerHelper.getSponsorBlockCategories() if (categories.isEmpty()) return@runCatching - segmentData = RetrofitInstance.api.getSegments( + segments = RetrofitInstance.api.getSegments( videoId, JsonHelper.json.encodeToString(categories) - ) + ).segments checkForSegments() } } @@ -328,24 +329,9 @@ class BackgroundMode : LifecycleService() { * check for SponsorBlock segments */ private fun checkForSegments() { - Handler(Looper.getMainLooper()).postDelayed(this::checkForSegments, 100) + handler.postDelayed(this::checkForSegments, 100) - if (segmentData == null || segmentData!!.segments.isEmpty()) return - - segmentData!!.segments.forEach { segment -> - val segmentStart = (segment.segment[0] * 1000f).toLong() - val segmentEnd = (segment.segment[1] * 1000f).toLong() - val currentPosition = player?.currentPosition - if (currentPosition in segmentStart until segmentEnd) { - if (PlayerHelper.sponsorBlockNotifications) { - runCatching { - Toast.makeText(this, R.string.segment_skipped, Toast.LENGTH_SHORT) - .show() - } - } - player?.seekTo(segmentEnd) - } - } + player?.checkForSegments(this, segments) } private fun updateQueue() { diff --git a/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt b/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt index 0af7ca433..73e8398b8 100644 --- a/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt +++ b/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt @@ -46,7 +46,6 @@ import com.github.libretube.api.RetrofitInstance import com.github.libretube.api.obj.ChapterSegment import com.github.libretube.api.obj.PipedStream import com.github.libretube.api.obj.Segment -import com.github.libretube.api.obj.SegmentData import com.github.libretube.api.obj.StreamItem import com.github.libretube.api.obj.Streams import com.github.libretube.constants.IntentData @@ -73,6 +72,7 @@ import com.github.libretube.helpers.DashHelper import com.github.libretube.helpers.ImageHelper import com.github.libretube.helpers.NavigationHelper import com.github.libretube.helpers.PlayerHelper +import com.github.libretube.helpers.PlayerHelper.checkForSegments import com.github.libretube.helpers.PlayerHelper.loadPlaybackParams import com.github.libretube.helpers.PreferenceHelper import com.github.libretube.obj.ShareData @@ -114,10 +114,6 @@ import com.google.android.exoplayer2.ui.StyledPlayerView import com.google.android.exoplayer2.upstream.DefaultDataSource import com.google.android.exoplayer2.util.MimeTypes import com.google.android.material.dialog.MaterialAlertDialogBuilder -import java.io.IOException -import java.util.* -import java.util.concurrent.Executors -import kotlin.math.abs import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -125,6 +121,10 @@ import kotlinx.coroutines.withContext import kotlinx.datetime.LocalDate import kotlinx.serialization.encodeToString import retrofit2.HttpException +import java.io.IOException +import java.util.* +import java.util.concurrent.Executors +import kotlin.math.abs class PlayerFragment : BaseFragment(), OnlinePlayerOptions { @@ -182,7 +182,7 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions { /** * SponsorBlock */ - private lateinit var segmentData: SegmentData + private var segments = listOf() private var sponsorBlockEnabled = PlayerHelper.sponsorBlockEnabled val handler = Handler(Looper.getMainLooper()) @@ -642,31 +642,14 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions { if (!sponsorBlockEnabled) return - if (!::segmentData.isInitialized || segmentData.segments.isEmpty()) return + if (segments.isEmpty()) return - val currentPosition = exoPlayer.currentPosition - segmentData.segments.forEach { segment: Segment -> - val segmentStart = (segment.segment[0] * 1000f).toLong() - val segmentEnd = (segment.segment[1] * 1000f).toLong() - - // show the button to manually skip the segment - if (currentPosition in segmentStart until segmentEnd) { - if (PlayerHelper.skipSegmentsManually) { - binding.sbSkipBtn.visibility = View.VISIBLE - binding.sbSkipBtn.setOnClickListener { - exoPlayer.seekTo(segmentEnd) - } - return - } - - if (PlayerHelper.sponsorBlockNotifications) { - Toast.makeText(context, R.string.segment_skipped, Toast.LENGTH_SHORT).show() - } - - // skip the segment automatically + exoPlayer.checkForSegments(requireContext(), segments, PlayerHelper.skipSegmentsManually)?.let { segmentEnd -> + binding.sbSkipBtn.visibility = View.VISIBLE + binding.sbSkipBtn.setOnClickListener { exoPlayer.seekTo(segmentEnd) - return } + return } if (PlayerHelper.skipSegmentsManually) binding.sbSkipBtn.visibility = View.GONE @@ -764,13 +747,13 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions { runCatching { val categories = PlayerHelper.getSponsorBlockCategories() if (categories.isEmpty()) return@runCatching - segmentData = + segments = RetrofitInstance.api.getSegments( videoId!!, JsonHelper.json.encodeToString(categories) - ) - if (segmentData.segments.isEmpty()) return@runCatching - playerBinding.exoProgress.setSegments(segmentData.segments) + ).segments + if (segments.isEmpty()) return@runCatching + playerBinding.exoProgress.setSegments(segments) runOnUiThread { playerBinding.sbToggle.visibility = View.VISIBLE updateDisplayedDuration() @@ -1103,12 +1086,10 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions { playerBinding.duration.text = DateUtils.formatElapsedTime( exoPlayer.duration.div(1000) ) - if (!this::segmentData.isInitialized || this.segmentData.segments.isEmpty()) { - return - } + if (segments.isEmpty()) return val durationWithSb = DateUtils.formatElapsedTime( - exoPlayer.duration.div(1000) - segmentData.segments.sumOf { + exoPlayer.duration.div(1000) - segments.sumOf { it.segment[1] - it.segment[0] }.toInt() )