diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/ReturnYouTubeDislikePatch.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/ReturnYouTubeDislikePatch.java index bb351b66b..dbd1ad8d4 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/ReturnYouTubeDislikePatch.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/ReturnYouTubeDislikePatch.java @@ -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. */ diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/HideInfoCardsFilterPatch.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/HideInfoCardsFilter.java similarity index 78% rename from extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/HideInfoCardsFilterPatch.java rename to extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/HideInfoCardsFilter.java index ce92b592e..3c4c33d16 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/HideInfoCardsFilterPatch.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/HideInfoCardsFilter.java @@ -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, diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/PlaybackSpeedMenuFilterPatch.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/PlaybackSpeedMenuFilter.java similarity index 58% rename from extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/PlaybackSpeedMenuFilterPatch.java rename to extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/PlaybackSpeedMenuFilter.java index 531578a8b..78ce3595d 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/PlaybackSpeedMenuFilterPatch.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/PlaybackSpeedMenuFilter.java @@ -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; } diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/ReturnYouTubeDislikeFilterPatch.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/ReturnYouTubeDislikeFilter.java similarity index 97% rename from extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/ReturnYouTubeDislikeFilterPatch.java rename to extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/ReturnYouTubeDislikeFilter.java index 0d1504e40..2164e4331 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/ReturnYouTubeDislikeFilterPatch.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/ReturnYouTubeDislikeFilter.java @@ -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. diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/playback/speed/CustomPlaybackSpeedPatch.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/playback/speed/CustomPlaybackSpeedPatch.java index da37aa426..88eae4a0d 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/playback/speed/CustomPlaybackSpeedPatch.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/playback/speed/CustomPlaybackSpeedPatch.java @@ -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 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. *

diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/Settings.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/Settings.java index edeb7ca0b..2f51b1347 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/Settings.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/Settings.java @@ -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); diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/HideInfoCardsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/HideInfoCardsPatch.kt index 0a3d7cdbf..cac5c169b 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/HideInfoCardsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/HideInfoCardsPatch.kt @@ -99,7 +99,7 @@ val hideInfoCardsPatch = bytecodePatch( ) // Info cards can also appear as Litho components. - val filterClassDescriptor = "Lapp/revanced/extension/youtube/patches/components/HideInfoCardsFilterPatch;" + val filterClassDescriptor = "Lapp/revanced/extension/youtube/patches/components/HideInfoCardsFilter;" addLithoFilter(filterClassDescriptor) } } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/ReturnYouTubeDislikePatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/ReturnYouTubeDislikePatch.kt index 200e652f3..b65b8f6c4 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/ReturnYouTubeDislikePatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/ReturnYouTubeDislikePatch.kt @@ -43,7 +43,7 @@ private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/ReturnYouTubeDislikePatch;" private const val FILTER_CLASS_DESCRIPTOR = - "Lapp/revanced/extension/youtube/patches/components/ReturnYouTubeDislikeFilterPatch;" + "Lapp/revanced/extension/youtube/patches/components/ReturnYouTubeDislikeFilter;" val returnYouTubeDislikePatch = bytecodePatch( name = "Return YouTube Dislike", diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/CustomPlaybackSpeedPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/CustomPlaybackSpeedPatch.kt index e6732fb09..b46375571 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/CustomPlaybackSpeedPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/CustomPlaybackSpeedPatch.kt @@ -1,11 +1,19 @@ package app.revanced.patches.youtube.video.speed.custom +import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.addInstructions +import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels import app.revanced.patcher.extensions.InstructionExtensions.getInstruction +import app.revanced.patcher.extensions.InstructionExtensions.instructions import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.patch.bytecodePatch +import app.revanced.patcher.patch.resourcePatch +import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable import app.revanced.patches.all.misc.resources.addResources import app.revanced.patches.all.misc.resources.addResourcesPatch +import app.revanced.patches.shared.misc.mapping.get +import app.revanced.patches.shared.misc.mapping.resourceMappingPatch +import app.revanced.patches.shared.misc.mapping.resourceMappings import app.revanced.patches.shared.misc.settings.preference.InputType import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.shared.misc.settings.preference.TextPreference @@ -18,18 +26,34 @@ import app.revanced.patches.youtube.misc.recyclerviewtree.hook.addRecyclerViewTr import app.revanced.patches.youtube.misc.recyclerviewtree.hook.recyclerViewTreeHookPatch import app.revanced.patches.youtube.misc.settings.settingsPatch import app.revanced.patches.youtube.video.speed.settingsMenuVideoSpeedGroup +import app.revanced.util.getReference import app.revanced.util.indexOfFirstInstructionOrThrow import app.revanced.util.indexOfFirstLiteralInstruction import app.revanced.util.indexOfFirstLiteralInstructionOrThrow +import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.iface.instruction.NarrowLiteralInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction +import com.android.tools.smali.dexlib2.iface.reference.FieldReference +import com.android.tools.smali.dexlib2.iface.reference.MethodReference +import com.android.tools.smali.dexlib2.immutable.ImmutableField private const val FILTER_CLASS_DESCRIPTOR = - "Lapp/revanced/extension/youtube/patches/components/PlaybackSpeedMenuFilterPatch;" + "Lapp/revanced/extension/youtube/patches/components/PlaybackSpeedMenuFilter;" -private const val EXTENSION_CLASS_DESCRIPTOR = +internal const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/playback/speed/CustomPlaybackSpeedPatch;" +internal var speedUnavailableId = -1L + private set + +private val customPlaybackSpeedResourcePatch = resourcePatch { + dependsOn(resourceMappingPatch) + + execute { + speedUnavailableId = resourceMappings["string", "varispeed_unavailable_message"] + } +} + internal val customPlaybackSpeedPatch = bytecodePatch( description = "Adds custom playback speed options.", ) { @@ -39,7 +63,8 @@ internal val customPlaybackSpeedPatch = bytecodePatch( addResourcesPatch, lithoFilterPatch, versionCheckPatch, - recyclerViewTreeHookPatch + recyclerViewTreeHookPatch, + customPlaybackSpeedResourcePatch ) execute { @@ -48,6 +73,7 @@ internal val customPlaybackSpeedPatch = bytecodePatch( settingsMenuVideoSpeedGroup.addAll( listOf( SwitchPreference("revanced_custom_speed_menu"), + SwitchPreference("revanced_restore_old_speed_menu"), TextPreference( "revanced_custom_playback_speeds", inputType = InputType.TEXT_MULTI_LINE @@ -77,15 +103,88 @@ internal val customPlaybackSpeedPatch = bytecodePatch( replaceInstruction(limitMaxIndex, "const/high16 v$limitMaxRegister, 8.0f") } + + // Replace the speeds float array with custom speeds. + // These speeds are used if the speed menu is immediately opened after a video is opened. + speedArrayGeneratorFingerprint.method.apply { + val sizeCallIndex = indexOfFirstInstructionOrThrow { getReference()?.name == "size" } + val sizeCallResultRegister = getInstruction(sizeCallIndex + 1).registerA + + replaceInstruction(sizeCallIndex + 1, "const/4 v$sizeCallResultRegister, 0x0") + + val arrayLengthConstIndex = indexOfFirstLiteralInstructionOrThrow(7) + val arrayLengthConstDestination = getInstruction(arrayLengthConstIndex).registerA + val playbackSpeedsArrayType = "$EXTENSION_CLASS_DESCRIPTOR->customPlaybackSpeeds:[F" + + addInstructions( + arrayLengthConstIndex + 1, + """ + sget-object v$arrayLengthConstDestination, $playbackSpeedsArrayType + array-length v$arrayLengthConstDestination, v$arrayLengthConstDestination + """, + ) + + val originalArrayFetchIndex = indexOfFirstInstructionOrThrow { + val reference = getReference() + reference?.type == "[F" && reference.definingClass.endsWith("/PlayerConfigModel;") + } + val originalArrayFetchDestination = + getInstruction(originalArrayFetchIndex).registerA + + replaceInstruction( + originalArrayFetchIndex, + "sget-object v$originalArrayFetchDestination, $playbackSpeedsArrayType", + ) + } + + // region Force old video quality menu. + + // Add a static INSTANCE field to the class. + // This is later used to call "showOldPlaybackSpeedMenu" on the instance. + + val instanceField = ImmutableField( + getOldPlaybackSpeedsFingerprint.originalClassDef.type, + "INSTANCE", + getOldPlaybackSpeedsFingerprint.originalClassDef.type, + AccessFlags.PUBLIC.value or AccessFlags.STATIC.value, + null, + null, + null, + ).toMutable() + + getOldPlaybackSpeedsFingerprint.classDef.staticFields.add(instanceField) + // Set the INSTANCE field to the instance of the class. + // In order to prevent a conflict with another patch, add the instruction at index 1. + getOldPlaybackSpeedsFingerprint.method.addInstruction(1, "sput-object p0, $instanceField") + + // Get the "showOldPlaybackSpeedMenu" method. + // This is later called on the field INSTANCE. + val showOldPlaybackSpeedMenuMethod = showOldPlaybackSpeedMenuFingerprint.match( + getOldPlaybackSpeedsFingerprint.classDef, + ).method + + // Insert the call to the "showOldPlaybackSpeedMenu" method on the field INSTANCE. + showOldPlaybackSpeedMenuExtensionFingerprint.method.apply { + addInstructionsWithLabels( + instructions.lastIndex, + """ + sget-object v0, $instanceField + if-nez v0, :not_null + return-void + :not_null + invoke-virtual { v0 }, $showOldPlaybackSpeedMenuMethod + """ + ) + } + + // endregion + // Close the unpatched playback dialog and show the modern custom dialog. addRecyclerViewTreeHook(EXTENSION_CLASS_DESCRIPTOR) // Required to check if the playback speed menu is currently shown. addLithoFilter(FILTER_CLASS_DESCRIPTOR) - // endregion - - // region Custom tap and hold 2x speed. if (is_19_25_or_greater) { diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/Fingerprints.kt index 9d8ba8315..f39a4136f 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/Fingerprints.kt @@ -3,10 +3,33 @@ package app.revanced.patches.youtube.video.speed.custom import app.revanced.patcher.fingerprint import app.revanced.util.getReference import app.revanced.util.indexOfFirstInstruction +import app.revanced.util.literal import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.reference.StringReference +internal val getOldPlaybackSpeedsFingerprint = fingerprint { + parameters("[L", "I") + strings("menu_item_playback_speed") +} + +internal val showOldPlaybackSpeedMenuFingerprint = fingerprint { + literal { speedUnavailableId } +} + +internal val showOldPlaybackSpeedMenuExtensionFingerprint = fingerprint { + custom { method, classDef -> + method.name == "showOldPlaybackSpeedMenu" && classDef.type == EXTENSION_CLASS_DESCRIPTOR + } +} + +internal val speedArrayGeneratorFingerprint = fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) + returns("[L") + parameters("Lcom/google/android/libraries/youtube/innertube/model/player/PlayerResponseModel;") + strings("0.0#") +} + internal val speedLimiterFingerprint = fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") diff --git a/patches/src/main/resources/addresources/values/strings.xml b/patches/src/main/resources/addresources/values/strings.xml index 79e04133b..8a356d06d 100644 --- a/patches/src/main/resources/addresources/values/strings.xml +++ b/patches/src/main/resources/addresources/values/strings.xml @@ -1547,6 +1547,9 @@ Enabling this can unlock higher video qualities" Custom playback speed menu Custom speed menu is shown Custom speed menu is not shown + Restore old playback speed menu + Old speed menu is shown + Modern speed menu is shown Custom playback speeds Add or change the custom playback speeds Custom speeds must be less than %s