From 24f376a4b8d6bdccc32ffff0d983f22eb4940791 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Wed, 10 May 2023 02:14:26 +0200 Subject: [PATCH] feat(youtube/hide-shorts-components): hide navigation bar --- .../app/revanced/extensions/Extensions.kt | 28 ++++-- .../BottomNavigationBarFingerprint.kt | 18 ++++ .../RenderBottomNavigationBarFingerprint.kt | 19 ++++ ...derBottomNavigationBarParentFingerprint.kt | 8 ++ .../SetPivotBarVisibilityFingerprint.kt | 19 ++++ .../SetPivotBarVisibilityParentFingerprint.kt | 8 ++ .../patch/HideShortsComponentsPatch.kt | 89 +++++++++++++++---- .../settings/bytecode/patch/SettingsPatch.kt | 1 + 8 files changed, 167 insertions(+), 23 deletions(-) create mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/fingerprints/BottomNavigationBarFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/fingerprints/RenderBottomNavigationBarFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/fingerprints/RenderBottomNavigationBarParentFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/fingerprints/SetPivotBarVisibilityFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/fingerprints/SetPivotBarVisibilityParentFingerprint.kt diff --git a/src/main/kotlin/app/revanced/extensions/Extensions.kt b/src/main/kotlin/app/revanced/extensions/Extensions.kt index f09f1c5c2..37b9ffcee 100644 --- a/src/main/kotlin/app/revanced/extensions/Extensions.kt +++ b/src/main/kotlin/app/revanced/extensions/Extensions.kt @@ -6,7 +6,10 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.patch.PatchResultError import app.revanced.patcher.util.proxy.mutableTypes.MutableClass import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod +import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch +import org.jf.dexlib2.Opcode import org.jf.dexlib2.iface.Method +import org.jf.dexlib2.iface.instruction.WideLiteralInstruction import org.jf.dexlib2.util.MethodUtil import org.w3c.dom.Node @@ -16,7 +19,7 @@ import org.w3c.dom.Node * * @return A [PatchResultError] for the [MethodFingerprint]. */ -fun MethodFingerprint.toErrorResult() = PatchResultError("Failed to resolve $name") +internal fun MethodFingerprint.toErrorResult() = PatchResultError("Failed to resolve $name") /** * Find the [MutableMethod] from a given [Method] in a [MutableClass]. @@ -24,7 +27,7 @@ fun MethodFingerprint.toErrorResult() = PatchResultError("Failed to resolve $nam * @param method The [Method] to find. * @return The [MutableMethod]. */ -fun MutableClass.findMutableMethodOf(method: Method) = this.methods.first { +internal fun MutableClass.findMutableMethodOf(method: Method) = this.methods.first { MethodUtil.methodSignaturesMatch(it, method) } @@ -33,7 +36,7 @@ fun MutableClass.findMutableMethodOf(method: Method) = this.methods.first { * * @param transform the transformation function. original method goes in, transformed method goes out */ -fun MutableClass.transformMethods(transform: MutableMethod.() -> MutableMethod) { +internal fun MutableClass.transformMethods(transform: MutableMethod.() -> MutableMethod) { val transformedMethods = methods.map { it.transform() } methods.clear() methods.addAll(transformedMethods) @@ -44,7 +47,7 @@ internal fun Node.doRecursively(action: (Node) -> Unit) { for (i in 0 until this.childNodes.length) this.childNodes.item(i).doRecursively(action) } -fun MutableMethod.injectHideViewCall( +internal fun MutableMethod.injectHideViewCall( insertIndex: Int, viewRegister: Int, classDescriptor: String, @@ -52,4 +55,19 @@ fun MutableMethod.injectHideViewCall( ) = addInstruction( insertIndex, "invoke-static { v$viewRegister }, $classDescriptor->$targetMethod(Landroid/view/View;)V" -) \ No newline at end of file +) + +internal fun MutableMethod.findIndexForIdResource(resourceName: String): Int { + fun getIdResourceId(resourceName: String) = ResourceMappingPatch.resourceMappings.single { + it.type == "id" && it.name == resourceName + }.id + + val resourceId = getIdResourceId(resourceName) + return implementation!!.instructions.indexOfFirst { + if (it.opcode != Opcode.CONST) return@indexOfFirst false + + val literal = (it as WideLiteralInstruction).wideLiteral + + return@indexOfFirst resourceId == literal + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/fingerprints/BottomNavigationBarFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/fingerprints/BottomNavigationBarFingerprint.kt new file mode 100644 index 000000000..c53e79673 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/fingerprints/BottomNavigationBarFingerprint.kt @@ -0,0 +1,18 @@ +package app.revanced.patches.youtube.layout.hide.shorts.bytecode.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.Opcode + +object BottomNavigationBarFingerprint : MethodFingerprint( + opcodes = listOf( + Opcode.MOVE_RESULT_OBJECT, // Refers to bottom navigation bar + Opcode.IF_EQZ, + Opcode.IGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.IGET_OBJECT, + ), + strings = listOf( + "navigation_endpoint_interaction_logging_extension", + "reel_watch_fragment_watch_while", + ), +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/fingerprints/RenderBottomNavigationBarFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/fingerprints/RenderBottomNavigationBarFingerprint.kt new file mode 100644 index 000000000..216d7276a --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/fingerprints/RenderBottomNavigationBarFingerprint.kt @@ -0,0 +1,19 @@ +package app.revanced.patches.youtube.layout.hide.shorts.bytecode.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.Opcode + +object RenderBottomNavigationBarFingerprint : MethodFingerprint( + opcodes = listOf( + Opcode.IGET_OBJECT, + Opcode.MONITOR_ENTER, + Opcode.IGET_OBJECT, + Opcode.IF_EQZ, + Opcode.INVOKE_INTERFACE, + Opcode.MONITOR_EXIT, + Opcode.RETURN_VOID, + Opcode.MOVE_EXCEPTION, + Opcode.MONITOR_EXIT, + Opcode.THROW, + ) +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/fingerprints/RenderBottomNavigationBarParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/fingerprints/RenderBottomNavigationBarParentFingerprint.kt new file mode 100644 index 000000000..70a2ebc0a --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/fingerprints/RenderBottomNavigationBarParentFingerprint.kt @@ -0,0 +1,8 @@ +package app.revanced.patches.youtube.layout.hide.shorts.bytecode.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint + +object RenderBottomNavigationBarParentFingerprint : MethodFingerprint( + parameters = listOf("I", "I", "L", "L", "J", "L"), + strings = listOf("aa") +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/fingerprints/SetPivotBarVisibilityFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/fingerprints/SetPivotBarVisibilityFingerprint.kt new file mode 100644 index 000000000..6c169f2ae --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/fingerprints/SetPivotBarVisibilityFingerprint.kt @@ -0,0 +1,19 @@ +package app.revanced.patches.youtube.layout.hide.shorts.bytecode.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.Opcode + +object SetPivotBarVisibilityFingerprint : MethodFingerprint( + parameters = listOf("Z"), + opcodes = listOf( + Opcode.IGET_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT, + Opcode.IF_EQZ, + Opcode.RETURN_VOID, + Opcode.IGET_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + ) +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/fingerprints/SetPivotBarVisibilityParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/fingerprints/SetPivotBarVisibilityParentFingerprint.kt new file mode 100644 index 000000000..170569b9a --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/fingerprints/SetPivotBarVisibilityParentFingerprint.kt @@ -0,0 +1,8 @@ +package app.revanced.patches.youtube.layout.hide.shorts.bytecode.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint + +object SetPivotBarVisibilityParentFingerprint : MethodFingerprint( + parameters = listOf("Z"), + strings = listOf("FEnotifications_inbox") +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/patch/HideShortsComponentsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/patch/HideShortsComponentsPatch.kt index 4d8ac578c..dcad8f43a 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/patch/HideShortsComponentsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/patch/HideShortsComponentsPatch.kt @@ -1,12 +1,15 @@ package app.revanced.patches.youtube.layout.hide.shorts.bytecode.patch +import app.revanced.extensions.findIndexForIdResource import app.revanced.extensions.injectHideViewCall import app.revanced.extensions.toErrorResult import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstruction import app.revanced.patcher.extensions.instruction +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess @@ -15,15 +18,13 @@ import app.revanced.patcher.patch.annotations.Patch import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch import app.revanced.patches.youtube.layout.hide.shorts.annotations.HideShortsComponentsCompatibility -import app.revanced.patches.youtube.layout.hide.shorts.bytecode.fingerprints.CreateShortsButtonsFingerprint -import app.revanced.patches.youtube.layout.hide.shorts.bytecode.fingerprints.ReelConstructorFingerprint +import app.revanced.patches.youtube.layout.hide.shorts.bytecode.fingerprints.* import app.revanced.patches.youtube.layout.hide.shorts.resource.patch.HideShortsComponentsResourcePatch import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch import app.revanced.patches.youtube.misc.litho.filter.patch.LithoFilterPatch -import org.jf.dexlib2.Opcode import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction +import org.jf.dexlib2.iface.instruction.OneRegisterInstruction import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction -import org.jf.dexlib2.iface.instruction.WideLiteralInstruction @Patch @DependsOn( @@ -38,9 +39,18 @@ import org.jf.dexlib2.iface.instruction.WideLiteralInstruction @Description("Hides components from YouTube Shorts.") @HideShortsComponentsCompatibility @Version("0.0.1") -class HideShortsComponentsPatch : BytecodePatch(listOf(CreateShortsButtonsFingerprint, ReelConstructorFingerprint)) { +class HideShortsComponentsPatch : BytecodePatch( + listOf( + CreateShortsButtonsFingerprint, + ReelConstructorFingerprint, + BottomNavigationBarFingerprint, + RenderBottomNavigationBarParentFingerprint, + SetPivotBarVisibilityParentFingerprint + ) +) { override fun execute(context: BytecodeContext): PatchResult { - // Hide the Shorts shelf. + // region Hide the Shorts shelf. + ReelConstructorFingerprint.result?.let { it.mutableMethod.apply { val insertIndex = it.scanResult.patternScanResult!!.startIndex + 2 @@ -55,10 +65,64 @@ class HideShortsComponentsPatch : BytecodePatch(listOf(CreateShortsButtonsFinger } } ?: return ReelConstructorFingerprint.toErrorResult() + // endregion + + // region Hide the Shorts buttons. + // Some Shorts buttons are views, hide them by setting their visibility to GONE. CreateShortsButtonsFingerprint.result?.let { ShortsButtons.values().forEach { button -> button.injectHideCall(it.mutableMethod) } } ?: return CreateShortsButtonsFingerprint.toErrorResult() + + // endregion + + // region Hide the navigation bar. + + // Hook to get the pivotBar view. + SetPivotBarVisibilityParentFingerprint.result?.let { + if (!SetPivotBarVisibilityFingerprint.resolve(context, it.classDef)) + throw SetPivotBarVisibilityFingerprint.toErrorResult() + + SetPivotBarVisibilityFingerprint.result!!.let { result -> + result.mutableMethod.apply { + val checkCastIndex = result.scanResult.patternScanResult!!.endIndex + val viewRegister = instruction(checkCastIndex).registerA + addInstruction( + checkCastIndex + 1, + "sput-object v$viewRegister, $CLASS_DESCRIPTOR->pivotBar:" + + "Lcom/google/android/libraries/youtube/rendering/ui/pivotbar/PivotBar;" + ) + } + } + } ?: return SetPivotBarVisibilityParentFingerprint.toErrorResult() + + // Hook to hide the navigation bar when Shorts are being played. + RenderBottomNavigationBarParentFingerprint.result?.let { + if (!RenderBottomNavigationBarFingerprint.resolve(context, it.classDef)) + throw RenderBottomNavigationBarFingerprint.toErrorResult() + + RenderBottomNavigationBarFingerprint.result!!.mutableMethod.apply { + addInstruction(0, "invoke-static { }, $CLASS_DESCRIPTOR->hideNavigationBar()V") + } + } ?: return RenderBottomNavigationBarParentFingerprint.toErrorResult() + + // Required to prevent a black bar from appearing at the bottom of the screen. + BottomNavigationBarFingerprint.result?.let { + it.mutableMethod.apply { + val moveResultIndex = it.scanResult.patternScanResult!!.startIndex + val viewRegister = instruction(moveResultIndex).registerA + val insertIndex = moveResultIndex + 1 + + addInstruction( + insertIndex, + "invoke-static { v$viewRegister }, $CLASS_DESCRIPTOR->" + + "hideNavigationBar(Landroid/view/View;)Landroid/view/View;" + ) + } + } ?: return BottomNavigationBarFingerprint.toErrorResult() + + // endregion + return PatchResultSuccess() } @@ -71,18 +135,7 @@ class HideShortsComponentsPatch : BytecodePatch(listOf(CreateShortsButtonsFinger SHARE("reel_dyn_share", "hideShortsShareButton"); fun injectHideCall(method: MutableMethod) { - val resourceId = ResourceMappingPatch.resourceMappings.single { - it.type == "id" && it.name == resourceName - }.id - - // Get the index of the reference to the view's resource ID. - val referencedIndex = method.implementation!!.instructions.indexOfFirst { - if (it.opcode != Opcode.CONST) return@indexOfFirst false - - val literal = (it as WideLiteralInstruction).wideLiteral - - return@indexOfFirst resourceId == literal - } + val referencedIndex = method.findIndexForIdResource(resourceName) val setIdIndex = referencedIndex + 1 val viewRegister = method.instruction(setIdIndex).registerC diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/patch/SettingsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/patch/SettingsPatch.kt index d4b1f6c1f..dd694ab64 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/patch/SettingsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/patch/SettingsPatch.kt @@ -44,6 +44,7 @@ class SettingsPatch : BytecodePatch( ThemeSetterSystemFingerprint.result!!.let { result -> val call = buildInvokeInstructionsString() result.mutableMethod.apply { + // TODO: The label is pointing to the instruction below, but should instead point to the new instruction. addInstruction( result.scanResult.patternScanResult!!.startIndex, call )