diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/annotations/HideFilterBar.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/annotations/HideFilterBar.kt new file mode 100644 index 000000000..db58b1c91 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/annotations/HideFilterBar.kt @@ -0,0 +1,8 @@ +package app.revanced.patches.youtube.layout.hide.filterbar.annotations + +import app.revanced.patcher.annotation.Compatibility +import app.revanced.patcher.annotation.Package + +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37"))]) +@Target(AnnotationTarget.CLASS) +internal annotation class HideFilterBar \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/fingerprints/FilterBarHeightFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/fingerprints/FilterBarHeightFingerprint.kt new file mode 100644 index 000000000..6178c4c89 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/fingerprints/FilterBarHeightFingerprint.kt @@ -0,0 +1,14 @@ +package app.revanced.patches.youtube.layout.hide.filterbar.fingerprints + +import app.revanced.patches.youtube.layout.hide.filterbar.patch.HideFilterBarResourcePatch.Companion.filterBarHeightId +import org.jf.dexlib2.Opcode + +object FilterBarHeightFingerprint : LiteralOpcodesFingerprint( + opcodes = listOf( + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT, + Opcode.IPUT + ), + filterBarHeightId +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/fingerprints/LiteralOpcodesFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/fingerprints/LiteralOpcodesFingerprint.kt new file mode 100644 index 000000000..7b7d6a9fb --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/fingerprints/LiteralOpcodesFingerprint.kt @@ -0,0 +1,19 @@ +package app.revanced.patches.youtube.layout.hide.filterbar.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.Opcode +import org.jf.dexlib2.iface.instruction.WideLiteralInstruction + + +abstract class LiteralOpcodesFingerprint(opcodes: List, literal: Long) : MethodFingerprint( + opcodes = opcodes, + customFingerprint = { + it.implementation?.instructions?.any { instruction -> + if (instruction.opcode != Opcode.CONST) return@any false + + val wideLiteral = (instruction as WideLiteralInstruction).wideLiteral + + literal == wideLiteral + } ?: false + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/fingerprints/RelatedChipCloudFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/fingerprints/RelatedChipCloudFingerprint.kt new file mode 100644 index 000000000..be0ef5cee --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/fingerprints/RelatedChipCloudFingerprint.kt @@ -0,0 +1,13 @@ +package app.revanced.patches.youtube.layout.hide.filterbar.fingerprints + +import app.revanced.patches.youtube.layout.hide.filterbar.patch.HideFilterBarResourcePatch.Companion.relatedChipCloudMarginId +import org.jf.dexlib2.Opcode + +object RelatedChipCloudFingerprint : LiteralOpcodesFingerprint( + opcodes = listOf( + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT + ), + relatedChipCloudMarginId +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/fingerprints/SearchResultsChipBarFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/fingerprints/SearchResultsChipBarFingerprint.kt new file mode 100644 index 000000000..82deee685 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/fingerprints/SearchResultsChipBarFingerprint.kt @@ -0,0 +1,15 @@ +package app.revanced.patches.youtube.layout.hide.filterbar.fingerprints + +import app.revanced.patches.youtube.layout.hide.filterbar.patch.HideFilterBarResourcePatch.Companion.barContainerHeightId +import org.jf.dexlib2.Opcode + +object SearchResultsChipBarFingerprint : LiteralOpcodesFingerprint( + opcodes = listOf( + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT + ), + barContainerHeightId +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/patch/HideFilterBarPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/patch/HideFilterBarPatch.kt new file mode 100644 index 000000000..ea69ddbe3 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/patch/HideFilterBarPatch.kt @@ -0,0 +1,87 @@ +package app.revanced.patches.youtube.layout.hide.filterbar.patch + +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.addInstructions +import app.revanced.patcher.extensions.instruction +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patches.youtube.layout.hide.filterbar.annotations.HideFilterBar +import app.revanced.patches.youtube.layout.hide.filterbar.fingerprints.FilterBarHeightFingerprint +import app.revanced.patches.youtube.layout.hide.filterbar.fingerprints.RelatedChipCloudFingerprint +import app.revanced.patches.youtube.layout.hide.filterbar.fingerprints.SearchResultsChipBarFingerprint +import org.jf.dexlib2.iface.instruction.OneRegisterInstruction +import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction + +@Patch +@Name("hide-filter-bar") +@Description("Hides the filter bar in video feeds.") +@DependsOn([HideFilterBarResourcePatch::class]) +@HideFilterBar +@Version("0.0.1") +class HideFilterBarPatch : BytecodePatch( + listOf( + RelatedChipCloudFingerprint, + SearchResultsChipBarFingerprint, + FilterBarHeightFingerprint + ) +) { + override fun execute(context: BytecodeContext): PatchResult { + FilterBarHeightFingerprint.patch { register -> + """ + invoke-static { v$register }, $INTEGRATIONS_CLASS_DESCRIPTOR->hideInFeed(I)I + move-result v$register + """ + } + + RelatedChipCloudFingerprint.patch(1) { register -> + "invoke-static { v$register }, " + + "$INTEGRATIONS_CLASS_DESCRIPTOR->hideInRelatedVideos(Landroid/view/View;)V" + } + + SearchResultsChipBarFingerprint.patch(-1, -2) { register -> + """ + invoke-static { v$register }, $INTEGRATIONS_CLASS_DESCRIPTOR->hideInSearch(I)I + move-result v$register + """ + } + + return PatchResultSuccess() + } + + private companion object { + const val INTEGRATIONS_CLASS_DESCRIPTOR = + "Lapp/revanced/integrations/patches/HideFilterBarPatch;" + + /** + * Patch a [MethodFingerprint] with a given [instructions]. + * + * @param RegisterInstruction The type of instruction to get the register from. + * @param insertIndexOffset The offset to add to the end index of the [MethodFingerprint]. + * @param hookRegisterOffset The offset to add to the register of the hook. + * @param instructions The instructions to add with the register as a parameter. + */ + private fun MethodFingerprint.patch( + insertIndexOffset: Int = 0, + hookRegisterOffset: Int = 0, + instructions: (Int) -> String + ) = + result?.let { + it.mutableMethod.apply { + val endIndex = it.scanResult.patternScanResult!!.endIndex + + val insertIndex = endIndex + insertIndexOffset + val register = instruction(endIndex + hookRegisterOffset).registerA + + addInstructions(insertIndex, instructions(register)) + } + } ?: throw toErrorResult() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/patch/HideFilterBarResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/patch/HideFilterBarResourcePatch.kt new file mode 100644 index 000000000..963104068 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/patch/HideFilterBarResourcePatch.kt @@ -0,0 +1,94 @@ +package app.revanced.patches.youtube.layout.hide.filterbar.patch + +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch +import app.revanced.patches.shared.settings.preference.impl.PreferenceScreen +import app.revanced.patches.shared.settings.preference.impl.StringResource +import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch + +@DependsOn([SettingsPatch::class, ResourceMappingPatch::class]) +@Version("0.0.1") +class HideFilterBarResourcePatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( + PreferenceScreen( + "revanced_hide_filter_bar_preference", + StringResource( + "revanced_hide_filter_bar_preference_title", + "Hide filter bar" + ), + listOf( + SwitchPreference( + "revanced_hide_filter_bar_feed_in_feed", + StringResource( + "revanced_hide_filter_bar_feed_in_feed_title", + "Hide in feed" + ), + false, + StringResource( + "revanced_hide_filter_bar_feed_in_feed_summary_on", + "Hidden in feed" + ), + StringResource( + "revanced_hide_filter_bar_feed_in_feed_summary_off", + "Shown in feed" + ) + ), + SwitchPreference( + "revanced_hide_filter_bar_feed_in_search", + StringResource( + "revanced_hide_filter_bar_feed_in_search_title", + "Hide in search" + ), + false, + StringResource( + "revanced_hide_filter_bar_feed_in_search_summary_on", + "Hidden in search" + ), + StringResource( + "revanced_hide_filter_bar_feed_in_search_summary_off", + "Shown in search" + ) + ), + SwitchPreference( + "revanced_hide_filter_bar_feed_in_related_videos", + StringResource( + "revanced_hide_filter_bar_feed_in_related_videos_title", + "Hide in related videos" + ), + false, + StringResource( + "revanced_hide_filter_bar_feed_in_related_videos_summary_on", + "Hidden in related videos" + ), + StringResource( + "revanced_hide_filter_bar_feed_in_related_videos_summary_off", + "Shown in related videos" + ) + ), + ), + ) + ) + + relatedChipCloudMarginId = "related_chip_cloud_reduced_margins".layoutResourceId("layout") + filterBarHeightId = "filter_bar_height".layoutResourceId() + barContainerHeightId = "bar_container_height".layoutResourceId() + + return PatchResultSuccess() + } + + internal companion object { + var filterBarHeightId = -1L + var relatedChipCloudMarginId = -1L + var barContainerHeightId = -1L + + private fun String.layoutResourceId(type: String = "dimen") = + ResourceMappingPatch.resourceMappings.single { it.type == type && it.name == this }.id + } +} \ No newline at end of file