Merge pull request #1513 from Bnyro/master

Add features to the offline player
This commit is contained in:
Bnyro 2022-10-07 19:40:47 +02:00 committed by GitHub
commit 9dd7940d15
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 233 additions and 212 deletions

View File

@ -39,6 +39,8 @@
<activity <activity
android:name=".ui.activities.OfflinePlayerActivity" android:name=".ui.activities.OfflinePlayerActivity"
android:supportsPictureInPicture="true"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
android:label="@string/player" /> android:label="@string/player" />
<activity <activity

View File

@ -5,7 +5,6 @@ import android.app.NotificationChannel
import android.app.NotificationManager import android.app.NotificationManager
import android.app.Service import android.app.Service
import android.content.Intent import android.content.Intent
import android.media.session.PlaybackState
import android.os.Build import android.os.Build
import android.os.Handler import android.os.Handler
import android.os.IBinder import android.os.IBinder
@ -18,8 +17,6 @@ import com.github.libretube.constants.BACKGROUND_CHANNEL_ID
import com.github.libretube.constants.IntentData import com.github.libretube.constants.IntentData
import com.github.libretube.constants.PLAYER_NOTIFICATION_ID 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.DatabaseHelper
import com.github.libretube.extensions.query
import com.github.libretube.extensions.toID import com.github.libretube.extensions.toID
import com.github.libretube.util.AutoPlayHelper import com.github.libretube.util.AutoPlayHelper
import com.github.libretube.util.NowPlayingNotification import com.github.libretube.util.NowPlayingNotification
@ -89,8 +86,6 @@ class BackgroundMode : Service() {
/** /**
* Autoplay Preference * Autoplay Preference
*/ */
private val autoplay = PreferenceHelper.getBoolean(PreferenceKeys.AUTO_PLAY, true)
private val handler = Handler(Looper.getMainLooper()) private val handler = Handler(Looper.getMainLooper())
/** /**
@ -191,7 +186,7 @@ class BackgroundMode : Service() {
fetchSponsorBlockSegments() fetchSponsorBlockSegments()
if (autoplay) setNextStream() if (PlayerHelper.autoPlayEnabled) setNextStream()
} }
/** /**
@ -217,21 +212,13 @@ class BackgroundMode : Service() {
override fun onPlaybackStateChanged(state: Int) { override fun onPlaybackStateChanged(state: Int) {
when (state) { when (state) {
Player.STATE_ENDED -> { Player.STATE_ENDED -> {
if (autoplay) playNextVideo() if (PlayerHelper.autoPlayEnabled) playNextVideo()
} }
Player.STATE_IDLE -> { Player.STATE_IDLE -> {
onDestroy() onDestroy()
} }
Player.STATE_BUFFERING -> {} Player.STATE_BUFFERING -> {}
Player.STATE_READY -> {} Player.STATE_READY -> {}
PlaybackState.STATE_PAUSED -> {
query {
DatabaseHelper.saveWatchPosition(
videoId,
player?.currentPosition ?: 0L
)
}
}
} }
} }
@ -332,11 +319,7 @@ class BackgroundMode : Service() {
val segmentEnd = (segment.segment[1] * 1000f).toLong() val segmentEnd = (segment.segment[1] * 1000f).toLong()
val currentPosition = player?.currentPosition val currentPosition = player?.currentPosition
if (currentPosition in segmentStart until segmentEnd) { if (currentPosition in segmentStart until segmentEnd) {
if (PreferenceHelper.getBoolean( if (PlayerHelper.sponsorBlockNotifications) {
"sb_notifications_key",
true
)
) {
try { try {
Toast.makeText(this, R.string.segment_skipped, Toast.LENGTH_SHORT) Toast.makeText(this, R.string.segment_skipped, Toast.LENGTH_SHORT)
.show() .show()

View File

@ -1,8 +1,11 @@
package com.github.libretube.ui.activities package com.github.libretube.ui.activities
import android.app.PictureInPictureParams
import android.content.pm.ActivityInfo import android.content.pm.ActivityInfo
import android.graphics.Color import android.graphics.Color
import android.media.session.PlaybackState
import android.net.Uri import android.net.Uri
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import android.view.WindowManager import android.view.WindowManager
@ -14,6 +17,7 @@ import com.github.libretube.databinding.ActivityOfflinePlayerBinding
import com.github.libretube.databinding.ExoStyledPlayerControlViewBinding import com.github.libretube.databinding.ExoStyledPlayerControlViewBinding
import com.github.libretube.ui.base.BaseActivity import com.github.libretube.ui.base.BaseActivity
import com.github.libretube.util.DownloadHelper import com.github.libretube.util.DownloadHelper
import com.github.libretube.util.PlayerHelper
import com.google.android.exoplayer2.ExoPlayer import com.google.android.exoplayer2.ExoPlayer
import com.google.android.exoplayer2.MediaItem import com.google.android.exoplayer2.MediaItem
import com.google.android.exoplayer2.source.MergingMediaSource import com.google.android.exoplayer2.source.MergingMediaSource
@ -43,6 +47,8 @@ class OfflinePlayerActivity : BaseActivity() {
initializePlayer() initializePlayer()
playVideo() playVideo()
requestedOrientation = PlayerHelper.getOrientation(player.videoSize)
} }
private fun initializePlayer() { private fun initializePlayer() {
@ -153,4 +159,20 @@ class OfflinePlayerActivity : BaseActivity() {
player.release() player.release()
super.onDestroy() super.onDestroy()
} }
override fun onUserLeaveHint() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return
if (!PlayerHelper.pipEnabled) return
if (player.playbackState == PlaybackState.STATE_PAUSED) return
enterPictureInPictureMode(
PictureInPictureParams.Builder()
.setActions(emptyList())
.build()
)
super.onUserLeaveHint()
}
} }

View File

@ -67,7 +67,6 @@ import com.github.libretube.ui.views.BottomSheet
import com.github.libretube.util.AutoPlayHelper import com.github.libretube.util.AutoPlayHelper
import com.github.libretube.util.BackgroundHelper import com.github.libretube.util.BackgroundHelper
import com.github.libretube.util.ImageHelper import com.github.libretube.util.ImageHelper
import com.github.libretube.util.NetworkHelper
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
@ -150,25 +149,8 @@ class PlayerFragment : BaseFragment() {
/** /**
* user preferences * user preferences
*/ */
private var token = "" private var token = PreferenceHelper.getToken()
private var relatedStreamsEnabled = true
private var autoRotationEnabled = true
private var pausePlayerOnScreenOffEnabled = false
private var fullscreenOrientationPref = "ratio"
private var watchHistoryEnabled = true
private var watchPositionsEnabled = true
private var useSystemCaptionStyle = true
private var videoFormatPreference = "webm"
private var defRes = ""
private var bufferingGoal = 50000
private var defaultSubtitleCode = ""
private var sponsorBlockEnabled = true
private var sponsorBlockNotifications = true
private var skipButtonsEnabled = false
private var pipEnabled = true
private var videoShownInExternalPlayer = false private var videoShownInExternalPlayer = false
private var skipSegmentsManually = false
private var progressiveLoadingIntervalSize = "64"
/** /**
* for autoplay * for autoplay
@ -214,7 +196,7 @@ class PlayerFragment : BaseFragment() {
setUserPrefs() setUserPrefs()
val mainActivity = activity as MainActivity val mainActivity = activity as MainActivity
if (autoRotationEnabled) { if (PlayerHelper.autoRotationEnabled) {
// enable auto rotation // enable auto rotation
mainActivity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR mainActivity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR
onConfigurationChanged(resources.configuration) onConfigurationChanged(resources.configuration)
@ -245,102 +227,8 @@ class PlayerFragment : BaseFragment() {
token = PreferenceHelper.getToken() token = PreferenceHelper.getToken()
// save whether auto rotation is enabled // save whether auto rotation is enabled
autoRotationEnabled = PreferenceHelper.getBoolean(
PreferenceKeys.AUTO_FULLSCREEN,
false
)
// save whether related streams are enabled // save whether related streams are enabled
relatedStreamsEnabled = PreferenceHelper.getBoolean(
PreferenceKeys.RELATED_STREAMS,
true
)
fullscreenOrientationPref = PreferenceHelper.getString(
PreferenceKeys.FULLSCREEN_ORIENTATION,
"ratio"
)
pausePlayerOnScreenOffEnabled = PreferenceHelper.getBoolean(
PreferenceKeys.PAUSE_ON_SCREEN_OFF,
false
)
watchPositionsEnabled = PreferenceHelper.getBoolean(
PreferenceKeys.WATCH_POSITION_TOGGLE,
true
)
watchHistoryEnabled = PreferenceHelper.getBoolean(
PreferenceKeys.WATCH_HISTORY_TOGGLE,
true
)
useSystemCaptionStyle = PreferenceHelper.getBoolean(
PreferenceKeys.SYSTEM_CAPTION_STYLE,
true
)
videoFormatPreference = PreferenceHelper.getString(
PreferenceKeys.PLAYER_VIDEO_FORMAT,
"webm"
)
defRes = if (NetworkHelper.isNetworkMobile(requireContext())) {
PreferenceHelper.getString(
PreferenceKeys.DEFAULT_RESOLUTION_MOBILE,
""
)
} else {
PreferenceHelper.getString(
PreferenceKeys.DEFAULT_RESOLUTION,
""
)
}
bufferingGoal = PreferenceHelper.getString(
PreferenceKeys.BUFFERING_GOAL,
"50"
).toInt() * 1000
sponsorBlockEnabled = PreferenceHelper.getBoolean(
"sb_enabled_key",
true
)
sponsorBlockNotifications = PreferenceHelper.getBoolean(
"sb_notifications_key",
true
)
defaultSubtitleCode = PreferenceHelper.getString(
PreferenceKeys.DEFAULT_SUBTITLE,
""
)
if (defaultSubtitleCode.contains("-")) {
defaultSubtitleCode = defaultSubtitleCode.split("-")[0]
}
skipButtonsEnabled = PreferenceHelper.getBoolean(
PreferenceKeys.SKIP_BUTTONS,
false
)
pipEnabled = PreferenceHelper.getBoolean(
PreferenceKeys.PICTURE_IN_PICTURE,
true
)
skipSegmentsManually = PreferenceHelper.getBoolean(
PreferenceKeys.SB_SKIP_MANUALLY,
false
)
progressiveLoadingIntervalSize = PreferenceHelper.getString(
PreferenceKeys.PROGRESSIVE_LOADING_INTERVAL_SIZE,
"64"
)
} }
@SuppressLint("ClickableViewAccessibility") @SuppressLint("ClickableViewAccessibility")
@ -522,7 +410,7 @@ class PlayerFragment : BaseFragment() {
// FullScreen button trigger // FullScreen button trigger
// hide fullscreen button if auto rotation enabled // hide fullscreen button if auto rotation enabled
playerBinding.fullscreen.visibility = if (autoRotationEnabled) View.GONE else View.VISIBLE playerBinding.fullscreen.visibility = if (PlayerHelper.autoRotationEnabled) View.GONE else View.VISIBLE
playerBinding.fullscreen.setOnClickListener { playerBinding.fullscreen.setOnClickListener {
// hide player controller // hide player controller
exoPlayerView.hideController() exoPlayerView.hideController()
@ -582,24 +470,9 @@ class PlayerFragment : BaseFragment() {
playerBinding.exoTitle.visibility = View.VISIBLE playerBinding.exoTitle.visibility = View.VISIBLE
val mainActivity = activity as MainActivity val mainActivity = activity as MainActivity
if (!autoRotationEnabled) { if (!PlayerHelper.autoRotationEnabled) {
// different orientations of the video are only available when auto rotation is disabled // different orientations of the video are only available when auto rotation is disabled
val orientation = when (fullscreenOrientationPref) { val orientation = PlayerHelper.getOrientation(exoPlayer.videoSize)
"ratio" -> {
val videoSize = exoPlayer.videoSize
// probably a youtube shorts video
if (videoSize.height > videoSize.width) {
ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT
} // a video with normal aspect ratio
else {
ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
}
}
"auto" -> ActivityInfo.SCREEN_ORIENTATION_SENSOR
"landscape" -> ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
"portrait" -> ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT
else -> ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
}
mainActivity.requestedOrientation = orientation mainActivity.requestedOrientation = orientation
} }
@ -619,7 +492,7 @@ class PlayerFragment : BaseFragment() {
playerBinding.fullscreen.setImageResource(R.drawable.ic_fullscreen) playerBinding.fullscreen.setImageResource(R.drawable.ic_fullscreen)
playerBinding.exoTitle.visibility = View.INVISIBLE playerBinding.exoTitle.visibility = View.INVISIBLE
if (!autoRotationEnabled) { if (!PlayerHelper.autoRotationEnabled) {
// switch back to portrait mode if auto rotation disabled // switch back to portrait mode if auto rotation disabled
val mainActivity = activity as MainActivity val mainActivity = activity as MainActivity
mainActivity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT mainActivity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT
@ -673,7 +546,7 @@ class PlayerFragment : BaseFragment() {
// pause player if screen off and setting enabled // pause player if screen off and setting enabled
if ( if (
this::exoPlayer.isInitialized && !isScreenOn && pausePlayerOnScreenOffEnabled this::exoPlayer.isInitialized && !isScreenOn && PlayerHelper.pausePlayerOnScreenOffEnabled
) { ) {
exoPlayer.pause() exoPlayer.pause()
} }
@ -701,19 +574,19 @@ class PlayerFragment : BaseFragment() {
// save the watch position if video isn't finished and option enabled // save the watch position if video isn't finished and option enabled
private fun saveWatchPosition() { private fun saveWatchPosition() {
if (watchPositionsEnabled && exoPlayer.currentPosition != exoPlayer.duration) { if (PlayerHelper.watchPositionsEnabled && exoPlayer.currentPosition != exoPlayer.duration) {
DatabaseHelper.saveWatchPosition( DatabaseHelper.saveWatchPosition(
videoId!!, videoId!!,
exoPlayer.currentPosition exoPlayer.currentPosition
) )
} else if (watchPositionsEnabled) { } else if (PlayerHelper.watchPositionsEnabled) {
// delete watch position if video has ended // delete watch position if video has ended
DatabaseHelper.removeWatchPosition(videoId!!) DatabaseHelper.removeWatchPosition(videoId!!)
} }
} }
private fun checkForSegments() { private fun checkForSegments() {
if (!exoPlayer.isPlaying || !sponsorBlockEnabled) return if (!exoPlayer.isPlaying || !PlayerHelper.sponsorBlockEnabled) return
Handler(Looper.getMainLooper()).postDelayed(this::checkForSegments, 100) Handler(Looper.getMainLooper()).postDelayed(this::checkForSegments, 100)
@ -726,7 +599,7 @@ class PlayerFragment : BaseFragment() {
// show the button to manually skip the segment // show the button to manually skip the segment
if (currentPosition in segmentStart until segmentEnd) { if (currentPosition in segmentStart until segmentEnd) {
if (skipSegmentsManually) { if (PlayerHelper.skipSegmentsManually) {
binding.sbSkipBtn.visibility = View.VISIBLE binding.sbSkipBtn.visibility = View.VISIBLE
binding.sbSkipBtn.setOnClickListener { binding.sbSkipBtn.setOnClickListener {
exoPlayer.seekTo(segmentEnd) exoPlayer.seekTo(segmentEnd)
@ -734,7 +607,7 @@ class PlayerFragment : BaseFragment() {
return return
} }
if (sponsorBlockNotifications) { if (PlayerHelper.sponsorBlockNotifications) {
Toast Toast
.makeText( .makeText(
context, context,
@ -749,7 +622,7 @@ class PlayerFragment : BaseFragment() {
} }
} }
if (skipSegmentsManually) binding.sbSkipBtn.visibility = View.GONE if (PlayerHelper.skipSegmentsManually) binding.sbSkipBtn.visibility = View.GONE
} }
private fun playVideo() { private fun playVideo() {
@ -789,14 +662,14 @@ class PlayerFragment : BaseFragment() {
} }
// show the player notification // show the player notification
initializePlayerNotification() initializePlayerNotification()
if (sponsorBlockEnabled) fetchSponsorBlockSegments() if (PlayerHelper.sponsorBlockEnabled) fetchSponsorBlockSegments()
// show comments if related streams disabled // show comments if related streams disabled
if (!relatedStreamsEnabled) toggleComments() if (!PlayerHelper.relatedStreamsEnabled) toggleComments()
// prepare for autoplay // prepare for autoplay
if (binding.player.autoplayEnabled) setNextStream() if (binding.player.autoplayEnabled) setNextStream()
// add the video to the watch history // add the video to the watch history
if (watchHistoryEnabled) DatabaseHelper.addToWatchHistory(videoId!!, streams) if (PlayerHelper.watchHistoryEnabled) DatabaseHelper.addToWatchHistory(videoId!!, streams)
} }
} }
} }
@ -902,7 +775,7 @@ class PlayerFragment : BaseFragment() {
player = exoPlayer player = exoPlayer
} }
if (useSystemCaptionStyle) { if (PlayerHelper.useSystemCaptionStyle) {
// set the subtitle style // set the subtitle style
val captionStyle = PlayerHelper.getCaptionStyle(requireContext()) val captionStyle = PlayerHelper.getCaptionStyle(requireContext())
exoPlayerView.subtitleView?.setApplyEmbeddedStyles(captionStyle == CaptionStyleCompat.DEFAULT) exoPlayerView.subtitleView?.setApplyEmbeddedStyles(captionStyle == CaptionStyleCompat.DEFAULT)
@ -964,7 +837,7 @@ class PlayerFragment : BaseFragment() {
// Listener for play and pause icon change // Listener for play and pause icon change
exoPlayer.addListener(object : Player.Listener { exoPlayer.addListener(object : Player.Listener {
override fun onIsPlayingChanged(isPlaying: Boolean) { override fun onIsPlayingChanged(isPlaying: Boolean) {
if (isPlaying && sponsorBlockEnabled) { if (isPlaying && PlayerHelper.sponsorBlockEnabled) {
Handler(Looper.getMainLooper()).postDelayed( Handler(Looper.getMainLooper()).postDelayed(
this@PlayerFragment::checkForSegments, this@PlayerFragment::checkForSegments,
100 100
@ -1070,7 +943,7 @@ class PlayerFragment : BaseFragment() {
} }
} }
} }
if (relatedStreamsEnabled) { if (PlayerHelper.relatedStreamsEnabled) {
// only show related streams if enabled // only show related streams if enabled
binding.relatedRecView.adapter = TrendingAdapter( binding.relatedRecView.adapter = TrendingAdapter(
response.relatedStreams!!, response.relatedStreams!!,
@ -1120,13 +993,13 @@ class PlayerFragment : BaseFragment() {
// next and previous buttons // next and previous buttons
playerBinding.skipPrev.visibility = if ( playerBinding.skipPrev.visibility = if (
skipButtonsEnabled && PlayingQueue.hasPrev() PlayerHelper.skipButtonsEnabled && PlayingQueue.hasPrev()
) { ) {
View.VISIBLE View.VISIBLE
} else { } else {
View.INVISIBLE View.INVISIBLE
} }
playerBinding.skipNext.visibility = if (skipButtonsEnabled) View.VISIBLE else View.INVISIBLE playerBinding.skipNext.visibility = if (PlayerHelper.skipButtonsEnabled) View.VISIBLE else View.INVISIBLE
playerBinding.skipPrev.setOnClickListener { playerBinding.skipPrev.setOnClickListener {
videoId = PlayingQueue.getPrev() videoId = PlayingQueue.getPrev()
@ -1220,9 +1093,9 @@ class PlayerFragment : BaseFragment() {
videoUri: Uri, videoUri: Uri,
audioUrl: String audioUrl: String
) { ) {
val checkIntervalSize = when (progressiveLoadingIntervalSize) { val checkIntervalSize = when (PlayerHelper.progressiveLoadingIntervalSize) {
"default" -> ProgressiveMediaSource.DEFAULT_LOADING_CHECK_INTERVAL_BYTES "default" -> ProgressiveMediaSource.DEFAULT_LOADING_CHECK_INTERVAL_BYTES
else -> progressiveLoadingIntervalSize.toInt() * 1024 else -> PlayerHelper.progressiveLoadingIntervalSize.toInt() * 1024
} }
val dataSourceFactory: DataSource.Factory = val dataSourceFactory: DataSource.Factory =
@ -1270,7 +1143,7 @@ class PlayerFragment : BaseFragment() {
for (vid in streams.videoStreams!!) { for (vid in streams.videoStreams!!) {
// append quality to list if it has the preferred format (e.g. MPEG) // append quality to list if it has the preferred format (e.g. MPEG)
val preferredMimeType = "video/$videoFormatPreference" val preferredMimeType = "video/${PlayerHelper.videoFormatPreference}"
if (vid.url != null && vid.mimeType == preferredMimeType) { // preferred format if (vid.url != null && vid.mimeType == preferredMimeType) { // preferred format
videosNameArray += vid.quality.toString() videosNameArray += vid.quality.toString()
videosUrlArray += vid.url!!.toUri() videosUrlArray += vid.url!!.toUri()
@ -1302,9 +1175,9 @@ class PlayerFragment : BaseFragment() {
} }
// set the default subtitle if available // set the default subtitle if available
if (defaultSubtitleCode != "" && subtitleCodesList.contains(defaultSubtitleCode)) { if (PlayerHelper.defaultSubtitleCode != "" && subtitleCodesList.contains(PlayerHelper.defaultSubtitleCode)) {
val newParams = trackSelector.buildUponParameters() val newParams = trackSelector.buildUponParameters()
.setPreferredTextLanguage(defaultSubtitleCode) .setPreferredTextLanguage(PlayerHelper.defaultSubtitleCode)
.setPreferredTextRoleFlags(C.ROLE_FLAG_CAPTION) .setPreferredTextRoleFlags(C.ROLE_FLAG_CAPTION)
trackSelector.setParameters(newParams) trackSelector.setParameters(newParams)
} }
@ -1322,10 +1195,11 @@ class PlayerFragment : BaseFragment() {
videosNameArray: Array<String>, videosNameArray: Array<String>,
videosUrlArray: Array<Uri> videosUrlArray: Array<Uri>
) { ) {
if (defRes != "") { val defaultResolution = PlayerHelper.getDefaultResolution(requireContext())
if (defaultResolution != "") {
videosNameArray.forEachIndexed { index, pipedStream -> videosNameArray.forEachIndexed { index, pipedStream ->
// search for quality preference in the available stream sources // search for quality preference in the available stream sources
if (pipedStream.contains(defRes)) { if (pipedStream.contains(defaultResolution)) {
val videoUri = videosUrlArray[index] val videoUri = videosUrlArray[index]
val audioUrl = val audioUrl =
PlayerHelper.getAudioSource(requireContext(), streams.audioStreams!!) PlayerHelper.getAudioSource(requireContext(), streams.audioStreams!!)
@ -1371,7 +1245,7 @@ class PlayerFragment : BaseFragment() {
.setBackBuffer(1000 * 60 * 3, true) .setBackBuffer(1000 * 60 * 3, true)
.setBufferDurationsMs( .setBufferDurationsMs(
1000 * 10, // exo default is 50s 1000 * 10, // exo default is 50s
bufferingGoal, PlayerHelper.bufferingGoal,
DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_MS, DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_MS,
DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS
) )
@ -1526,7 +1400,7 @@ class PlayerFragment : BaseFragment() {
} }
private fun shouldStartPiP(): Boolean { private fun shouldStartPiP(): Boolean {
if (!pipEnabled || if (!PlayerHelper.pipEnabled ||
exoPlayer.playbackState == PlaybackState.STATE_PAUSED || exoPlayer.playbackState == PlaybackState.STATE_PAUSED ||
videoShownInExternalPlayer videoShownInExternalPlayer
) { ) {
@ -1558,14 +1432,12 @@ class PlayerFragment : BaseFragment() {
override fun onConfigurationChanged(newConfig: Configuration) { override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig) super.onConfigurationChanged(newConfig)
if (autoRotationEnabled) { if (!PlayerHelper.autoRotationEnabled) return
val orientation = newConfig.orientation when (newConfig.orientation) {
when (orientation) { // go to fullscreen mode
// go to fullscreen mode Configuration.ORIENTATION_LANDSCAPE -> setFullscreen()
Configuration.ORIENTATION_LANDSCAPE -> setFullscreen() // exit fullscreen if not landscape
// exit fullscreen if not landscape else -> unsetFullscreen()
else -> unsetFullscreen()
}
} }
} }
} }

View File

@ -10,7 +10,6 @@ import android.view.MotionEvent
import android.view.View import android.view.View
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
import com.github.libretube.R import com.github.libretube.R
import com.github.libretube.constants.PreferenceKeys
import com.github.libretube.databinding.DoubleTapOverlayBinding import com.github.libretube.databinding.DoubleTapOverlayBinding
import com.github.libretube.databinding.ExoStyledPlayerControlViewBinding import com.github.libretube.databinding.ExoStyledPlayerControlViewBinding
import com.github.libretube.models.interfaces.DoubleTapInterface import com.github.libretube.models.interfaces.DoubleTapInterface
@ -19,13 +18,12 @@ import com.github.libretube.obj.BottomSheetItem
import com.github.libretube.ui.activities.MainActivity import com.github.libretube.ui.activities.MainActivity
import com.github.libretube.ui.sheets.PlaybackSpeedSheet import com.github.libretube.ui.sheets.PlaybackSpeedSheet
import com.github.libretube.util.DoubleTapListener import com.github.libretube.util.DoubleTapListener
import com.github.libretube.util.PreferenceHelper import com.github.libretube.util.PlayerHelper
import com.google.android.exoplayer2.PlaybackParameters import com.google.android.exoplayer2.PlaybackParameters
import com.google.android.exoplayer2.trackselection.TrackSelector import com.google.android.exoplayer2.trackselection.TrackSelector
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout import com.google.android.exoplayer2.ui.AspectRatioFrameLayout
import com.google.android.exoplayer2.ui.StyledPlayerView import com.google.android.exoplayer2.ui.StyledPlayerView
import com.google.android.exoplayer2.util.RepeatModeUtil import com.google.android.exoplayer2.util.RepeatModeUtil
import kotlin.math.roundToInt
@SuppressLint("ClickableViewAccessibility") @SuppressLint("ClickableViewAccessibility")
internal class CustomExoPlayerView( internal class CustomExoPlayerView(
@ -53,27 +51,9 @@ internal class CustomExoPlayerView(
/** /**
* Preferences * Preferences
*/ */
var autoplayEnabled = PreferenceHelper.getBoolean( var autoplayEnabled = PlayerHelper.autoPlayEnabled
PreferenceKeys.AUTO_PLAY,
true
)
private val playbackSpeed = PreferenceHelper.getString( private var resizeModePref = PlayerHelper.resizeModePref
PreferenceKeys.PLAYBACK_SPEED,
"1"
).replace("F", "")
private val seekIncrement = PreferenceHelper.getString(
PreferenceKeys.SEEK_INCREMENT,
"10.0"
).toFloat()
.roundToInt()
.toLong() * 1000
private var resizeModePref = PreferenceHelper.getString(
PreferenceKeys.PLAYER_RESIZE_MODE,
"fit"
)
private fun toggleController() { private fun toggleController() {
if (isControllerFullyVisible) hideController() else showController() if (isControllerFullyVisible) hideController() else showController()
@ -108,7 +88,7 @@ internal class CustomExoPlayerView(
initializeAdvancedOptions(context) initializeAdvancedOptions(context)
player?.playbackParameters = PlaybackParameters( player?.playbackParameters = PlaybackParameters(
playbackSpeed.toFloat(), PlayerHelper.playbackSpeed.toFloat(),
1.0f 1.0f
) )
@ -250,7 +230,7 @@ internal class CustomExoPlayerView(
private fun enableDoubleTapToSeek() { private fun enableDoubleTapToSeek() {
// set seek increment text // set seek increment text
val seekIncrementText = (seekIncrement / 1000).toString() val seekIncrementText = (PlayerHelper.seekIncrement / 1000).toString()
doubleTapOverlayBinding?.rewindTV?.text = seekIncrementText doubleTapOverlayBinding?.rewindTV?.text = seekIncrementText
doubleTapOverlayBinding?.forwardTV?.text = seekIncrementText doubleTapOverlayBinding?.forwardTV?.text = seekIncrementText
doubleTapListener = doubleTapListener =
@ -265,7 +245,7 @@ internal class CustomExoPlayerView(
} }
private fun rewind() { private fun rewind() {
player?.seekTo((player?.currentPosition ?: 0L) - seekIncrement) player?.seekTo((player?.currentPosition ?: 0L) - PlayerHelper.seekIncrement)
// show the rewind button // show the rewind button
doubleTapOverlayBinding?.rewindBTN.apply { doubleTapOverlayBinding?.rewindBTN.apply {
@ -289,7 +269,7 @@ internal class CustomExoPlayerView(
} }
private fun forward() { private fun forward() {
player?.seekTo(player!!.currentPosition + seekIncrement) player?.seekTo(player!!.currentPosition + PlayerHelper.seekIncrement)
// show the forward button // show the forward button
doubleTapOverlayBinding?.forwardBTN.apply { doubleTapOverlayBinding?.forwardBTN.apply {

View File

@ -1,9 +1,12 @@
package com.github.libretube.util package com.github.libretube.util
import android.content.Context import android.content.Context
import android.content.pm.ActivityInfo
import android.view.accessibility.CaptioningManager import android.view.accessibility.CaptioningManager
import com.github.libretube.constants.PreferenceKeys import com.github.libretube.constants.PreferenceKeys
import com.google.android.exoplayer2.ui.CaptionStyleCompat import com.google.android.exoplayer2.ui.CaptionStyleCompat
import com.google.android.exoplayer2.video.VideoSize
import kotlin.math.roundToInt
object PlayerHelper { object PlayerHelper {
// get the audio source following the users preferences // get the audio source following the users preferences
@ -137,4 +140,163 @@ object PlayerHelper {
} }
return categories return categories
} }
fun getOrientation(videoSize: VideoSize): Int {
val fullscreenOrientationPref = PreferenceHelper.getString(
PreferenceKeys.FULLSCREEN_ORIENTATION,
"ratio"
)
return when (fullscreenOrientationPref) {
"ratio" -> {
// probably a youtube shorts video
if (videoSize.height > videoSize.width) {
ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT
} // a video with normal aspect ratio
else {
ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
}
}
"auto" -> ActivityInfo.SCREEN_ORIENTATION_SENSOR
"landscape" -> ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
"portrait" -> ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT
else -> ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
}
}
val autoRotationEnabled: Boolean
get() = PreferenceHelper.getBoolean(
PreferenceKeys.AUTO_FULLSCREEN,
false
)
val relatedStreamsEnabled: Boolean
get() = PreferenceHelper.getBoolean(
PreferenceKeys.RELATED_STREAMS,
true
)
val pausePlayerOnScreenOffEnabled: Boolean
get() = PreferenceHelper.getBoolean(
PreferenceKeys.PAUSE_ON_SCREEN_OFF,
false
)
val watchPositionsEnabled: Boolean
get() = PreferenceHelper.getBoolean(
PreferenceKeys.WATCH_POSITION_TOGGLE,
true
)
val watchHistoryEnabled: Boolean
get() = PreferenceHelper.getBoolean(
PreferenceKeys.WATCH_HISTORY_TOGGLE,
true
)
val useSystemCaptionStyle: Boolean
get() = PreferenceHelper.getBoolean(
PreferenceKeys.SYSTEM_CAPTION_STYLE,
true
)
val videoFormatPreference: String
get() = PreferenceHelper.getString(
PreferenceKeys.PLAYER_VIDEO_FORMAT,
"webm"
)
val bufferingGoal: Int
get() = PreferenceHelper.getString(
PreferenceKeys.BUFFERING_GOAL,
"50"
).toInt() * 1000
val sponsorBlockEnabled: Boolean
get() = PreferenceHelper.getBoolean(
"sb_enabled_key",
true
)
val sponsorBlockNotifications: Boolean
get() = PreferenceHelper.getBoolean(
"sb_notifications_key",
true
)
val defaultSubtitleCode: String
get() {
val code = PreferenceHelper.getString(
PreferenceKeys.DEFAULT_SUBTITLE,
""
)
if (code.contains("-")) {
return code.split("-")[0]
}
return code
}
val skipButtonsEnabled: Boolean
get() = PreferenceHelper.getBoolean(
PreferenceKeys.SKIP_BUTTONS,
false
)
val pipEnabled: Boolean get() = PreferenceHelper.getBoolean(
PreferenceKeys.PICTURE_IN_PICTURE,
true
)
val skipSegmentsManually: Boolean
get() = PreferenceHelper.getBoolean(
PreferenceKeys.SB_SKIP_MANUALLY,
false
)
val progressiveLoadingIntervalSize: String
get() = PreferenceHelper.getString(
PreferenceKeys.PROGRESSIVE_LOADING_INTERVAL_SIZE,
"64"
)
val autoPlayEnabled: Boolean
get() = PreferenceHelper.getBoolean(
PreferenceKeys.AUTO_PLAY,
true
)
val seekIncrement: Long
get() = PreferenceHelper.getString(
PreferenceKeys.SEEK_INCREMENT,
"10.0"
).toFloat()
.roundToInt()
.toLong() * 1000
val playbackSpeed: String
get() = PreferenceHelper.getString(
PreferenceKeys.PLAYBACK_SPEED,
"1"
).replace("F", "")
val resizeModePref: String
get() = PreferenceHelper.getString(
PreferenceKeys.PLAYER_RESIZE_MODE,
"fit"
)
fun getDefaultResolution(context: Context): String {
return if (NetworkHelper.isNetworkMobile(context)) {
PreferenceHelper.getString(
PreferenceKeys.DEFAULT_RESOLUTION_MOBILE,
""
)
} else {
PreferenceHelper.getString(
PreferenceKeys.DEFAULT_RESOLUTION,
""
)
}
}
} }