From cfcf67450911c5647ed0ad79715e227c2736819d Mon Sep 17 00:00:00 2001 From: Bnyro Date: Mon, 25 Sep 2023 10:44:36 +0200 Subject: [PATCH] feat: option to set a different default resolution when not in fullscreen --- .../github/libretube/helpers/PlayerHelper.kt | 37 ++++++++------ .../libretube/ui/fragments/PlayerFragment.kt | 51 +++++++++++++------ app/src/main/res/values/array.xml | 11 ++++ app/src/main/res/values/strings.xml | 3 ++ app/src/main/res/xml/audio_video_settings.xml | 18 +++++++ 5 files changed, 89 insertions(+), 31 deletions(-) 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 882dba8d50..eeb0388684 100644 --- a/app/src/main/java/com/github/libretube/helpers/PlayerHelper.kt +++ b/app/src/main/java/com/github/libretube/helpers/PlayerHelper.kt @@ -36,10 +36,10 @@ import com.github.libretube.enums.SbSkipOptions import com.github.libretube.extensions.updateParameters import com.github.libretube.obj.VideoStats import com.github.libretube.util.TextUtils +import kotlinx.coroutines.runBlocking import java.util.Locale import kotlin.math.absoluteValue import kotlin.math.roundToInt -import kotlinx.coroutines.runBlocking object PlayerHelper { private const val ACTION_MEDIA_CONTROL = "media_control" @@ -324,13 +324,17 @@ object PlayerHelper { true ) - fun getDefaultResolution(context: Context): String { - val prefKey = if (NetworkHelper.isNetworkMetered(context)) { + fun getDefaultResolution(context: Context, isFullscreen: Boolean): Int? { + var prefKey = if (NetworkHelper.isNetworkMetered(context)) { PreferenceKeys.DEFAULT_RESOLUTION_MOBILE } else { PreferenceKeys.DEFAULT_RESOLUTION } + if (!isFullscreen) prefKey += "_no_fullscreen" + return PreferenceHelper.getString(prefKey, "") + .replace("p", "") + .toIntOrNull() } /** @@ -502,9 +506,9 @@ object PlayerHelper { if (currentPosition in segmentStart until segmentEnd) { if (sponsorBlockConfig[segment.category] == SbSkipOptions.AUTOMATIC || ( - sponsorBlockConfig[segment.category] == SbSkipOptions.AUTOMATIC_ONCE && - !segment.skipped - ) + sponsorBlockConfig[segment.category] == SbSkipOptions.AUTOMATIC_ONCE && + !segment.skipped + ) ) { if (sponsorBlockNotifications) { runCatching { @@ -516,9 +520,9 @@ object PlayerHelper { segment.skipped = true } else if (sponsorBlockConfig[segment.category] == SbSkipOptions.MANUAL || ( - sponsorBlockConfig[segment.category] == SbSkipOptions.AUTOMATIC_ONCE && - segment.skipped - ) + sponsorBlockConfig[segment.category] == SbSkipOptions.AUTOMATIC_ONCE && + segment.skipped + ) ) { return segment } @@ -543,9 +547,9 @@ object PlayerHelper { 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 + // 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 } @@ -701,9 +705,9 @@ object PlayerHelper { */ fun haveAudioTrackRoleFlagSet(@C.RoleFlags roleFlags: Int): Boolean { return isFlagSet(roleFlags, C.ROLE_FLAG_DESCRIBES_VIDEO) || - isFlagSet(roleFlags, C.ROLE_FLAG_DUB) || - isFlagSet(roleFlags, C.ROLE_FLAG_MAIN) || - isFlagSet(roleFlags, C.ROLE_FLAG_ALTERNATE) + isFlagSet(roleFlags, C.ROLE_FLAG_DUB) || + isFlagSet(roleFlags, C.ROLE_FLAG_MAIN) || + isFlagSet(roleFlags, C.ROLE_FLAG_ALTERNATE) } @androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class) @@ -716,7 +720,8 @@ object PlayerHelper { val audioInfo = "${player.audioFormat?.codecs.orEmpty()} ${ TextUtils.formatBitrate(player.audioFormat?.bitrate) }" - val videoQuality = "${player.videoFormat?.width}x${player.videoFormat?.height} ${player.videoFormat?.frameRate?.toInt()}fps" + val videoQuality = + "${player.videoFormat?.width}x${player.videoFormat?.height} ${player.videoFormat?.frameRate?.toInt()}fps" return VideoStats(videoId, videoInfo, videoQuality, audioInfo) } } 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 6f2a7080ca..8805f499a7 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 @@ -159,33 +159,32 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions { */ private lateinit var streams: Streams - /** - * for the transition - */ + // progress state of the motion layout transition private var transitionStartId = 0 private var transitionEndId = 0 private var isTransitioning = true - /** - * for the player - */ + // data and objects stored for the player private lateinit var exoPlayer: ExoPlayer private lateinit var trackSelector: DefaultTrackSelector private var currentSubtitle = Subtitle(code = PlayerHelper.defaultSubtitleCode) + // if null, it's been set to automatic + private var fullscreenResolution: Int? = null + + // the resolution to use when the video is not played in fullscreen + // if null, use same quality as fullscreen + private var noFullscreenResolution: Int? = null + private val cronetDataSourceFactory = CronetDataSource.Factory( CronetHelper.cronetEngine, Executors.newCachedThreadPool() ) - /** - * for the player notification - */ + // for the player notification private lateinit var nowPlayingNotification: NowPlayingNotification - /** - * SponsorBlock - */ + // SponsorBlock private var segments = listOf() private var sponsorBlockEnabled = PlayerHelper.sponsorBlockEnabled private var sponsorBlockConfig = PlayerHelper.getSponsorBlockCategories() @@ -263,6 +262,9 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions { 1000, 1000 ) + + fullscreenResolution = PlayerHelper.getDefaultResolution(requireContext(), true) + noFullscreenResolution = PlayerHelper.getDefaultResolution(requireContext(), false) } override fun onCreateView( @@ -541,6 +543,8 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions { updateFullscreenOrientation() viewModel.isFullscreen.value = true + + updateResolutionOnFullscreenChange(true) } @SuppressLint("SourceLockedOrientationActivity") @@ -570,6 +574,8 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions { } viewModel.isFullscreen.value = false + + updateResolutionOnFullscreenChange(false) } private fun toggleDescription() { @@ -1324,9 +1330,16 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions { } } + private fun updateResolutionOnFullscreenChange(isFullscreen: Boolean) { + if (!isFullscreen && noFullscreenResolution != null) { + setPlayerResolution(noFullscreenResolution!!) + } else { + setPlayerResolution(fullscreenResolution ?: Int.MAX_VALUE) + } + } + private suspend fun setStreamSource() { - val defaultResolution = PlayerHelper.getDefaultResolution(requireContext()).replace("p", "") - if (defaultResolution.isNotEmpty()) setPlayerResolution(defaultResolution.toInt()) + updateResolutionOnFullscreenChange(viewModel.isFullscreen.value == true) val (uri, mimeType) = when { // LBRY HLS @@ -1503,7 +1516,15 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions { if (currentQuality == it.resolution) "${it.name} ✓" else it.name } ) { which -> - setPlayerResolution(resolutions[which].resolution) + val newResolution = resolutions[which].resolution + setPlayerResolution(newResolution) + + // save the selected resolution to update on fullscreen change + if (noFullscreenResolution != null && viewModel.isFullscreen.value != true) { + noFullscreenResolution = newResolution + } else { + fullscreenResolution = newResolution + } } .show(childFragmentManager) } diff --git a/app/src/main/res/values/array.xml b/app/src/main/res/values/array.xml index c3b991500a..8be6154728 100644 --- a/app/src/main/res/values/array.xml +++ b/app/src/main/res/values/array.xml @@ -177,6 +177,17 @@ 240p 144p + + @string/same_as_fullscreen + 2160p + 1440p + 1080p + 720p + 480p + 360p + 240p + 144p + 2160p diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 20e260ae40..bd3194f905 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -445,6 +445,9 @@ Uploader name Duration: %1$s Remove watched videos + No-Fullscreen resolution + Same as fullscreen + Import subscriptions from Export subscriptions to diff --git a/app/src/main/res/xml/audio_video_settings.xml b/app/src/main/res/xml/audio_video_settings.xml index 2b574f285f..15fa1f0d23 100644 --- a/app/src/main/res/xml/audio_video_settings.xml +++ b/app/src/main/res/xml/audio_video_settings.xml @@ -13,6 +13,15 @@ app:title="@string/defres" app:useSimpleSummaryProvider="true" /> + + + +