mirror of
https://github.com/libre-tube/LibreTube.git
synced 2025-01-07 10:00:31 +05:30
Merge pull request #4849 from Bnyro/master
feat: option to set a different default resolution when not in fullscreen
This commit is contained in:
commit
38549dbdb8
@ -36,10 +36,10 @@ import com.github.libretube.enums.SbSkipOptions
|
|||||||
import com.github.libretube.extensions.updateParameters
|
import com.github.libretube.extensions.updateParameters
|
||||||
import com.github.libretube.obj.VideoStats
|
import com.github.libretube.obj.VideoStats
|
||||||
import com.github.libretube.util.TextUtils
|
import com.github.libretube.util.TextUtils
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import kotlin.math.absoluteValue
|
import kotlin.math.absoluteValue
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
|
|
||||||
object PlayerHelper {
|
object PlayerHelper {
|
||||||
private const val ACTION_MEDIA_CONTROL = "media_control"
|
private const val ACTION_MEDIA_CONTROL = "media_control"
|
||||||
@ -324,13 +324,17 @@ object PlayerHelper {
|
|||||||
true
|
true
|
||||||
)
|
)
|
||||||
|
|
||||||
fun getDefaultResolution(context: Context): String {
|
fun getDefaultResolution(context: Context, isFullscreen: Boolean): Int? {
|
||||||
val prefKey = if (NetworkHelper.isNetworkMetered(context)) {
|
var prefKey = if (NetworkHelper.isNetworkMetered(context)) {
|
||||||
PreferenceKeys.DEFAULT_RESOLUTION_MOBILE
|
PreferenceKeys.DEFAULT_RESOLUTION_MOBILE
|
||||||
} else {
|
} else {
|
||||||
PreferenceKeys.DEFAULT_RESOLUTION
|
PreferenceKeys.DEFAULT_RESOLUTION
|
||||||
}
|
}
|
||||||
|
if (!isFullscreen) prefKey += "_no_fullscreen"
|
||||||
|
|
||||||
return PreferenceHelper.getString(prefKey, "")
|
return PreferenceHelper.getString(prefKey, "")
|
||||||
|
.replace("p", "")
|
||||||
|
.toIntOrNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -502,9 +506,9 @@ object PlayerHelper {
|
|||||||
if (currentPosition in segmentStart until segmentEnd) {
|
if (currentPosition in segmentStart until segmentEnd) {
|
||||||
if (sponsorBlockConfig[segment.category] == SbSkipOptions.AUTOMATIC ||
|
if (sponsorBlockConfig[segment.category] == SbSkipOptions.AUTOMATIC ||
|
||||||
(
|
(
|
||||||
sponsorBlockConfig[segment.category] == SbSkipOptions.AUTOMATIC_ONCE &&
|
sponsorBlockConfig[segment.category] == SbSkipOptions.AUTOMATIC_ONCE &&
|
||||||
!segment.skipped
|
!segment.skipped
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
if (sponsorBlockNotifications) {
|
if (sponsorBlockNotifications) {
|
||||||
runCatching {
|
runCatching {
|
||||||
@ -516,9 +520,9 @@ object PlayerHelper {
|
|||||||
segment.skipped = true
|
segment.skipped = true
|
||||||
} else if (sponsorBlockConfig[segment.category] == SbSkipOptions.MANUAL ||
|
} else if (sponsorBlockConfig[segment.category] == SbSkipOptions.MANUAL ||
|
||||||
(
|
(
|
||||||
sponsorBlockConfig[segment.category] == SbSkipOptions.AUTOMATIC_ONCE &&
|
sponsorBlockConfig[segment.category] == SbSkipOptions.AUTOMATIC_ONCE &&
|
||||||
segment.skipped
|
segment.skipped
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
return segment
|
return segment
|
||||||
}
|
}
|
||||||
@ -543,9 +547,9 @@ object PlayerHelper {
|
|||||||
return chapters
|
return chapters
|
||||||
.filter {
|
.filter {
|
||||||
it.highlightDrawable == null ||
|
it.highlightDrawable == null ||
|
||||||
// remove the video highlight if it's already longer ago than [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
|
// otherwise the SponsorBlock highlight would be shown from its starting point to the end
|
||||||
(currentPositionSeconds - it.start) < ChapterSegment.HIGHLIGHT_LENGTH
|
(currentPositionSeconds - it.start) < ChapterSegment.HIGHLIGHT_LENGTH
|
||||||
}
|
}
|
||||||
.sortedBy { it.start }
|
.sortedBy { it.start }
|
||||||
.indexOfLast { currentPositionSeconds >= it.start }
|
.indexOfLast { currentPositionSeconds >= it.start }
|
||||||
@ -701,9 +705,9 @@ object PlayerHelper {
|
|||||||
*/
|
*/
|
||||||
fun haveAudioTrackRoleFlagSet(@C.RoleFlags roleFlags: Int): Boolean {
|
fun haveAudioTrackRoleFlagSet(@C.RoleFlags roleFlags: Int): Boolean {
|
||||||
return isFlagSet(roleFlags, C.ROLE_FLAG_DESCRIBES_VIDEO) ||
|
return isFlagSet(roleFlags, C.ROLE_FLAG_DESCRIBES_VIDEO) ||
|
||||||
isFlagSet(roleFlags, C.ROLE_FLAG_DUB) ||
|
isFlagSet(roleFlags, C.ROLE_FLAG_DUB) ||
|
||||||
isFlagSet(roleFlags, C.ROLE_FLAG_MAIN) ||
|
isFlagSet(roleFlags, C.ROLE_FLAG_MAIN) ||
|
||||||
isFlagSet(roleFlags, C.ROLE_FLAG_ALTERNATE)
|
isFlagSet(roleFlags, C.ROLE_FLAG_ALTERNATE)
|
||||||
}
|
}
|
||||||
|
|
||||||
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
|
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
|
||||||
@ -716,7 +720,8 @@ object PlayerHelper {
|
|||||||
val audioInfo = "${player.audioFormat?.codecs.orEmpty()} ${
|
val audioInfo = "${player.audioFormat?.codecs.orEmpty()} ${
|
||||||
TextUtils.formatBitrate(player.audioFormat?.bitrate)
|
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)
|
return VideoStats(videoId, videoInfo, videoQuality, audioInfo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -159,33 +159,32 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
|||||||
*/
|
*/
|
||||||
private lateinit var streams: Streams
|
private lateinit var streams: Streams
|
||||||
|
|
||||||
/**
|
// progress state of the motion layout transition
|
||||||
* for the transition
|
|
||||||
*/
|
|
||||||
private var transitionStartId = 0
|
private var transitionStartId = 0
|
||||||
private var transitionEndId = 0
|
private var transitionEndId = 0
|
||||||
private var isTransitioning = true
|
private var isTransitioning = true
|
||||||
|
|
||||||
/**
|
// data and objects stored for the player
|
||||||
* for the player
|
|
||||||
*/
|
|
||||||
private lateinit var exoPlayer: ExoPlayer
|
private lateinit var exoPlayer: ExoPlayer
|
||||||
private lateinit var trackSelector: DefaultTrackSelector
|
private lateinit var trackSelector: DefaultTrackSelector
|
||||||
private var currentSubtitle = Subtitle(code = PlayerHelper.defaultSubtitleCode)
|
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(
|
private val cronetDataSourceFactory = CronetDataSource.Factory(
|
||||||
CronetHelper.cronetEngine,
|
CronetHelper.cronetEngine,
|
||||||
Executors.newCachedThreadPool()
|
Executors.newCachedThreadPool()
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
// for the player notification
|
||||||
* for the player notification
|
|
||||||
*/
|
|
||||||
private lateinit var nowPlayingNotification: NowPlayingNotification
|
private lateinit var nowPlayingNotification: NowPlayingNotification
|
||||||
|
|
||||||
/**
|
// SponsorBlock
|
||||||
* SponsorBlock
|
|
||||||
*/
|
|
||||||
private var segments = listOf<Segment>()
|
private var segments = listOf<Segment>()
|
||||||
private var sponsorBlockEnabled = PlayerHelper.sponsorBlockEnabled
|
private var sponsorBlockEnabled = PlayerHelper.sponsorBlockEnabled
|
||||||
private var sponsorBlockConfig = PlayerHelper.getSponsorBlockCategories()
|
private var sponsorBlockConfig = PlayerHelper.getSponsorBlockCategories()
|
||||||
@ -263,6 +262,9 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
|||||||
1000,
|
1000,
|
||||||
1000
|
1000
|
||||||
)
|
)
|
||||||
|
|
||||||
|
fullscreenResolution = PlayerHelper.getDefaultResolution(requireContext(), true)
|
||||||
|
noFullscreenResolution = PlayerHelper.getDefaultResolution(requireContext(), false)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
@ -541,6 +543,8 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
|||||||
|
|
||||||
updateFullscreenOrientation()
|
updateFullscreenOrientation()
|
||||||
viewModel.isFullscreen.value = true
|
viewModel.isFullscreen.value = true
|
||||||
|
|
||||||
|
updateResolutionOnFullscreenChange(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("SourceLockedOrientationActivity")
|
@SuppressLint("SourceLockedOrientationActivity")
|
||||||
@ -570,6 +574,8 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
viewModel.isFullscreen.value = false
|
viewModel.isFullscreen.value = false
|
||||||
|
|
||||||
|
updateResolutionOnFullscreenChange(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun toggleDescription() {
|
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() {
|
private suspend fun setStreamSource() {
|
||||||
val defaultResolution = PlayerHelper.getDefaultResolution(requireContext()).replace("p", "")
|
updateResolutionOnFullscreenChange(viewModel.isFullscreen.value == true)
|
||||||
if (defaultResolution.isNotEmpty()) setPlayerResolution(defaultResolution.toInt())
|
|
||||||
|
|
||||||
val (uri, mimeType) = when {
|
val (uri, mimeType) = when {
|
||||||
// LBRY HLS
|
// LBRY HLS
|
||||||
@ -1503,7 +1516,15 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
|||||||
if (currentQuality == it.resolution) "${it.name} ✓" else it.name
|
if (currentQuality == it.resolution) "${it.name} ✓" else it.name
|
||||||
}
|
}
|
||||||
) { which ->
|
) { 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)
|
.show(childFragmentManager)
|
||||||
}
|
}
|
||||||
|
@ -177,6 +177,17 @@
|
|||||||
<item>240p</item>
|
<item>240p</item>
|
||||||
<item>144p</item>
|
<item>144p</item>
|
||||||
</string-array>
|
</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">
|
<string-array name="defresValue">
|
||||||
<item />
|
<item />
|
||||||
<item>2160p</item>
|
<item>2160p</item>
|
||||||
|
@ -445,6 +445,9 @@
|
|||||||
<string name="uploader_name">Uploader name</string>
|
<string name="uploader_name">Uploader name</string>
|
||||||
<string name="duration_span">Duration: %1$s</string>
|
<string name="duration_span">Duration: %1$s</string>
|
||||||
<string name="remove_watched_videos">Remove watched videos</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 -->
|
<!-- Backup & Restore Settings -->
|
||||||
<string name="import_subscriptions_from">Import subscriptions from</string>
|
<string name="import_subscriptions_from">Import subscriptions from</string>
|
||||||
<string name="export_subscriptions_to">Export subscriptions to</string>
|
<string name="export_subscriptions_to">Export subscriptions to</string>
|
||||||
|
@ -13,6 +13,15 @@
|
|||||||
app:title="@string/defres"
|
app:title="@string/defres"
|
||||||
app:useSimpleSummaryProvider="true" />
|
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
|
<ListPreference
|
||||||
android:icon="@drawable/ic_headphones"
|
android:icon="@drawable/ic_headphones"
|
||||||
app:defaultValue="auto"
|
app:defaultValue="auto"
|
||||||
@ -35,6 +44,15 @@
|
|||||||
app:title="@string/defres"
|
app:title="@string/defres"
|
||||||
app:useSimpleSummaryProvider="true" />
|
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
|
<ListPreference
|
||||||
android:icon="@drawable/ic_headphones"
|
android:icon="@drawable/ic_headphones"
|
||||||
app:defaultValue="auto"
|
app:defaultValue="auto"
|
||||||
|
Loading…
Reference in New Issue
Block a user