Merge pull request #4849 from Bnyro/master

feat: option to set a different default resolution when not in fullscreen
This commit is contained in:
Bnyro 2023-09-25 10:43:56 +02:00 committed by GitHub
commit 38549dbdb8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 89 additions and 31 deletions

View File

@ -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)
}
}

View File

@ -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<Segment>()
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)
}

View File

@ -177,6 +177,17 @@
<item>240p</item>
<item>144p</item>
</string-array>
<string-array name="defresNoPortrait">
<item>@string/same_as_fullscreen</item>
<item>2160p</item>
<item>1440p</item>
<item>1080p</item>
<item>720p</item>
<item>480p</item>
<item>360p</item>
<item>240p</item>
<item>144p</item>
</string-array>
<string-array name="defresValue">
<item />
<item>2160p</item>

View File

@ -445,6 +445,9 @@
<string name="uploader_name">Uploader name</string>
<string name="duration_span">Duration: %1$s</string>
<string name="remove_watched_videos">Remove watched videos</string>
<string name="no_fullscreen_resolution">No-Fullscreen resolution</string>
<string name="same_as_fullscreen">Same as fullscreen</string>
<!-- Backup & Restore Settings -->
<string name="import_subscriptions_from">Import subscriptions from</string>
<string name="export_subscriptions_to">Export subscriptions to</string>

View File

@ -13,6 +13,15 @@
app:title="@string/defres"
app:useSimpleSummaryProvider="true" />
<ListPreference
android:icon="@drawable/ic_fullscreen"
app:defaultValue=""
app:entries="@array/defresNoPortrait"
app:entryValues="@array/defresValue"
app:key="default_res_no_fullscreen"
app:title="@string/no_fullscreen_resolution"
app:useSimpleSummaryProvider="true" />
<ListPreference
android:icon="@drawable/ic_headphones"
app:defaultValue="auto"
@ -35,6 +44,15 @@
app:title="@string/defres"
app:useSimpleSummaryProvider="true" />
<ListPreference
android:icon="@drawable/ic_fullscreen"
app:defaultValue=""
app:entries="@array/defresNoPortrait"
app:entryValues="@array/defresValue"
app:key="default_res_mobile_no_fullscreen"
app:title="@string/no_fullscreen_resolution"
app:useSimpleSummaryProvider="true" />
<ListPreference
android:icon="@drawable/ic_headphones"
app:defaultValue="auto"