Merge branch 'master' of gitlab.futo.org:videostreaming/grayjay

This commit is contained in:
Koen J 2025-06-06 10:17:03 +02:00
commit 57a3be35d0
8 changed files with 104 additions and 17 deletions

View file

@ -15,7 +15,6 @@
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK"/> <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC"/> <uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC"/>
<uses-permission android:name="android.permission.WRITE_SETTINGS" tools:ignore="ProtectedPermissions"/> <uses-permission android:name="android.permission.WRITE_SETTINGS" tools:ignore="ProtectedPermissions"/>
<uses-permission android:name="android.permission.UPDATE_PACKAGES_WITHOUT_USER_ACTION" />
<application <application
android:allowBackup="true" android:allowBackup="true"

View file

@ -531,6 +531,59 @@ class Settings : FragmentedStorageFileJson() {
else -> 10_000L; else -> 10_000L;
} }
} }
@FormField(R.string.min_playback_speed, FieldForm.DROPDOWN, R.string.min_playback_speed_description, 25)
@DropdownFieldOptionsId(R.array.min_playback_speed)
var minimumPlaybackSpeed: Int = 0;
@FormField(R.string.max_playback_speed, FieldForm.DROPDOWN, R.string.max_playback_speed_description, 26)
@DropdownFieldOptionsId(R.array.max_playback_speed)
var maximumPlaybackSpeed: Int = 2;
@FormField(R.string.step_playback_speed, FieldForm.DROPDOWN, R.string.step_playback_speed_description, 26)
@DropdownFieldOptionsId(R.array.step_playback_speed)
var stepPlaybackSpeed: Int = 1;
fun getPlaybackSpeedStep(): Double {
return when(stepPlaybackSpeed) {
0 -> 0.05
1 -> 0.1
2 -> 0.25
else -> 0.1;
}
}
fun getPlaybackSpeeds(): List<Double> {
val playbackSpeeds = mutableListOf<Double>();
playbackSpeeds.add(1.0);
val minSpeed = when(minimumPlaybackSpeed) {
0 -> 0.25
1 -> 0.5
2 -> 1.0
else -> 0.25
}
val maxSpeed = when(maximumPlaybackSpeed) {
0 -> 2.0
1 -> 2.25
2 -> 3.0
3 -> 4.0
4 -> 5.0
else -> 2.25;
}
var testSpeed = 1.0;
while(testSpeed > minSpeed) {
val nextSpeed = (testSpeed - 0.25) as Double;
testSpeed = Math.max(nextSpeed, minSpeed);
playbackSpeeds.add(testSpeed);
}
testSpeed = 1.0;
while(testSpeed < maxSpeed) {
val nextSpeed = (testSpeed + if(testSpeed < 2) 0.25 else 1.0) as Double;
testSpeed = Math.min(nextSpeed, maxSpeed);
playbackSpeeds.add(testSpeed);
}
playbackSpeeds.sort();
return playbackSpeeds;
}
} }
@FormField(R.string.comments, "group", R.string.comments_description, 6) @FormField(R.string.comments, "group", R.string.comments_description, 6)

View file

@ -7,9 +7,7 @@ import android.app.PendingIntent.getBroadcast
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageInstaller import android.content.pm.PackageInstaller
import android.content.pm.PackageInstaller.SessionParams.USER_ACTION_NOT_REQUIRED
import android.graphics.drawable.Animatable import android.graphics.drawable.Animatable
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
@ -157,9 +155,6 @@ class AutoUpdateDialog(context: Context?) : AlertDialog(context) {
val packageInstaller: PackageInstaller = context.packageManager.packageInstaller; val packageInstaller: PackageInstaller = context.packageManager.packageInstaller;
val params = PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL); val params = PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
params.setRequireUserAction(USER_ACTION_NOT_REQUIRED)
}
val sessionId = packageInstaller.createSession(params); val sessionId = packageInstaller.createSession(params);
session = packageInstaller.openSession(sessionId) session = packageInstaller.openSession(sessionId)

View file

@ -191,7 +191,7 @@ class SubscriptionsFeedFragment : MainFragment() {
private var _bypassRateLimit = false; private var _bypassRateLimit = false;
private val _lastExceptions: List<Throwable>? = null; private val _lastExceptions: List<Throwable>? = null;
private val _taskGetPager = TaskHandler<Boolean, IPager<IPlatformContent>>({StateApp.instance.scope}, { withRefresh -> private val _taskGetPager = TaskHandler<Boolean, IPager<IPlatformContent>>({fragment.lifecycleScope}, { withRefresh ->
val group = subGroup; val group = subGroup;
if(!_bypassRateLimit) { if(!_bypassRateLimit) {
val subRequestCounts = StateSubscriptions.instance.getSubscriptionRequestCount(group); val subRequestCounts = StateSubscriptions.instance.getSubscriptionRequestCount(group);
@ -202,7 +202,7 @@ class SubscriptionsFeedFragment : MainFragment() {
throw RateLimitException(rateLimitPlugins.map { it.key.id }); throw RateLimitException(rateLimitPlugins.map { it.key.id });
} }
_bypassRateLimit = false; _bypassRateLimit = false;
val resp = StateSubscriptions.instance.getGlobalSubscriptionFeed(StateApp.instance.scope, withRefresh, group); val resp = StateSubscriptions.instance.getGlobalSubscriptionFeed(fragment.lifecycleScope, withRefresh, group);
val feed = StateSubscriptions.instance.getFeed(group?.id); val feed = StateSubscriptions.instance.getFeed(group?.id);
val currentExs = feed?.exceptions ?: listOf(); val currentExs = feed?.exceptions ?: listOf();

View file

@ -2149,23 +2149,40 @@ class VideoDetailView : ConstraintLayout {
val canSetSpeed = !_isCasting || StateCasting.instance.activeDevice?.canSetSpeed == true val canSetSpeed = !_isCasting || StateCasting.instance.activeDevice?.canSetSpeed == true
val currentPlaybackRate = if (_isCasting) StateCasting.instance.activeDevice?.speed else _player.getPlaybackRate() val currentPlaybackRate = if (_isCasting) StateCasting.instance.activeDevice?.speed else _player.getPlaybackRate()
val qualityPlaybackSpeedTitle = if (canSetSpeed) SlideUpMenuTitle(this.context).apply { setTitle(context.getString(R.string.playback_rate) + " (${String.format("%.2f", currentPlaybackRate)})"); } else null;
_overlay_quality_selector = SlideUpMenuOverlay(this.context, _overlay_quality_container, context.getString( _overlay_quality_selector = SlideUpMenuOverlay(this.context, _overlay_quality_container, context.getString(
R.string.quality), null, true, R.string.quality), null, true,
if (canSetSpeed) SlideUpMenuTitle(this.context).apply { setTitle(context.getString(R.string.playback_rate)) } else null, qualityPlaybackSpeedTitle,
if (canSetSpeed) SlideUpMenuButtonList(this.context, null, "playback_rate").apply { if (canSetSpeed) SlideUpMenuButtonList(this.context, null, "playback_rate").apply {
setButtons(listOf("0.25", "0.5", "0.75", "1.0", "1.25", "1.5", "1.75", "2.0", "2.25"), currentPlaybackRate!!.toString()); val playbackSpeeds = Settings.instance.playback.getPlaybackSpeeds();
val format = if(playbackSpeeds.size < 20) "%.2f" else "%.1f";
val playbackLabels = playbackSpeeds.map { String.format(format, it) }.toMutableList();
playbackLabels.add("+");
playbackLabels.add(0, "-");
setButtons(playbackLabels, String.format(format, currentPlaybackRate));
onClick.subscribe { v -> onClick.subscribe { v ->
val currentPlaybackSpeed = if (_isCasting) StateCasting.instance.activeDevice?.speed else _player.getPlaybackRate();
var playbackSpeedString = v;
val stepSpeed = Settings.instance.playback.getPlaybackSpeedStep();
if(v == "+")
playbackSpeedString = String.format("%.2f", (currentPlaybackSpeed?.toDouble() ?: 1.0) + stepSpeed).toString();
else if(v == "-")
playbackSpeedString = String.format("%.2f", (currentPlaybackSpeed?.toDouble() ?: 1.0) - stepSpeed).toString();
val newPlaybackSpeed = playbackSpeedString.toDouble();
if (_isCasting) { if (_isCasting) {
val ad = StateCasting.instance.activeDevice ?: return@subscribe val ad = StateCasting.instance.activeDevice ?: return@subscribe
if (!ad.canSetSpeed) { if (!ad.canSetSpeed) {
return@subscribe return@subscribe
} }
ad.changeSpeed(v.toDouble()) qualityPlaybackSpeedTitle?.setTitle(context.getString(R.string.playback_rate) + " (${String.format("%.2f", newPlaybackSpeed)})");
setSelected(v); ad.changeSpeed(newPlaybackSpeed)
setSelected(playbackSpeedString);
} else { } else {
_player.setPlaybackRate(v.toFloat()); qualityPlaybackSpeedTitle?.setTitle(context.getString(R.string.playback_rate) + " (${String.format("%.2f", newPlaybackSpeed)})");
setSelected(v); _player.setPlaybackRate(playbackSpeedString.toFloat());
setSelected(playbackSpeedString);
} }
}; };
} else null, } else null,

View file

@ -31,7 +31,7 @@ class SlideUpMenuButtonList : LinearLayout {
fun setButtons(texts: List<String>, activeText: String? = null) { fun setButtons(texts: List<String>, activeText: String? = null) {
_root.removeAllViews(); _root.removeAllViews();
val marginLeft = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 3.0f, resources.displayMetrics).toInt(); val marginLeft = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1.5f, resources.displayMetrics).toInt();
val marginRight = marginLeft; val marginRight = marginLeft;
buttons.clear(); buttons.clear();

View file

@ -5,7 +5,7 @@
android:layout_marginTop="10dp" android:layout_marginTop="10dp"
android:id="@+id/root" android:id="@+id/root"
android:orientation="horizontal" android:orientation="horizontal"
android:paddingStart="6dp" android:paddingStart="0dp"
android:paddingEnd="6dp"> android:paddingEnd="0dp">
</LinearLayout> </LinearLayout>

View file

@ -427,6 +427,12 @@
<string name="delete_watchlist_on_finish">Delete from WatchLater when watched</string> <string name="delete_watchlist_on_finish">Delete from WatchLater when watched</string>
<string name="delete_watchlist_on_finish_description">After you leave a video that you mostly watched, it will be removed from watch later.</string> <string name="delete_watchlist_on_finish_description">After you leave a video that you mostly watched, it will be removed from watch later.</string>
<string name="seek_offset">Seek duration</string> <string name="seek_offset">Seek duration</string>
<string name="min_playback_speed">Minimum Playback Speed</string>
<string name="min_playback_speed_description">Minimum Available Speed</string>
<string name="max_playback_speed">Maximum Playback Speed</string>
<string name="max_playback_speed_description">Maximum Available Speed</string>
<string name="step_playback_speed">Playback Speed Step Size</string>
<string name="step_playback_speed_description">The step size of playback speeds, may not affect higher playback speeds.</string>
<string name="seek_offset_description">Fast-Forward / Fast-Rewind duration</string> <string name="seek_offset_description">Fast-Forward / Fast-Rewind duration</string>
<string name="background_switch_audio">Switch to Audio in Background</string> <string name="background_switch_audio">Switch to Audio in Background</string>
<string name="subscription_group_menu">Groups</string> <string name="subscription_group_menu">Groups</string>
@ -1091,6 +1097,23 @@
<item>30 seconds</item> <item>30 seconds</item>
<item>60 seconds</item> <item>60 seconds</item>
</string-array> </string-array>
<string-array name="max_playback_speed">
<item>2.0</item>
<item>2.25</item>
<item>3.0</item>
<item>4.0</item>
<item>5.0</item>
</string-array>
<string-array name="min_playback_speed">
<item>0.25</item>
<item>0.5</item>
<item>1.0</item>
</string-array>
<string-array name="step_playback_speed">
<item>0.05</item>
<item>0.1</item>
<item>0.25</item>
</string-array>
<string-array name="rotation_zone"> <string-array name="rotation_zone">
<item>15</item> <item>15</item>
<item>30</item> <item>30</item>