Skip to content
This repository has been archived by the owner on Oct 26, 2024. It is now read-only.

fix(YouTube - Playback speed): Restore old playback speed menu #728

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions app/src/main/java/app/revanced/integrations/shared/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -317,9 +317,10 @@ public static ViewParent getParentView(@NonNull View view, int nthParent) {
return parent;
}

final int currentDepthLog = currentDepth;
final int finalDepthLog = currentDepth;
final ViewParent finalParent = parent;
Logger.printDebug(() -> "Could not find parent view of depth: " + nthParent
+ " and instead found at: " + currentDepthLog + " view: " + view);
+ " and instead found at: " + finalDepthLog + " view: " + finalParent);
return null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,48 @@
import androidx.annotation.Nullable;

import app.revanced.integrations.youtube.patches.playback.speed.CustomPlaybackSpeedPatch;
import app.revanced.integrations.youtube.settings.Settings;

/**
* Abuse LithoFilter for {@link CustomPlaybackSpeedPatch}.
*/
public final class PlaybackSpeedMenuFilterPatch extends Filter {
// Must be volatile or synchronized, as litho filtering runs off main thread and this field is then access from the main thread.
public static volatile boolean isPlaybackSpeedMenuVisible;

/**
* Old litho based speed selection menu.
*/
public static volatile boolean isOldPlaybackSpeedMenuVisible;

/**
* 0.05x speed selection menu.
*/
public static volatile boolean isPlaybackRateSelectorMenuVisible;

private final StringFilterGroup oldPlaybackMenuGroup;

public PlaybackSpeedMenuFilterPatch() {
addPathCallbacks(new StringFilterGroup(
null,
"playback_speed_sheet_content.eml-js"
));
// 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, oldPlaybackMenuGroup);
}

@Override
boolean isFiltered(@Nullable String identifier, String path, byte[] protobufBufferArray,
StringFilterGroup matchedGroup, FilterContentType contentType, int contentIndex) {
isPlaybackSpeedMenuVisible = true;
if (matchedGroup == oldPlaybackMenuGroup) {
isOldPlaybackSpeedMenuVisible = true;
} else {
isPlaybackRateSelectorMenuVisible = true;
}

return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,18 +59,24 @@ private static void loadCustomSpeeds() {
if (speedStrings.length == 0) {
throw new IllegalArgumentException();
}

customPlaybackSpeeds = new float[speedStrings.length];
for (int i = 0, length = speedStrings.length; i < length; i++) {
final float speed = Float.parseFloat(speedStrings[i]);
if (speed <= 0 || arrayContains(customPlaybackSpeeds, speed)) {

int i = 0;
for (String speedString : speedStrings) {
final float speedFloat = Float.parseFloat(speedString);
if (speedFloat <= 0 || arrayContains(customPlaybackSpeeds, speedFloat)) {
throw new IllegalArgumentException();
}
if (speed >= MAXIMUM_PLAYBACK_SPEED) {

if (speedFloat >= MAXIMUM_PLAYBACK_SPEED) {
resetCustomSpeeds(str("revanced_custom_playback_speeds_invalid", MAXIMUM_PLAYBACK_SPEED));
loadCustomSpeeds();
return;
}
customPlaybackSpeeds[i] = speed;

customPlaybackSpeeds[i] = speedFloat;
i++;
}
} catch (Exception ex) {
Logger.printInfo(() -> "parse error", ex);
Expand All @@ -89,10 +95,12 @@ private static boolean arrayContains(float[] array, float value) {
/**
* Initialize a settings preference list with the available playback speeds.
*/
@SuppressWarnings("deprecation")
public static void initializeListPreference(ListPreference preference) {
if (preferenceListEntries == null) {
preferenceListEntries = new String[customPlaybackSpeeds.length];
preferenceListEntryValues = new String[customPlaybackSpeeds.length];

int i = 0;
for (float speed : customPlaybackSpeeds) {
String speedString = String.valueOf(speed);
Expand All @@ -101,6 +109,7 @@ public static void initializeListPreference(ListPreference preference) {
i++;
}
}

preference.setEntries(preferenceListEntries);
preference.setEntryValues(preferenceListEntryValues);
}
Expand All @@ -111,52 +120,67 @@ public static void initializeListPreference(ListPreference preference) {
public static void onFlyoutMenuCreate(RecyclerView recyclerView) {
recyclerView.getViewTreeObserver().addOnDrawListener(() -> {
try {
// For some reason, the custom playback speed flyout panel is activated when the user opens the share panel. (A/B tests)
// Check the child count of playback speed flyout panel to prevent this issue.
// Child count of playback speed flyout panel is always 8.
if (!PlaybackSpeedMenuFilterPatch.isPlaybackSpeedMenuVisible || recyclerView.getChildCount() == 0) {
if (PlaybackSpeedMenuFilterPatch.isPlaybackRateSelectorMenuVisible) {
if (hideLithoMenuAndShowOldSpeedMenu(recyclerView, 5)) {
PlaybackSpeedMenuFilterPatch.isPlaybackRateSelectorMenuVisible = false;
}
return;
}
} catch (Exception ex) {
Logger.printException(() -> "isPlaybackRateSelectorMenuVisible failure", ex);
}

View firstChild = recyclerView.getChildAt(0);
if (!(firstChild instanceof ViewGroup)) {
return;
}
ViewGroup PlaybackSpeedParentView = (ViewGroup) firstChild;
if (PlaybackSpeedParentView.getChildCount() != 8) {
return;
try {
if (PlaybackSpeedMenuFilterPatch.isOldPlaybackSpeedMenuVisible) {
if (hideLithoMenuAndShowOldSpeedMenu(recyclerView, 8)) {
PlaybackSpeedMenuFilterPatch.isOldPlaybackSpeedMenuVisible = false;
}
}
} catch (Exception ex) {
Logger.printException(() -> "isOldPlaybackSpeedMenuVisible failure", ex);
}
});
}

PlaybackSpeedMenuFilterPatch.isPlaybackSpeedMenuVisible = false;

ViewParent parentView3rd = Utils.getParentView(recyclerView, 3);
if (!(parentView3rd instanceof ViewGroup)) {
return;
}
ViewParent parentView4th = parentView3rd.getParent();
if (!(parentView4th instanceof ViewGroup)) {
return;
}
private static boolean hideLithoMenuAndShowOldSpeedMenu(RecyclerView recyclerView, int expectedChildCount) {
if (recyclerView.getChildCount() == 0) {
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);
touchInsidedView.setSoundEffectsEnabled(false);
touchInsidedView.performClick();
View firstChild = recyclerView.getChildAt(0);
if (!(firstChild instanceof ViewGroup)) {
return false;
}

// 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);
ViewGroup PlaybackSpeedParentView = (ViewGroup) firstChild;
if (PlaybackSpeedParentView.getChildCount() != expectedChildCount) {
return false;
}

// This works without issues for both tablet and phone layouts,
// So no code is needed to check whether the current device is a tablet or phone.
ViewParent parentView3rd = Utils.getParentView(recyclerView, 3);
if (!(parentView3rd instanceof ViewGroup)) {
return true;
}

// Close the new Playback speed menu and show the old one.
showOldPlaybackSpeedMenu();
} catch (Exception ex) {
Logger.printException(() -> "onFlyoutMenuCreate failure", ex);
ViewParent parentView4th = parentView3rd.getParent();
if (!(parentView4th instanceof ViewGroup)) {
return true;
}
});

// 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);
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);

// Close the litho speed menu and show the old one.
showOldPlaybackSpeedMenu();

return true;
}

public static void showOldPlaybackSpeedMenu() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,31 @@ public static void newVideoStarted(VideoInformation.PlaybackController ignoredPl
*/
public static void userSelectedPlaybackSpeed(float playbackSpeed) {
if (Settings.REMEMBER_PLAYBACK_SPEED_LAST_SELECTED.get()) {
Settings.PLAYBACK_SPEED_DEFAULT.save(playbackSpeed);
// With the 0.05x menu, if the speed is set by integrations to higher than 2.0x
// then the menu will allow increasing without bounds but the max speed is
// still capped to under 8.0x.
playbackSpeed = Math.min(playbackSpeed, CustomPlaybackSpeedPatch.MAXIMUM_PLAYBACK_SPEED - 0.05f);

// Prevent toast spamming if using the 0.05x adjustments.
// Show exactly one toast after the user stops interacting with the speed menu.
final long now = System.currentTimeMillis();
lastTimeSpeedChanged = now;

final float finalPlaybackSpeed = playbackSpeed;
Utils.runOnMainThreadDelayed(() -> {
if (lastTimeSpeedChanged == now) {
Utils.showToastLong(str("revanced_remember_playback_speed_toast", (playbackSpeed + "x")));
} // else, the user made additional speed adjustments and this call is outdated.
if (lastTimeSpeedChanged != now) {
// The user made additional speed adjustments and this call is outdated.
return;
}

if (Settings.PLAYBACK_SPEED_DEFAULT.get() == finalPlaybackSpeed) {
// User changed to a different speed and immediately changed back.
// Or the user is going past 8.0x in the glitched out 0.05x menu.
return;
}
Settings.PLAYBACK_SPEED_DEFAULT.save(finalPlaybackSpeed);

Utils.showToastLong(str("revanced_remember_playback_speed_toast", (finalPlaybackSpeed + "x")));
}, TOAST_DELAY_MILLISECONDS);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,13 @@ public class Settings extends BaseSettings {
public static final BooleanSetting REMEMBER_VIDEO_QUALITY_LAST_SELECTED = new BooleanSetting("revanced_remember_video_quality_last_selected", FALSE);
public static final IntegerSetting VIDEO_QUALITY_DEFAULT_WIFI = new IntegerSetting("revanced_video_quality_default_wifi", -2);
public static final IntegerSetting VIDEO_QUALITY_DEFAULT_MOBILE = new IntegerSetting("revanced_video_quality_default_mobile", -2);
// Speed
public static final BooleanSetting REMEMBER_PLAYBACK_SPEED_LAST_SELECTED = new BooleanSetting("revanced_remember_playback_speed_last_selected", FALSE);
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", 1.0f);
public static final StringSetting CUSTOM_PLAYBACK_SPEEDS = new StringSetting("revanced_custom_playback_speeds",
"0.25\n0.5\n0.75\n0.9\n0.95\n1.0\n1.05\n1.1\n1.25\n1.5\n1.75\n2.0\n3.0\n4.0\n5.0", true);

@Deprecated // Patch is obsolete and no longer works with 19.09+
public static final BooleanSetting HDR_AUTO_BRIGHTNESS = new BooleanSetting("revanced_hdr_auto_brightness", TRUE);

Expand Down
Loading