diff --git a/api/revanced-patches.api b/api/revanced-patches.api index 5ebfa2f71e..d5a47720a9 100644 --- a/api/revanced-patches.api +++ b/api/revanced-patches.api @@ -2184,6 +2184,7 @@ public final class app/revanced/util/BytecodeUtilsKt { public static final fun containsWideLiteralInstructionValue (Lcom/android/tools/smali/dexlib2/iface/Method;J)Z public static final fun findMutableMethodOf (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableClass;Lcom/android/tools/smali/dexlib2/iface/Method;)Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod; public static final fun findOpcodeIndicesReversed (Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/Opcode;)Ljava/util/List; + public static final fun findOpcodeIndicesReversed (Lcom/android/tools/smali/dexlib2/iface/Method;Lkotlin/jvm/functions/Function1;)Ljava/util/List; public static final fun getException (Lapp/revanced/patcher/fingerprint/MethodFingerprint;)Lapp/revanced/patcher/patch/PatchException; public static final fun indexOfFirstInstruction (Lcom/android/tools/smali/dexlib2/iface/Method;ILkotlin/jvm/functions/Function1;)I public static final fun indexOfFirstInstruction (Lcom/android/tools/smali/dexlib2/iface/Method;Lkotlin/jvm/functions/Function1;)I diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsPatch.kt index a505497b13..4f2e832d8f 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsPatch.kt @@ -18,13 +18,18 @@ import app.revanced.patches.youtube.layout.hide.general.fingerprints.HideShowMor import app.revanced.patches.youtube.layout.hide.general.fingerprints.ParseElementFromBufferFingerprint import app.revanced.patches.youtube.layout.hide.general.fingerprints.PlayerOverlayFingerprint import app.revanced.patches.youtube.layout.hide.general.fingerprints.ShowWatermarkFingerprint +import app.revanced.patches.youtube.layout.hide.general.fingerprints.YoodlesImageViewFingerprint import app.revanced.patches.youtube.misc.litho.filter.LithoFilterPatch import app.revanced.patches.youtube.misc.navigation.NavigationBarHookPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch +import app.revanced.util.findOpcodeIndicesReversed +import app.revanced.util.getReference 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.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction +import com.android.tools.smali.dexlib2.iface.reference.MethodReference @Patch( name = "Hide layout components", @@ -70,7 +75,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction ) @Suppress("unused") object HideLayoutComponentsPatch : BytecodePatch( - setOf(ParseElementFromBufferFingerprint, PlayerOverlayFingerprint, HideShowMoreButtonFingerprint), + setOf( + ParseElementFromBufferFingerprint, + PlayerOverlayFingerprint, + HideShowMoreButtonFingerprint, + YoodlesImageViewFingerprint, + ), ) { private const val LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/youtube/patches/components/LayoutComponentsFilter;" @@ -128,6 +138,7 @@ object HideLayoutComponentsPatch : BytecodePatch( SwitchPreference("revanced_hide_search_result_recommendations"), SwitchPreference("revanced_hide_search_result_shelf_header"), SwitchPreference("revanced_hide_show_more_button"), + SwitchPreference("revanced_hide_yoodles"), PreferenceScreen( key = "revanced_hide_keyword_content_screen", sorting = Sorting.UNSORTED, @@ -226,5 +237,28 @@ object HideLayoutComponentsPatch : BytecodePatch( } // endregion + + // region 'Yoodles' + + YoodlesImageViewFingerprint.resultOrThrow().mutableMethod.apply { + findOpcodeIndicesReversed{ + opcode == Opcode.INVOKE_VIRTUAL + && getReference()?.name == "setImageDrawable" + }.forEach { insertIndex -> + val register = getInstruction(insertIndex).registerD + + addInstructionsWithLabels( + insertIndex, + """ + invoke-static { v$register }, $LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR->hideYoodles(Landroid/graphics/drawable/Drawable;)Landroid/graphics/drawable/Drawable; + move-result-object v$register + if-eqz v$register, :hide + """, + ExternalLabel("hide", getInstruction(insertIndex + 1)), + ) + } + } + + // endregion } } diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsResourcePatch.kt index c7b60d544e..24dcbb3f19 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsResourcePatch.kt @@ -17,10 +17,17 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch internal object HideLayoutComponentsResourcePatch : ResourcePatch() { internal var expandButtonDownId: Long = -1 + var youTubeLogo = -1L + override fun execute(context: ResourceContext) { expandButtonDownId = ResourceMappingPatch[ "layout", "expand_button_down", ] + + youTubeLogo = ResourceMappingPatch[ + "id", + "youtube_logo" + ] } } diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/fingerprints/YoodlesImageViewFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/fingerprints/YoodlesImageViewFingerprint.kt new file mode 100644 index 0000000000..092b5110b4 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/fingerprints/YoodlesImageViewFingerprint.kt @@ -0,0 +1,13 @@ +package app.revanced.patches.youtube.layout.hide.general.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patches.youtube.layout.hide.general.HideLayoutComponentsResourcePatch +import app.revanced.util.patch.LiteralValueFingerprint +import com.android.tools.smali.dexlib2.AccessFlags + +internal object YoodlesImageViewFingerprint : LiteralValueFingerprint( + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + parameters = listOf("L", "L"), + returnType = "Landroid/view/View;", + literalSupplier = { HideLayoutComponentsResourcePatch.youTubeLogo } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/util/BytecodeUtils.kt b/src/main/kotlin/app/revanced/util/BytecodeUtils.kt index d22bfbdbe0..98ec71428e 100644 --- a/src/main/kotlin/app/revanced/util/BytecodeUtils.kt +++ b/src/main/kotlin/app/revanced/util/BytecodeUtils.kt @@ -224,18 +224,25 @@ fun Method.indexOfFirstInstructionOrThrow(startIndex: Int = 0, predicate: Instru /** * @return The list of indices of the opcode in reverse order. */ -fun Method.findOpcodeIndicesReversed(opcode: Opcode): List { +fun Method.findOpcodeIndicesReversed(opcode: Opcode): List = + findOpcodeIndicesReversed { this.opcode == opcode } + +/** + * @return The list of indices of the opcode in reverse order. + */ +fun Method.findOpcodeIndicesReversed(filter: Instruction.() -> Boolean): List { val indexes = implementation!!.instructions .withIndex() - .filter { (_, instruction) -> instruction.opcode == opcode } + .filter { (_, instruction) -> filter(instruction) } .map { (index, _) -> index } .reversed() - if (indexes.isEmpty()) throw PatchException("No ${opcode.name} instructions found in: $this") + if (indexes.isEmpty()) throw PatchException("No matching instructions found in: $this") return indexes } + /** * Return the resolved method early. */ diff --git a/src/main/resources/addresources/values/strings.xml b/src/main/resources/addresources/values/strings.xml index 7ed20f9ee5..645f24cc34 100644 --- a/src/main/resources/addresources/values/strings.xml +++ b/src/main/resources/addresources/values/strings.xml @@ -231,6 +231,13 @@ This is because Crowdin requires temporarily flattening this file and removing t Transcript section is shown Video description Hide or show video description components + + + Hide Yoodles (YouTube Doodles) + Search bar Yoodles are hidden + Search bar Yoodles will be periodically shown + YouTube Yoodles show up a few days each year.\n\nIf a Yoodle is currently showing in your region and this hide setting is on, then the filter bar below the search bar will also be hidden. + Custom filter Hide components using custom filters Enable custom filter @@ -240,6 +247,7 @@ This is because Crowdin requires temporarily flattening this file and removing t List of component path builder strings to filter separated by new line Invalid custom filter: %s + Hide keyword content Hide search and feed videos using keyword filters Hide home videos by keywords