From fdfed3c9dd46f477c1cc1b9db0f08054ffa32293 Mon Sep 17 00:00:00 2001 From: Jack <18360463+wowitsjack@users.noreply.github.com> Date: Fri, 6 Mar 2026 21:27:41 +1000 Subject: [PATCH] fix(YouTube - Spoof video streams): Make it work on 21.x (#6705) Co-authored-by: wowitsjack Co-authored-by: oSumAtrIX --- .../youtube/patches/ExitFullscreenPatch.java | 4 ++-- .../patches/HidePlayerOverlayButtonsPatch.java | 8 ++++---- .../youtube/patches/PlayerControlsPatch.java | 11 +++++------ .../shared/misc/spoof/SpoofVideoStreamsPatch.kt | 6 +++--- .../youtube/layout/buttons/overlay/Fingerprints.kt | 3 ++- .../buttons/overlay/HidePlayerOverlayButtonsPatch.kt | 10 ++++++---- .../youtube/misc/playercontrols/Fingerprints.kt | 2 +- .../misc/playercontrols/PlayerControlsPatch.kt | 2 +- 8 files changed, 24 insertions(+), 22 deletions(-) diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/ExitFullscreenPatch.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/ExitFullscreenPatch.java index abb2d6ba9e..1666860287 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/ExitFullscreenPatch.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/ExitFullscreenPatch.java @@ -1,6 +1,6 @@ package app.revanced.extension.youtube.patches; -import android.widget.ImageView; +import android.view.View; import app.revanced.extension.shared.Logger; import app.revanced.extension.shared.Utils; @@ -46,7 +46,7 @@ public class ExitFullscreenPatch { // To fix this, push the perform click to the back fo the main thread, // and by then the overlay controls will be visible since the video is now finished. Utils.runOnMainThreadDelayed(() -> { - ImageView button = PlayerControlsPatch.fullscreenButtonRef.get(); + View button = PlayerControlsPatch.fullscreenButtonRef.get(); if (button == null) { Logger.printDebug(() -> "Fullscreen button is null, cannot click"); } else { diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/HidePlayerOverlayButtonsPatch.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/HidePlayerOverlayButtonsPatch.java index d7a413b790..3c6937a996 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/HidePlayerOverlayButtonsPatch.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/HidePlayerOverlayButtonsPatch.java @@ -109,13 +109,13 @@ public final class HidePlayerOverlayButtonsPatch { /** * Injection point. */ - public static ImageView hideFullscreenButton(ImageView imageView) { + public static View hideFullscreenButton(View view) { if (!Settings.HIDE_FULLSCREEN_BUTTON.get()) { - return imageView; + return view; } - if (imageView != null) { - imageView.setVisibility(View.GONE); + if (view != null) { + view.setVisibility(View.GONE); } return null; diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/PlayerControlsPatch.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/PlayerControlsPatch.java index be7fe91190..482c0c3c49 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/PlayerControlsPatch.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/PlayerControlsPatch.java @@ -2,7 +2,6 @@ package app.revanced.extension.youtube.patches; import android.view.View; import android.view.ViewTreeObserver; -import android.widget.ImageView; import java.lang.ref.WeakReference; @@ -11,7 +10,7 @@ import app.revanced.extension.shared.Logger; @SuppressWarnings("unused") public class PlayerControlsPatch { - public static WeakReference fullscreenButtonRef = new WeakReference<>(null); + public static WeakReference fullscreenButtonRef = new WeakReference<>(null); private static boolean fullscreenButtonVisibilityCallbacksExist() { return false; // Modified during patching if needed. @@ -20,8 +19,8 @@ public class PlayerControlsPatch { /** * Injection point. */ - public static void setFullscreenCloseButton(ImageView imageButton) { - fullscreenButtonRef = new WeakReference<>(imageButton); + public static void setFullscreenCloseButton(View button) { + fullscreenButtonRef = new WeakReference<>(button); Logger.printDebug(() -> "Fullscreen button set"); if (!fullscreenButtonVisibilityCallbacksExist()) { @@ -30,13 +29,13 @@ public class PlayerControlsPatch { // Add a global listener, since the protected method // View#onVisibilityChanged() does not have any call backs. - imageButton.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { + button.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { int lastVisibility = View.VISIBLE; @Override public void onGlobalLayout() { try { - final int visibility = imageButton.getVisibility(); + final int visibility = button.getVisibility(); if (lastVisibility != visibility) { lastVisibility = visibility; diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/misc/spoof/SpoofVideoStreamsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/shared/misc/spoof/SpoofVideoStreamsPatch.kt index ba7faa001b..7662718fc8 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/misc/spoof/SpoofVideoStreamsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/misc/spoof/SpoofVideoStreamsPatch.kt @@ -216,10 +216,10 @@ internal fun spoofVideoStreamsPatch( // A proper fix may include modifying the request body to match the platforms expected body. buildMediaDataSourceMethod.apply { - val targetIndex = instructions.count() - 1 + // Find return-void, not the last instruction, which may be a throw in an error branch + // where p0 is overwritten by new-instance IllegalArgumentException. + val targetIndex = indexOfFirstInstructionOrThrow(Opcode.RETURN_VOID) - // Instructions are added just before the method returns, - // so there's no concern of clobbering in-use registers. addInstructions( targetIndex, """ diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/overlay/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/overlay/Fingerprints.kt index a350d883a9..1016fd667a 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/overlay/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/overlay/Fingerprints.kt @@ -38,7 +38,8 @@ internal val BytecodePatchContext.fullscreenButtonMethodMatch by composingFirstM returnType("V") instructions( ResourceType.ID("fullscreen_button"), - Opcode.CHECK_CAST() + Opcode.INVOKE_VIRTUAL(), // findViewById call. + Opcode.MOVE_RESULT_OBJECT() // The actual view, not a check-cast in 21.x. ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/overlay/HidePlayerOverlayButtonsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/overlay/HidePlayerOverlayButtonsPatch.kt index f09b64213f..2af8a1177a 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/overlay/HidePlayerOverlayButtonsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/overlay/HidePlayerOverlayButtonsPatch.kt @@ -169,14 +169,16 @@ val hidePlayerOverlayButtonsPatch = bytecodePatch( fullscreenButtonMethodMatch.let { it.method.apply { - val castIndex = it[1] - val insertIndex = castIndex + 1 - val insertRegister = getInstruction(castIndex).registerA + // Youtube 21.x doesn't cast the fullscreen button to ImageView anymore, + // so match on move-result-object after findViewById instead of check-cast. + val moveResultIndex = it[2] + val insertIndex = moveResultIndex + 1 + val insertRegister = getInstruction(moveResultIndex).registerA addInstructionsWithLabels( insertIndex, """ - invoke-static { v$insertRegister }, ${EXTENSION_CLASS_DESCRIPTOR}->hideFullscreenButton(Landroid/widget/ImageView;)Landroid/widget/ImageView; + invoke-static { v$insertRegister }, ${EXTENSION_CLASS_DESCRIPTOR}->hideFullscreenButton(Landroid/view/View;)Landroid/view/View; move-result-object v$insertRegister if-nez v$insertRegister, :show return-void diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/Fingerprints.kt index 41889cb905..f289bc9035 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/Fingerprints.kt @@ -78,7 +78,7 @@ internal val BytecodePatchContext.overlayViewInflateMethodMatch by composingFirs instructions( ResourceType.ID("heatseeker_viewstub"), ResourceType.ID("fullscreen_button"), - allOf(Opcode.CHECK_CAST(), type("Landroid/widget/ImageView;")), + Opcode.CHECK_CAST(), ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/PlayerControlsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/PlayerControlsPatch.kt index aeec4f5b01..3dde033313 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/PlayerControlsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/PlayerControlsPatch.kt @@ -261,7 +261,7 @@ val playerControlsPatch = bytecodePatch( addInstruction( index + 1, "invoke-static { v$register }, " + - "$EXTENSION_CLASS_DESCRIPTOR->setFullscreenCloseButton(Landroid/widget/ImageView;)V", + "$EXTENSION_CLASS_DESCRIPTOR->setFullscreenCloseButton(Landroid/view/View;)V", ) }