From 1765d0575fbe5e42be11042eec7c1039e3184d02 Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Tue, 23 Apr 2024 22:17:20 +0900 Subject: [PATCH] feat(YouTube/Hide shorts components): use browseId instead of navigation bar index - Sometimes the Shorts shelves are loaded first before the navigation bar index is updated, and under certain circumstances the Shorts shelves are not hidden properly. - This issue can be resolved by checking the browser id instead of the navigation bar index. --- .../shorts/components/ShortsComponentPatch.kt | 2 - .../utils/browseid/BrowseIdHookPatch.kt | 109 ------------------ .../MobileTopBarDialogFingerprint.kt | 11 -- .../navigation/NavigationBarHookPatch.kt | 10 +- .../utils/playertype/PlayerTypeHookPatch.kt | 61 +++++++++- .../fingerprint}/BrowseIdClassFingerprint.kt | 2 +- .../kotlin/app/revanced/util/BytecodeUtils.kt | 2 +- 7 files changed, 65 insertions(+), 132 deletions(-) delete mode 100644 src/main/kotlin/app/revanced/patches/youtube/utils/browseid/BrowseIdHookPatch.kt delete mode 100644 src/main/kotlin/app/revanced/patches/youtube/utils/browseid/fingerprints/MobileTopBarDialogFingerprint.kt rename src/main/kotlin/app/revanced/patches/youtube/utils/{browseid/fingerprints => playertype/fingerprint}/BrowseIdClassFingerprint.kt (86%) diff --git a/src/main/kotlin/app/revanced/patches/youtube/shorts/components/ShortsComponentPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/shorts/components/ShortsComponentPatch.kt index 5f1e279f9..79770b1d9 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/shorts/components/ShortsComponentPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/shorts/components/ShortsComponentPatch.kt @@ -17,7 +17,6 @@ import app.revanced.patches.youtube.shorts.components.fingerprints.ShortsPivotLe import app.revanced.patches.youtube.utils.integrations.Constants.COMPATIBLE_PACKAGE import app.revanced.patches.youtube.utils.integrations.Constants.COMPONENTS_PATH import app.revanced.patches.youtube.utils.integrations.Constants.SHORTS_CLASS_DESCRIPTOR -import app.revanced.patches.youtube.utils.navigation.NavigationBarHookPatch import app.revanced.patches.youtube.utils.playertype.PlayerTypeHookPatch import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.ReelDynRemix @@ -45,7 +44,6 @@ object ShortsComponentPatch : BaseBytecodePatch( description = "Adds options to hide components related to YouTube Shorts.", dependencies = setOf( LithoFilterPatch::class, - NavigationBarHookPatch::class, PlayerTypeHookPatch::class, SettingsPatch::class, SharedResourceIdPatch::class, diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/browseid/BrowseIdHookPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/browseid/BrowseIdHookPatch.kt deleted file mode 100644 index aca1ab4fe..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/utils/browseid/BrowseIdHookPatch.kt +++ /dev/null @@ -1,109 +0,0 @@ -package app.revanced.patches.youtube.utils.browseid - -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.InstructionExtensions.addInstruction -import app.revanced.patcher.extensions.InstructionExtensions.addInstructions -import app.revanced.patcher.extensions.InstructionExtensions.getInstruction -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchException -import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.litho.LithoFilterPatch -import app.revanced.patches.shared.litho.fingerprints.PathBuilderFingerprint -import app.revanced.patches.youtube.utils.browseid.fingerprints.BrowseIdClassFingerprint -import app.revanced.patches.youtube.utils.browseid.fingerprints.MobileTopBarDialogFingerprint -import app.revanced.patches.youtube.utils.integrations.Constants.SHARED_PATH -import app.revanced.patches.youtube.utils.mainactivity.MainActivityResolvePatch -import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch -import app.revanced.util.getStringInstructionIndex -import app.revanced.util.getTargetIndex -import app.revanced.util.resultOrThrow -import com.android.tools.smali.dexlib2.Opcode -import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction -import com.android.tools.smali.dexlib2.iface.reference.FieldReference - -@Patch( - dependencies = [ - LithoFilterPatch::class, - MainActivityResolvePatch::class, - SharedResourceIdPatch::class - ] -) -@Deprecated("This patch will be removed in the future.") -object BrowseIdHookPatch : BytecodePatch( - setOf( - BrowseIdClassFingerprint, - MobileTopBarDialogFingerprint, - PathBuilderFingerprint - ) -) { - private const val INTEGRATIONS_CLASS_DESCRIPTOR = - "$SHARED_PATH/BrowseId;" - - private const val SETTINGS_ACTIVITY_CLASS_DESCRIPTOR = - "Lcom/google/android/apps/youtube/app/settings/SettingsActivity;" - - override fun execute(context: BytecodeContext) { - - /** - * This class handles BrowseId. - * Pass an instance of this class to integrations to use Java Reflection. - */ - BrowseIdClassFingerprint.resultOrThrow().let { - it.mutableMethod.apply { - val targetIndex = getStringInstructionIndex("VL") - 1 - val targetReference = getInstruction(targetIndex).reference - val targetClass = context.findClass((targetReference as FieldReference).definingClass)!!.mutableClass - - targetClass.methods.find { method -> method.name == "" } - ?.apply { - val browseIdFieldIndex = getTargetIndex(Opcode.IPUT_OBJECT) - val browseIdFieldName = - (getInstruction(browseIdFieldIndex).reference as FieldReference).name - - addInstructions( - 1, """ - const-string v0, "$browseIdFieldName" - invoke-static {p0, v0}, $INTEGRATIONS_CLASS_DESCRIPTOR->initialize(Ljava/lang/Object;Ljava/lang/String;)V - """ - ) - } ?: throw PatchException("BrowseIdClass not found!") - } - } - - val mobileTopBarDialogClass = - MobileTopBarDialogFingerprint.resultOrThrow().mutableClass - - val mobileTopBarDialogOnBackPressedMethod = - mobileTopBarDialogClass.methods.single { method -> - method.name == "onBackPressed" - } - - val mobileTopBarDialogOnStopMethod = - mobileTopBarDialogClass.methods.single { method -> - method.name == "onStop" - } - - val pathBuilderMethod = PathBuilderFingerprint.resultOrThrow().mutableMethod - - val settingsActivityOnBackPressedMethod = - context.findClass(SETTINGS_ACTIVITY_CLASS_DESCRIPTOR)!!.mutableClass.methods.single { method -> - method.name == "onBackPressed" - } - - /** - * Set BrowseId to integrations. - */ - listOf( - MainActivityResolvePatch.onBackPressedMethod, - mobileTopBarDialogOnBackPressedMethod, - mobileTopBarDialogOnStopMethod, - pathBuilderMethod, - settingsActivityOnBackPressedMethod - ).forEach { method -> - method.addInstruction( - 0, - "invoke-static {}, $INTEGRATIONS_CLASS_DESCRIPTOR->setBrowseIdFromField()V" - ) - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/browseid/fingerprints/MobileTopBarDialogFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/browseid/fingerprints/MobileTopBarDialogFingerprint.kt deleted file mode 100644 index f6b1af9c2..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/utils/browseid/fingerprints/MobileTopBarDialogFingerprint.kt +++ /dev/null @@ -1,11 +0,0 @@ -package app.revanced.patches.youtube.utils.browseid.fingerprints - -import app.revanced.patcher.fingerprint.MethodFingerprint - -internal object MobileTopBarDialogFingerprint : MethodFingerprint( - returnType = "V", - customFingerprint = { methodDef, classDef -> - methodDef.name == "setContentView" && - classDef.superclass == "Landroid/app/Dialog;" - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/navigation/NavigationBarHookPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/navigation/NavigationBarHookPatch.kt index 2b16fd054..cf792db5b 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/utils/navigation/NavigationBarHookPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/utils/navigation/NavigationBarHookPatch.kt @@ -10,7 +10,6 @@ import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.patches.youtube.utils.fingerprints.InitializeButtonsFingerprint import app.revanced.patches.youtube.utils.integrations.Constants.SHARED_PATH -import app.revanced.patches.youtube.utils.mainactivity.MainActivityResolvePatch import app.revanced.patches.youtube.utils.navigation.fingerprints.NavigationEnumFingerprint import app.revanced.patches.youtube.utils.navigation.fingerprints.PivotBarButtonsCreateDrawableViewFingerprint import app.revanced.patches.youtube.utils.navigation.fingerprints.PivotBarButtonsCreateResourceViewFingerprint @@ -18,19 +17,21 @@ import app.revanced.patches.youtube.utils.navigation.fingerprints.PivotBarButton import app.revanced.patches.youtube.utils.navigation.fingerprints.PivotBarConstructorFingerprint import app.revanced.patches.youtube.utils.playertype.PlayerTypeHookPatch import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch +import app.revanced.util.addFieldAndInstructions import app.revanced.util.getReference +import app.revanced.util.getTargetIndex import app.revanced.util.resultOrThrow import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.Instruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction +import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction import com.android.tools.smali.dexlib2.iface.reference.MethodReference import com.android.tools.smali.dexlib2.util.MethodUtil @Patch( description = "Hooks the active navigation or search bar.", dependencies = [ - MainActivityResolvePatch::class, PlayerTypeHookPatch::class, SharedResourceIdPatch::class ], @@ -112,11 +113,6 @@ object NavigationBarHookPatch : BytecodePatch( } } - MainActivityResolvePatch.injectOnBackPressedMethodCall( - INTEGRATIONS_CLASS_DESCRIPTOR, - "onBackPressed" - ) - navigationTabCreatedCallback = context.findClass(INTEGRATIONS_CLASS_DESCRIPTOR)?.mutableClass?.methods?.first { method -> method.name == "navigationTabCreatedCallback" } ?: throw PatchException("Could not find navigationTabCreatedCallback method") diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/playertype/PlayerTypeHookPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/playertype/PlayerTypeHookPatch.kt index acb6a6d37..2c1c1b2b8 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/utils/playertype/PlayerTypeHookPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/utils/playertype/PlayerTypeHookPatch.kt @@ -5,23 +5,31 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.annotation.Patch import app.revanced.patches.youtube.utils.fingerprints.YouTubeControlsOverlayFingerprint import app.revanced.patches.youtube.utils.integrations.Constants.SHARED_PATH import app.revanced.patches.youtube.utils.integrations.Constants.UTILS_PATH import app.revanced.patches.youtube.utils.playertype.fingerprint.ActionBarSearchResultsFingerprint +import app.revanced.patches.youtube.utils.playertype.fingerprint.BrowseIdClassFingerprint import app.revanced.patches.youtube.utils.playertype.fingerprint.PlayerTypeFingerprint import app.revanced.patches.youtube.utils.playertype.fingerprint.VideoStateFingerprint import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch +import app.revanced.util.addFieldAndInstructions +import app.revanced.util.getStringInstructionIndex +import app.revanced.util.getTargetIndex import app.revanced.util.getTargetIndexWithMethodReferenceName import app.revanced.util.resultOrThrow +import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction +import com.android.tools.smali.dexlib2.iface.reference.FieldReference @Patch(dependencies = [SharedResourceIdPatch::class]) object PlayerTypeHookPatch : BytecodePatch( setOf( ActionBarSearchResultsFingerprint, + BrowseIdClassFingerprint, PlayerTypeFingerprint, YouTubeControlsOverlayFingerprint ) @@ -34,6 +42,8 @@ object PlayerTypeHookPatch : BytecodePatch( override fun execute(context: BytecodeContext) { + // region patch for set player type + PlayerTypeFingerprint.resultOrThrow().let { it.mutableMethod.apply { addInstruction( @@ -44,6 +54,10 @@ object PlayerTypeHookPatch : BytecodePatch( } } + // endregion + + // region patch for set video state + YouTubeControlsOverlayFingerprint.resultOrThrow().let { parentResult -> VideoStateFingerprint.also { it.resolve(context, parentResult.classDef) }.resultOrThrow().let { @@ -62,7 +76,51 @@ object PlayerTypeHookPatch : BytecodePatch( } } - // Hook the search bar. + // endregion + + // region patch for hook browse id + + BrowseIdClassFingerprint.resultOrThrow().let { + it.mutableMethod.apply { + val targetIndex = getStringInstructionIndex("VL") - 1 + val targetReference = getInstruction(targetIndex).reference + val targetClass = context.findClass((targetReference as FieldReference).definingClass)!!.mutableClass + + targetClass.methods.find { method -> method.name == "" } + ?.apply { + val browseIdFieldIndex = getTargetIndex(Opcode.IPUT_OBJECT) + val browseIdFieldName = + (getInstruction(browseIdFieldIndex).reference as FieldReference).name + + val smaliInstructions = + """ + if-eqz v0, :ignore + iget-object v0, v0, $definingClass->$browseIdFieldName:Ljava/lang/String; + if-eqz v0, :ignore + return-object v0 + :ignore + const-string v0, "" + return-object v0 + """ + + val rootViewMutableClass = + context.findClass(INTEGRATIONS_ROOT_VIEW_HOOK_CLASS_DESCRIPTOR)!!.mutableClass + + rootViewMutableClass.addFieldAndInstructions( + context, + "getBrowseId", + "browseIdClass", + definingClass, + smaliInstructions, + true + ) + } ?: throw PatchException("BrowseIdClass not found!") + } + } + + // endregion + + // region patch for hook search bar // Two different layouts are used at the hooked code. // Insert before the first ViewGroup method call after inflating, @@ -78,6 +136,7 @@ object PlayerTypeHookPatch : BytecodePatch( ) } + // endregion } } diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/browseid/fingerprints/BrowseIdClassFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/playertype/fingerprint/BrowseIdClassFingerprint.kt similarity index 86% rename from src/main/kotlin/app/revanced/patches/youtube/utils/browseid/fingerprints/BrowseIdClassFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/utils/playertype/fingerprint/BrowseIdClassFingerprint.kt index 711410ba4..73b78028e 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/utils/browseid/fingerprints/BrowseIdClassFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/utils/playertype/fingerprint/BrowseIdClassFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.utils.browseid.fingerprints +package app.revanced.patches.youtube.utils.playertype.fingerprint import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/util/BytecodeUtils.kt b/src/main/kotlin/app/revanced/util/BytecodeUtils.kt index 04975e0be..752c6a2d7 100644 --- a/src/main/kotlin/app/revanced/util/BytecodeUtils.kt +++ b/src/main/kotlin/app/revanced/util/BytecodeUtils.kt @@ -397,7 +397,7 @@ fun MutableClass.addFieldAndInstructions( if (shouldAddConstructor) { context.findClass(objectClass)!!.mutableClass.methods - .filter { method -> MethodUtil.isConstructor(method) } + .filter { method -> method.name == "" } .forEach { mutableMethod -> mutableMethod.apply { val initializeIndex = getTargetIndexWithMethodReferenceName("")