feat(YouTube - Playback speed): Add "Restore old playback speed menu" option (#5552)

This commit is contained in:
LisoUseInAIKyrios
2025-07-28 20:44:18 +02:00
committed by GitHub
parent 0579a9f760
commit e9e4cf39b6
11 changed files with 216 additions and 45 deletions

View File

@@ -16,7 +16,7 @@ import java.util.Objects;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.youtube.patches.components.ReturnYouTubeDislikeFilterPatch;
import app.revanced.extension.youtube.patches.components.ReturnYouTubeDislikeFilter;
import app.revanced.extension.youtube.returnyoutubedislike.ReturnYouTubeDislike;
import app.revanced.extension.youtube.settings.Settings;
import app.revanced.extension.youtube.shared.PlayerType;
@@ -55,7 +55,7 @@ public class ReturnYouTubeDislikePatch {
private static volatile ReturnYouTubeDislike lastLithoShortsVideoData;
/**
* Because litho Shorts spans are created offscreen after {@link ReturnYouTubeDislikeFilterPatch}
* Because litho Shorts spans are created offscreen after {@link ReturnYouTubeDislikeFilter}
* detects the video ids, but the current Short can arbitrarily reload the same span,
* then use the {@link #lastLithoShortsVideoData} if this value is greater than zero.
*/

View File

@@ -3,9 +3,9 @@ package app.revanced.extension.youtube.patches.components;
import app.revanced.extension.youtube.settings.Settings;
@SuppressWarnings("unused")
public final class HideInfoCardsFilterPatch extends Filter {
public final class HideInfoCardsFilter extends Filter {
public HideInfoCardsFilterPatch() {
public HideInfoCardsFilter() {
addIdentifierCallbacks(
new StringFilterGroup(
Settings.HIDE_INFO_CARDS,

View File

@@ -8,27 +8,44 @@ import app.revanced.extension.youtube.settings.Settings;
/**
* Abuse LithoFilter for {@link CustomPlaybackSpeedPatch}.
*/
public final class PlaybackSpeedMenuFilterPatch extends Filter {
public final class PlaybackSpeedMenuFilter extends Filter {
/**
* Old litho based speed selection menu.
*/
public static volatile boolean isOldPlaybackSpeedMenuVisible;
/**
* 0.05x speed selection menu.
*/
public static volatile boolean isPlaybackRateSelectorMenuVisible;
public PlaybackSpeedMenuFilterPatch() {
private final StringFilterGroup oldPlaybackMenuGroup;
public PlaybackSpeedMenuFilter() {
// 0.05x litho speed menu.
var playbackRateSelectorGroup = new StringFilterGroup(
Settings.CUSTOM_SPEED_MENU,
"playback_rate_selector_menu_sheet.eml-js"
);
// Old litho based speed menu.
oldPlaybackMenuGroup = new StringFilterGroup(
Settings.CUSTOM_SPEED_MENU,
"playback_speed_sheet_content.eml-js");
addPathCallbacks(playbackRateSelectorGroup);
}
@Override
boolean isFiltered(@Nullable String identifier, String path, byte[] protobufBufferArray,
StringFilterGroup matchedGroup, FilterContentType contentType, int contentIndex) {
isPlaybackRateSelectorMenuVisible = true;
if (matchedGroup == oldPlaybackMenuGroup) {
isOldPlaybackSpeedMenuVisible = true;
} else {
isPlaybackRateSelectorMenuVisible = true;
}
return false;
}

View File

@@ -26,7 +26,7 @@ import app.revanced.extension.youtube.TrieSearch;
*
* Once a way to asynchronously update litho text is found, this strategy will no longer be needed.
*/
public final class ReturnYouTubeDislikeFilterPatch extends Filter {
public final class ReturnYouTubeDislikeFilter extends Filter {
/**
* Last unique video id's loaded. Value is ignored and Map is treated as a Set.
@@ -67,7 +67,7 @@ public final class ReturnYouTubeDislikeFilterPatch extends Filter {
private final ByteArrayFilterGroupList videoIdFilterGroup = new ByteArrayFilterGroupList();
public ReturnYouTubeDislikeFilterPatch() {
public ReturnYouTubeDislikeFilter() {
// When a new Short is opened, the like buttons always seem to load before the dislike.
// But if swiping back to a previous video and liking/disliking, then only that single button reloads.
// So must check for both buttons.

View File

@@ -23,7 +23,6 @@ import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.Window;
import android.view.WindowManager;
import android.view.animation.Animation;
@@ -42,7 +41,7 @@ import java.util.function.Function;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.youtube.patches.VideoInformation;
import app.revanced.extension.youtube.patches.components.PlaybackSpeedMenuFilterPatch;
import app.revanced.extension.youtube.patches.components.PlaybackSpeedMenuFilter;
import app.revanced.extension.youtube.settings.Settings;
import app.revanced.extension.youtube.shared.PlayerType;
import kotlin.Unit;
@@ -80,6 +79,16 @@ public class CustomPlaybackSpeedPatch {
*/
public static final float[] customPlaybackSpeeds;
/**
* Minimum and maximum custom playback speeds of {@link #customPlaybackSpeeds}.
*/
private static final float customPlaybackSpeedsMin, customPlaybackSpeedsMax;
/**
* The last time the old playback menu was forcefully called.
*/
private static volatile long lastTimeOldPlaybackMenuInvoked;
/**
* Formats speeds to UI strings.
*/
@@ -90,11 +99,6 @@ public class CustomPlaybackSpeedPatch {
*/
private static WeakReference<Dialog> currentDialog = new WeakReference<>(null);
/**
* Minimum and maximum custom playback speeds of {@link #customPlaybackSpeeds}.
*/
private static final float customPlaybackSpeedsMin, customPlaybackSpeedsMax;
static {
// Cap at 2 decimals (rounds automatically).
speedFormatter.setMaximumFractionDigits(2);
@@ -174,25 +178,33 @@ public class CustomPlaybackSpeedPatch {
public static void onFlyoutMenuCreate(RecyclerView recyclerView) {
recyclerView.getViewTreeObserver().addOnDrawListener(() -> {
try {
if (PlaybackSpeedMenuFilterPatch.isPlaybackRateSelectorMenuVisible) {
if (hideLithoMenuAndShowCustomSpeedMenu(recyclerView, 5)) {
PlaybackSpeedMenuFilterPatch.isPlaybackRateSelectorMenuVisible = false;
if (PlaybackSpeedMenuFilter.isPlaybackRateSelectorMenuVisible) {
if (hideLithoMenuAndShowSpeedMenu(recyclerView, 5)) {
PlaybackSpeedMenuFilter.isPlaybackRateSelectorMenuVisible = false;
}
}
} catch (Exception ex) {
Logger.printException(() -> "onFlyoutMenuCreate failure", ex);
Logger.printException(() -> "isPlaybackRateSelectorMenuVisible failure", ex);
}
try {
if (PlaybackSpeedMenuFilter.isOldPlaybackSpeedMenuVisible) {
if (hideLithoMenuAndShowSpeedMenu(recyclerView, 8)) {
PlaybackSpeedMenuFilter.isOldPlaybackSpeedMenuVisible = false;
}
}
} catch (Exception ex) {
Logger.printException(() -> "isOldPlaybackSpeedMenuVisible failure", ex);
}
});
}
@SuppressWarnings("SameParameterValue")
private static boolean hideLithoMenuAndShowCustomSpeedMenu(RecyclerView recyclerView, int expectedChildCount) {
private static boolean hideLithoMenuAndShowSpeedMenu(RecyclerView recyclerView, int expectedChildCount) {
if (recyclerView.getChildCount() == 0) {
return false;
}
View firstChild = recyclerView.getChildAt(0);
if (!(firstChild instanceof ViewGroup playbackSpeedParentView)) {
if (!(recyclerView.getChildAt(0) instanceof ViewGroup playbackSpeedParentView)) {
return false;
}
@@ -200,33 +212,49 @@ public class CustomPlaybackSpeedPatch {
return false;
}
ViewParent parentView3rd = Utils.getParentView(recyclerView, 3);
if (!(parentView3rd instanceof ViewGroup)) {
return true;
if (!(Utils.getParentView(recyclerView, 3) instanceof ViewGroup parentView3rd)) {
return false;
}
ViewParent parentView4th = parentView3rd.getParent();
if (!(parentView4th instanceof ViewGroup)) {
return true;
if (!(parentView3rd.getParent() instanceof ViewGroup parentView4th)) {
return false;
}
// Dismiss View [R.id.touch_outside] is the 1st ChildView of the 4th ParentView.
// This only shows in phone layout.
final var touchInsidedView = ((ViewGroup) parentView4th).getChildAt(0);
var touchInsidedView = parentView4th.getChildAt(0);
touchInsidedView.setSoundEffectsEnabled(false);
touchInsidedView.performClick();
// In tablet layout there is no Dismiss View, instead we just hide all two parent views.
((ViewGroup) parentView3rd).setVisibility(View.GONE);
((ViewGroup) parentView4th).setVisibility(View.GONE);
parentView3rd.setVisibility(View.GONE);
parentView4th.setVisibility(View.GONE);
// Close the litho speed menu and show the modern custom speed dialog.
showModernCustomPlaybackSpeedDialog(recyclerView.getContext());
Logger.printDebug(() -> "Modern playback speed dialog shown");
// Close the litho speed menu and show the custom speeds.
if (Settings.RESTORE_OLD_SPEED_MENU.get()) {
showOldPlaybackSpeedMenu();
Logger.printDebug(() -> "Old playback speed dialog shown");
} else {
showModernCustomPlaybackSpeedDialog(recyclerView.getContext());
Logger.printDebug(() -> "Modern playback speed dialog shown");
}
return true;
}
public static void showOldPlaybackSpeedMenu() {
// This method is sometimes used multiple times.
// To prevent this, ignore method reuse within 1 second.
final long now = System.currentTimeMillis();
if (now - lastTimeOldPlaybackMenuInvoked < 1000) {
Logger.printDebug(() -> "Ignoring call to showOldPlaybackSpeedMenu");
return;
}
lastTimeOldPlaybackMenuInvoked = now;
// Rest of the implementation added by patch.
}
/**
* Displays a modern custom dialog for adjusting video playback speed.
* <p>

View File

@@ -68,8 +68,9 @@ public class Settings extends BaseSettings {
public static final BooleanSetting REMEMBER_PLAYBACK_SPEED_LAST_SELECTED = new BooleanSetting("revanced_remember_playback_speed_last_selected", FALSE);
public static final BooleanSetting REMEMBER_PLAYBACK_SPEED_LAST_SELECTED_TOAST = new BooleanSetting("revanced_remember_playback_speed_last_selected_toast", TRUE, false,
parent(REMEMBER_PLAYBACK_SPEED_LAST_SELECTED));
public static final BooleanSetting CUSTOM_SPEED_MENU = new BooleanSetting("revanced_custom_speed_menu", TRUE);
public static final FloatSetting PLAYBACK_SPEED_DEFAULT = new FloatSetting("revanced_playback_speed_default", -2.0f);
public static final BooleanSetting CUSTOM_SPEED_MENU = new BooleanSetting("revanced_custom_speed_menu", TRUE);
public static final BooleanSetting RESTORE_OLD_SPEED_MENU = new BooleanSetting("revanced_restore_old_speed_menu", FALSE, parent(CUSTOM_SPEED_MENU));
public static final StringSetting CUSTOM_PLAYBACK_SPEEDS = new StringSetting("revanced_custom_playback_speeds",
"0.25\n0.5\n0.75\n1.0\n1.25\n1.5\n1.75\n2.0\n2.5\n3.0\n4.0\n5.0\n6.0\n7.0\n8.0", true);