feat(youtube): add hide-shorts-components patch

This commit is contained in:
oSumAtrIX
2023-05-18 19:06:05 +02:00
parent acb9b5fe6b
commit af82eb633c
14 changed files with 265 additions and 176 deletions
@@ -21,4 +21,4 @@ import app.revanced.patcher.annotation.Package
)]
)
@Target(AnnotationTarget.CLASS)
internal annotation class CommentsCompatibility
internal annotation class HideCommentsCompatibility
@@ -1,17 +0,0 @@
package app.revanced.patches.youtube.layout.hide.comments.bytecode.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.youtube.layout.hide.comments.resource.patch.CommentsResourcePatch
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
object ShortsCommentsButtonFingerprint : MethodFingerprint(
"V", AccessFlags.PRIVATE or AccessFlags.FINAL, listOf("Z", "Z", "L"),
customFingerprint = { methodDef, _ ->
methodDef.implementation?.instructions?.any {
it.opcode.ordinal == Opcode.CONST.ordinal && (it as WideLiteralInstruction).wideLiteral == CommentsResourcePatch.shortsCommentsButtonId
} == true
}
)
@@ -1,75 +0,0 @@
package app.revanced.patches.youtube.layout.hide.comments.bytecode.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.fingerprint.method.impl.MethodFingerprint.Companion.resolve
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.comments.annotations.CommentsCompatibility
import app.revanced.patches.youtube.layout.hide.comments.bytecode.fingerprints.ShortsCommentsButtonFingerprint
import app.revanced.patches.youtube.layout.hide.comments.resource.patch.CommentsResourcePatch
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
@Patch
@DependsOn([IntegrationsPatch::class, CommentsResourcePatch::class])
@Name("comments")
@Description("Hides components related to comments.")
@CommentsCompatibility
@Version("0.0.1")
class CommentsPatch : BytecodePatch(
listOf(
ShortsCommentsButtonFingerprint
)
) {
override fun execute(context: BytecodeContext): PatchResult {
val checkCastAnchorFingerprint = object : MethodFingerprint(
opcodes = listOf(
Opcode.CONST,
Opcode.CONST_HIGH16,
Opcode.IF_EQZ,
Opcode.CONST,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CHECK_CAST,
)
) {}
ShortsCommentsButtonFingerprint.result?.let {
it.mutableMethod.apply {
val checkCastAnchorIndex = checkCastAnchorFingerprint.also { result ->
if (!result.resolve(context, this, it.classDef))
throw checkCastAnchorFingerprint.toErrorResult()
}.result!!.scanResult.patternScanResult!!.endIndex
val shortsCommentsButtonRegister = instruction<OneRegisterInstruction>(checkCastAnchorIndex).registerA
val insertIndex = checkCastAnchorIndex + 1
addInstructions(
insertIndex,
"""
invoke-static { v$shortsCommentsButtonRegister }, $FILTER_METHOD_DESCRIPTOR
"""
)
}
} ?: return ShortsCommentsButtonFingerprint.toErrorResult()
return PatchResultSuccess()
}
private companion object {
private const val FILTER_METHOD_DESCRIPTOR =
"Lapp/revanced/integrations/patches/HideShortsCommentsButtonPatch;" +
"->hideShortsCommentsButton(Landroid/view/View;)V"
}
}
@@ -1,5 +1,6 @@
package app.revanced.patches.youtube.layout.hide.comments.resource.patch
package app.revanced.patches.youtube.layout.hide.comments.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.ResourceContext
@@ -7,22 +8,21 @@ 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.patcher.patch.annotations.Patch
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.layout.hide.comments.annotations.CommentsCompatibility
import app.revanced.patches.youtube.layout.hide.comments.annotations.HideCommentsCompatibility
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
@Name("comments-resource-patch")
@CommentsCompatibility
@Patch
@Name("comments")
@Description("Hides components related to comments.")
@HideCommentsCompatibility
@DependsOn([SettingsPatch::class, ResourceMappingPatch::class])
@Version("0.0.1")
class CommentsResourcePatch : ResourcePatch {
companion object {
internal var shortsCommentsButtonId: Long = -1
}
class CommentsPatch : ResourcePatch {
override fun execute(context: ResourceContext): PatchResult {
SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(
PreferenceScreen(
@@ -40,22 +40,12 @@ class CommentsResourcePatch : ResourcePatch {
StringResource("revanced_hide_preview_comment_title", "Hide preview comment"),
StringResource("revanced_hide_preview_comment_on", "Preview comment is hidden"),
StringResource("revanced_hide_preview_comment_off", "Preview comment is shown")
),
SwitchPreference(
"revanced_hide_shorts_comments_button",
StringResource("revanced_hide_shorts_comments_button_title", "Hide shorts comments button"),
StringResource("revanced_hide_shorts_comments_button_on", "Shorts comments button is hidden"),
StringResource("revanced_hide_shorts_comments_button_off", "Shorts comments button is shown")
),
)
),
StringResource("revanced_comments_preference_screen_summary", "Manage the visibility of comments section components")
)
)
shortsCommentsButtonId = ResourceMappingPatch.resourceMappings.single {
it.type == "drawable" && it.name == "ic_right_comment_32c"
}.id
return PatchResultSuccess()
}
}
@@ -0,0 +1,8 @@
package app.revanced.patches.youtube.layout.hide.shorts.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 HideShortsComponentsCompatibility
@@ -0,0 +1,19 @@
package app.revanced.patches.youtube.layout.hide.shorts.bytecode.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.youtube.layout.hide.shorts.resource.patch.HideShortsComponentsResourcePatch
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
object CreateShortsButtonsFingerprint : MethodFingerprint(
parameters = listOf("Z", "Z", "L"),
customFingerprint = { methodDef, _ ->
methodDef.implementation?.instructions?.any {
if (it.opcode != Opcode.CONST) return@any false
val literal = (it as WideLiteralInstruction).wideLiteral
literal == HideShortsComponentsResourcePatch.reelPlayerRightLargeIconSize
} ?: false
}
)
@@ -0,0 +1,19 @@
package app.revanced.patches.youtube.layout.hide.shorts.bytecode.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.youtube.layout.hide.shorts.resource.patch.HideShortsComponentsResourcePatch
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
object ReelConstructorFingerprint : MethodFingerprint(
opcodes = listOf(Opcode.INVOKE_VIRTUAL),
customFingerprint = { method, _ ->
method.implementation?.instructions?.any {
if (it.opcode != Opcode.CONST) return@any false
val literal = (it as WideLiteralInstruction).wideLiteral
literal == HideShortsComponentsResourcePatch.reelMultipleItemShelfId
} ?: false
}
)
@@ -0,0 +1,93 @@
package app.revanced.patches.youtube.layout.hide.shorts.bytecode.patch
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.instruction
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.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.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.TwoRegisterInstruction
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
@Patch
@DependsOn(
[
IntegrationsPatch::class,
LithoFilterPatch::class,
HideShortsComponentsResourcePatch::class,
ResourceMappingPatch::class
]
)
@Name("hide-shorts-components")
@Description("Hides components from YouTube Shorts.")
@HideShortsComponentsCompatibility
@Version("0.0.1")
class HideShortsComponentsPatch : BytecodePatch(listOf(CreateShortsButtonsFingerprint, ReelConstructorFingerprint)) {
override fun execute(context: BytecodeContext): PatchResult {
// Hide the Shorts shelf.
ReelConstructorFingerprint.result?.let {
it.mutableMethod.apply {
val insertIndex = it.scanResult.patternScanResult!!.startIndex + 2
val viewRegister = instruction<TwoRegisterInstruction>(insertIndex).registerA
injectHideViewCall(
insertIndex,
viewRegister,
CLASS_DESCRIPTOR,
"hideShortsShelf"
)
}
} ?: return ReelConstructorFingerprint.toErrorResult()
// 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()
return PatchResultSuccess()
}
private companion object {
private const val CLASS_DESCRIPTOR = "Lapp/revanced/integrations/patches/components/ShortsFilter;"
private enum class ShortsButtons(private val resourceName: String, private val methodName: String) {
COMMENTS("reel_dyn_comment", "hideShortsCommentsButton"),
REMIX("reel_dyn_remix", "hideShortsRemixButton"),
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 setIdIndex = referencedIndex + 1
val viewRegister = method.instruction<FiveRegisterInstruction>(setIdIndex).registerC
method.injectHideViewCall(setIdIndex, viewRegister, CLASS_DESCRIPTOR, methodName)
}
}
}
}
@@ -0,0 +1,89 @@
package app.revanced.patches.youtube.layout.hide.shorts.resource.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 HideShortsComponentsResourcePatch : ResourcePatch {
override fun execute(context: ResourceContext): PatchResult {
SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(
PreferenceScreen(
"revanced_shorts",
StringResource("revanced_shorts_title", "Shorts components"),
listOf(
SwitchPreference(
"revanced_hide_shorts",
StringResource("revanced_hide_shorts_enabled_title", "Hide shorts"),
StringResource("revanced_hide_shorts_on", "Shorts are hidden"),
StringResource("revanced_hide_shorts_off", "Shorts are shown")
),
SwitchPreference(
"revanced_hide_shorts_join_button",
StringResource("revanced_hide_shorts_join_button_title", "Hide join button"),
StringResource("revanced_hide_shorts_join_button_on", "Join button is hidden"),
StringResource("revanced_hide_shorts_join_button_off", "Join button is shown")
),
SwitchPreference(
"revanced_hide_shorts_subscribe_button",
StringResource("revanced_hide_shorts_subscribe_button_title", "Hide subscribe button"),
StringResource("revanced_hide_shorts_subscribe_button_on", "Subscribe button is hidden"),
StringResource("revanced_hide_shorts_subscribe_button_off", "Subscribe button is shown")
),
SwitchPreference(
"revanced_hide_shorts_thanks_button",
StringResource("revanced_hide_shorts_thanks_button_title", "Hide thanks button"),
StringResource("revanced_hide_shorts_thanks_button_on", "Thanks button is hidden"),
StringResource("revanced_hide_shorts_thanks_button_off", "Thanks button is shown")
),
SwitchPreference(
"revanced_hide_shorts_comments_button",
StringResource("revanced_hide_shorts_comments_button_title", "Hide comments button"),
StringResource("revanced_hide_shorts_comments_button_on", "Comments button is hidden"),
StringResource("revanced_hide_shorts_comments_button_off", "Comments button is shown")
),
SwitchPreference(
"revanced_hide_shorts_remix_button",
StringResource("revanced_hide_shorts_remix_button_title", "Hide remix button"),
StringResource("revanced_hide_shorts_remix_button_on", "Remix button is hidden"),
StringResource("revanced_hide_shorts_remix_button_off", "Remix button is shown")
),
SwitchPreference(
"revanced_hide_shorts_share_button",
StringResource("revanced_hide_shorts_share_button_title", "Hide share button"),
StringResource("revanced_hide_shorts_share_button_on", "Share button is hidden"),
StringResource("revanced_hide_shorts_share_button_off", "Share button is shown")
),
SwitchPreference(
"revanced_hide_shorts_navigation_bar",
StringResource("revanced_hide_shorts_navigation_bar_title", "Hide navigation bar"),
StringResource("revanced_hide_shorts_navigation_bar_on", "Navigation bar is hidden"),
StringResource("revanced_hide_shorts_navigation_bar_off", "Navigation bar is shown")
),
),
StringResource("revanced_shorts_summary", "Manage the visibility of Shorts components")
)
)
fun String.getId() = ResourceMappingPatch.resourceMappings.single { it.name == this }.id
reelMultipleItemShelfId = "reel_multiple_items_shelf".getId()
reelPlayerRightLargeIconSize = "reel_player_right_large_icon_size".getId()
return PatchResultSuccess()
}
companion object {
var reelMultipleItemShelfId: Long = -1
var reelPlayerRightLargeIconSize = -1L
}
}