feat(YouTube - Description components): Remove Title in video description panel setting (No more necessary)

This commit is contained in:
inotia00
2025-02-10 17:16:40 +09:00
parent d1154db77e
commit 37e5a48665
15 changed files with 200 additions and 256 deletions

View File

@ -14,7 +14,6 @@ import app.revanced.patches.shared.mainactivity.onCreateMethod
import app.revanced.patches.youtube.utils.bottomsheet.bottomSheetHookPatch
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
import app.revanced.patches.youtube.utils.engagement.engagementPanelHookPatch
import app.revanced.patches.youtube.utils.engagement.hookEngagementPanelState
import app.revanced.patches.youtube.utils.extension.Constants.COMPONENTS_PATH
import app.revanced.patches.youtube.utils.extension.Constants.FEED_CLASS_DESCRIPTOR
import app.revanced.patches.youtube.utils.extension.Constants.FEED_PATH
@ -190,8 +189,6 @@ val feedComponentsPatch = bytecodePatch(
}
}
hookEngagementPanelState(RELATED_VIDEO_CLASS_DESCRIPTOR)
// endregion
// region patch for hide subscriptions channel section for tablet

View File

@ -2,14 +2,12 @@
package app.revanced.patches.youtube.player.components
import app.revanced.patches.youtube.utils.resourceid.componentLongClickListener
import app.revanced.patches.youtube.utils.resourceid.darkBackground
import app.revanced.patches.youtube.utils.resourceid.donationCompanion
import app.revanced.patches.youtube.utils.resourceid.easySeekEduContainer
import app.revanced.patches.youtube.utils.resourceid.endScreenElementLayoutCircle
import app.revanced.patches.youtube.utils.resourceid.endScreenElementLayoutIcon
import app.revanced.patches.youtube.utils.resourceid.endScreenElementLayoutVideo
import app.revanced.patches.youtube.utils.resourceid.offlineActionsVideoDeletedUndoSnackbarText
import app.revanced.patches.youtube.utils.resourceid.scrubbing
import app.revanced.patches.youtube.utils.resourceid.seekEasyHorizontalTouchOffsetToStartScrubbing
import app.revanced.patches.youtube.utils.resourceid.suggestedAction
@ -209,30 +207,6 @@ internal val layoutVideoFingerprint = legacyFingerprint(
literals = listOf(endScreenElementLayoutVideo),
)
internal val lithoComponentOnClickListenerFingerprint = legacyFingerprint(
name = "lithoComponentOnClickListenerFingerprint",
returnType = "V",
accessFlags = AccessFlags.PRIVATE or AccessFlags.STATIC,
parameters = listOf("L"),
literals = listOf(componentLongClickListener),
)
internal val engagementPanelPlaylistSyntheticFingerprint = legacyFingerprint(
name = "engagementPanelPlaylistSyntheticFingerprint",
strings = listOf("engagement-panel-playlist"),
customFingerprint = { _, classDef ->
classDef.interfaces.contains("Landroid/view/View${'$'}OnClickListener;")
}
)
internal val offlineActionsOnClickListenerFingerprint = legacyFingerprint(
name = "offlineActionsOnClickListenerFingerprint",
returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("Ljava/lang/String;"),
literals = listOf(offlineActionsVideoDeletedUndoSnackbarText),
)
internal val quickSeekOverlayFingerprint = legacyFingerprint(
name = "quickSeekOverlayFingerprint",
returnType = "V",

View File

@ -13,10 +13,13 @@ import app.revanced.patches.shared.litho.addLithoFilter
import app.revanced.patches.shared.litho.lithoFilterPatch
import app.revanced.patches.shared.spans.addSpanFilter
import app.revanced.patches.shared.spans.inclusiveSpanPatch
import app.revanced.patches.shared.startVideoInformerFingerprint
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
import app.revanced.patches.youtube.utils.controlsoverlay.controlsOverlayConfigPatch
import app.revanced.patches.youtube.utils.engagementPanelBuilderFingerprint
import app.revanced.patches.youtube.utils.engagement.engagementPanelBuilderMethod
import app.revanced.patches.youtube.utils.engagement.engagementPanelFreeRegister
import app.revanced.patches.youtube.utils.engagement.engagementPanelHookPatch
import app.revanced.patches.youtube.utils.engagement.engagementPanelIdIndex
import app.revanced.patches.youtube.utils.engagement.engagementPanelIdRegister
import app.revanced.patches.youtube.utils.extension.Constants.COMPONENTS_PATH
import app.revanced.patches.youtube.utils.extension.Constants.PLAYER_CLASS_DESCRIPTOR
import app.revanced.patches.youtube.utils.extension.Constants.SPANS_PATH
@ -39,7 +42,6 @@ import app.revanced.patches.youtube.utils.youtubeControlsOverlayFingerprint
import app.revanced.patches.youtube.video.information.hookVideoInformation
import app.revanced.patches.youtube.video.information.videoInformationPatch
import app.revanced.util.REGISTER_TEMPLATE_REPLACEMENT
import app.revanced.util.Utils.printWarn
import app.revanced.util.findMethodOrThrow
import app.revanced.util.fingerprint.injectLiteralInstructionBooleanCall
import app.revanced.util.fingerprint.injectLiteralInstructionViewCall
@ -49,7 +51,6 @@ import app.revanced.util.fingerprint.mutableClassOrThrow
import app.revanced.util.fingerprint.resolvable
import app.revanced.util.getReference
import app.revanced.util.getWalkerMethod
import app.revanced.util.indexOfFirstInstruction
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
import app.revanced.util.indexOfFirstLiteralInstructionOrThrow
@ -286,6 +287,7 @@ val playerComponentsPatch = bytecodePatch(
suggestedVideoEndScreenPatch,
videoInformationPatch,
versionCheckPatch,
engagementPanelHookPatch,
)
execute {
@ -373,54 +375,19 @@ val playerComponentsPatch = bytecodePatch(
// region patch for disable auto player popup panels
fun MutableMethod.hookInitVideoPanel(initVideoPanel: Int) =
addInstructions(
0, """
const/4 v0, $initVideoPanel
invoke-static {v0}, $PLAYER_CLASS_DESCRIPTOR->setInitVideoPanel(Z)V
"""
)
arrayOf(
lithoComponentOnClickListenerFingerprint,
offlineActionsOnClickListenerFingerprint,
).forEach { fingerprint ->
fingerprint.methodOrThrow().apply {
val syntheticIndex =
indexOfFirstInstruction(Opcode.NEW_INSTANCE)
if (syntheticIndex >= 0) {
val syntheticReference =
getInstruction<ReferenceInstruction>(syntheticIndex).reference.toString()
findMethodOrThrow(syntheticReference) {
name == "onClick"
}.hookInitVideoPanel(0)
} else {
printWarn("target Opcode not found in ${fingerprint.first}")
}
}
}
findMethodOrThrow(
engagementPanelPlaylistSyntheticFingerprint.methodOrThrow().definingClass
) {
name == "onClick"
}.hookInitVideoPanel(0)
startVideoInformerFingerprint.methodOrThrow().hookInitVideoPanel(1)
engagementPanelBuilderFingerprint.methodOrThrow().apply {
addInstructionsWithLabels(
0, """
move/from16 v0, p4
invoke-static {v0}, $PLAYER_CLASS_DESCRIPTOR->disableAutoPlayerPopupPanels(Z)Z
move-result v0
if-eqz v0, :shown
const/4 v0, 0x0
return-object v0
""", ExternalLabel("shown", getInstruction(0))
)
}
engagementPanelBuilderMethod.addInstructionsWithLabels(
engagementPanelIdIndex, """
move/from16 v$engagementPanelFreeRegister, p4
invoke-static {v$engagementPanelFreeRegister, v$engagementPanelIdRegister}, $PLAYER_CLASS_DESCRIPTOR->disableAutoPlayerPopupPanels(ZLjava/lang/String;)Z
move-result v$engagementPanelFreeRegister
if-eqz v$engagementPanelFreeRegister, :shown
const/4 v$engagementPanelFreeRegister, 0x0
return-object v$engagementPanelFreeRegister
:shown
nop
"""
)
hookVideoInformation("$PLAYER_CLASS_DESCRIPTOR->disableAutoPlayerPopupPanels(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;JZ)V")
// endregion

View File

@ -9,6 +9,7 @@ import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.shared.litho.addLithoFilter
import app.revanced.patches.shared.litho.lithoFilterPatch
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
import app.revanced.patches.youtube.utils.engagement.engagementPanelHookPatch
import app.revanced.patches.youtube.utils.extension.Constants.COMPONENTS_PATH
import app.revanced.patches.youtube.utils.extension.Constants.PLAYER_CLASS_DESCRIPTOR
import app.revanced.patches.youtube.utils.patch.PatchList.DESCRIPTION_COMPONENTS
@ -46,6 +47,7 @@ val descriptionComponentsPatch = bytecodePatch(
lithoFilterPatch,
playerTypeHookPatch,
recyclerViewTreeObserverPatch,
engagementPanelHookPatch,
sharedResourceIdPatch,
versionCheckPatch,
)
@ -104,19 +106,6 @@ val descriptionComponentsPatch = bytecodePatch(
)
}
engagementPanelTitleFingerprint.methodOrThrow(engagementPanelTitleParentFingerprint)
.apply {
val contentDescriptionIndex = indexOfContentDescriptionInstruction(this)
val contentDescriptionRegister =
getInstruction<FiveRegisterInstruction>(contentDescriptionIndex).registerD
addInstruction(
contentDescriptionIndex,
"invoke-static {v$contentDescriptionRegister}," +
"$PLAYER_CLASS_DESCRIPTOR->setContentDescription(Ljava/lang/String;)V"
)
}
recyclerViewTreeObserverHook("$PLAYER_CLASS_DESCRIPTOR->onVideoDescriptionCreate(Landroid/support/v7/widget/RecyclerView;)V")
settingArray += "SETTINGS: DESCRIPTION_INTERACTION"

View File

@ -3,30 +3,10 @@ package app.revanced.patches.youtube.player.descriptions
import app.revanced.util.fingerprint.legacyFingerprint
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
import app.revanced.util.indexOfFirstInstructionReversed
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
internal val engagementPanelTitleFingerprint = legacyFingerprint(
name = "engagementPanelTitleFingerprint",
strings = listOf(". "),
customFingerprint = { method, _ ->
indexOfContentDescriptionInstruction(method) >= 0
}
)
internal val engagementPanelTitleParentFingerprint = legacyFingerprint(
name = "engagementPanelTitleParentFingerprint",
strings = listOf("[EngagementPanelTitleHeader] Cannot remove action buttons from header as the child count is out of sync. Buttons to remove exceed current header child count.")
)
internal fun indexOfContentDescriptionInstruction(method: Method) =
method.indexOfFirstInstructionReversed {
opcode == Opcode.INVOKE_VIRTUAL &&
getReference<MethodReference>()?.name == "setContentDescription"
}
/**
* This fingerprint is compatible with YouTube v18.35.xx~
* Nonetheless, the patch works in YouTube v19.02.xx~

View File

@ -1,24 +1,30 @@
package app.revanced.patches.youtube.utils.engagement
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.util.proxy.mutableTypes.MutableMethod
import app.revanced.patches.youtube.utils.engagementPanelBuilderFingerprint
import app.revanced.patches.youtube.utils.extension.Constants.SHARED_PATH
import app.revanced.patches.youtube.utils.resourceid.sharedResourceIdPatch
import app.revanced.util.fingerprint.matchOrThrow
import app.revanced.util.findMethodOrThrow
import app.revanced.util.fingerprint.methodOrThrow
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionReversed
import app.revanced.util.indexOfFirstInstruction
import app.revanced.util.indexOfFirstInstructionOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
import com.android.tools.smali.dexlib2.util.MethodUtil
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
private lateinit var engagementPanelBuilderMethod: MutableMethod
private lateinit var hideEngagementPanelMethod: MutableMethod
private var showEngagementPanelMethods = mutableListOf<MutableMethod>()
private const val EXTENSION_CLASS_DESCRIPTOR =
"$SHARED_PATH/EngagementPanel;"
internal lateinit var engagementPanelBuilderMethod: MutableMethod
internal var engagementPanelFreeRegister = 0
internal var engagementPanelIdIndex = 0
internal var engagementPanelIdRegister = 0
val engagementPanelHookPatch = bytecodePatch(
description = "engagementPanelHookPatch"
@ -26,45 +32,66 @@ val engagementPanelHookPatch = bytecodePatch(
dependsOn(sharedResourceIdPatch)
execute {
engagementPanelBuilderFingerprint.matchOrThrow().let {
engagementPanelBuilderMethod = it.method
fun Method.setFreeIndex(startIndex: Int) {
val startRegister = engagementPanelIdRegister
var index = startIndex
var register = startRegister
it.classDef.methods.filter { method ->
method.indexOfEngagementPanelBuilderInstruction() >= 0
}.forEach { method ->
showEngagementPanelMethods.add(method)
while (register == startRegister) {
index = indexOfFirstInstruction(index + 1, Opcode.IGET_OBJECT)
register = getInstruction<TwoRegisterInstruction>(index).registerA
}
engagementPanelFreeRegister = register
}
hideEngagementPanelMethod =
engagementPanelUpdateFingerprint.methodOrThrow(engagementPanelBuilderFingerprint)
}
}
val engagementPanelInfoClass = engagementPanelLayoutFingerprint
.methodOrThrow()
.parameters[0]
.toString()
private fun Method.indexOfEngagementPanelBuilderInstruction() =
indexOfFirstInstructionReversed {
opcode == Opcode.INVOKE_DIRECT &&
MethodUtil.methodSignaturesMatch(
engagementPanelBuilderMethod,
getReference<MethodReference>()!!
val (engagementPanelIdReference, engagementPanelObjectReference) =
with(findMethodOrThrow(engagementPanelInfoClass)) {
val engagementPanelIdIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.IPUT_OBJECT &&
getReference<FieldReference>()?.type == "Ljava/lang/String;"
}
val engagementPanelObjectIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.IPUT_OBJECT &&
getReference<FieldReference>()?.type != "Ljava/lang/String;"
}
Pair(
getInstruction<ReferenceInstruction>(engagementPanelIdIndex).reference.toString(),
getInstruction<ReferenceInstruction>(engagementPanelObjectIndex).reference.toString(),
)
}
}
internal fun hookEngagementPanelState(classDescriptor: String) {
showEngagementPanelMethods.forEach { method ->
method.apply {
val index = indexOfEngagementPanelBuilderInstruction()
val register = getInstruction<OneRegisterInstruction>(index + 1).registerA
engagementPanelBuilderFingerprint.methodOrThrow().apply {
val insertIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.IGET_OBJECT &&
getReference<FieldReference>()?.toString() == engagementPanelObjectReference
}
val insertInstruction = getInstruction<TwoRegisterInstruction>(insertIndex)
val classRegister = insertInstruction.registerB
engagementPanelIdRegister = insertInstruction.registerA
addInstruction(
index + 2,
"invoke-static {v$register}, $classDescriptor->showEngagementPanel(Ljava/lang/Object;)V"
setFreeIndex(insertIndex)
addInstructions(
insertIndex, """
iget-object v$engagementPanelIdRegister, v$classRegister, $engagementPanelIdReference
invoke-static {v$engagementPanelIdRegister}, $EXTENSION_CLASS_DESCRIPTOR->setId(Ljava/lang/String;)V
"""
)
engagementPanelIdIndex = insertIndex + 1
engagementPanelBuilderMethod = this
}
}
hideEngagementPanelMethod.addInstruction(
0,
"invoke-static {}, $classDescriptor->hideEngagementPanel()V"
)
}
engagementPanelUpdateFingerprint
.methodOrThrow(engagementPanelBuilderFingerprint)
.addInstruction(
0,
"invoke-static {}, $EXTENSION_CLASS_DESCRIPTOR->hide()V"
)
}
}

View File

@ -1,22 +0,0 @@
package app.revanced.patches.youtube.utils.engagement
import app.revanced.util.fingerprint.legacyFingerprint
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
import app.revanced.util.or
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
internal val engagementPanelUpdateFingerprint = legacyFingerprint(
name = "engagementPanelUpdateFingerprint",
returnType = "V",
accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL,
parameters = listOf("L", "Z"),
customFingerprint = { method, _ ->
method.indexOfFirstInstruction {
opcode == Opcode.INVOKE_VIRTUAL &&
getReference<MethodReference>().toString() == "Ljava/util/ArrayDeque;->pop()Ljava/lang/Object;"
} >= 0
}
)

View File

@ -0,0 +1,46 @@
package app.revanced.patches.youtube.utils.engagement
import app.revanced.util.fingerprint.legacyFingerprint
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
import app.revanced.util.or
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
internal val engagementPanelBuilderFingerprint = legacyFingerprint(
name = "engagementPanelBuilderFingerprint",
returnType = "L",
accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL,
parameters = listOf("L", "L", "Z", "Z"),
strings = listOf(
"EngagementPanelController: cannot show EngagementPanel before EngagementPanelController.init() has been called.",
"[EngagementPanel] Cannot show EngagementPanel before EngagementPanelController.init() has been called."
)
)
internal val engagementPanelLayoutFingerprint = legacyFingerprint(
name = "engagementPanelLayoutFingerprint",
returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("L", "L", "I"),
customFingerprint = { method, _ ->
method.indexOfFirstInstruction {
opcode == Opcode.INVOKE_VIRTUAL &&
getReference<MethodReference>().toString() == "Landroid/widget/FrameLayout;->indexOfChild(Landroid/view/View;)I"
} >= 0
}
)
internal val engagementPanelUpdateFingerprint = legacyFingerprint(
name = "engagementPanelUpdateFingerprint",
returnType = "V",
accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL,
parameters = listOf("L", "Z"),
customFingerprint = { method, _ ->
method.indexOfFirstInstruction {
opcode == Opcode.INVOKE_VIRTUAL &&
getReference<MethodReference>().toString() == "Ljava/util/ArrayDeque;->pop()Ljava/lang/Object;"
} >= 0
}
)

View File

@ -61,8 +61,6 @@ var compactLink = -1L
private set
var compactListItem = -1L
private set
var componentLongClickListener = -1L
private set
var contentPill = -1L
private set
var controlsLayoutStub = -1L
@ -145,8 +143,6 @@ var musicAppDeeplinkButtonView = -1L
private set
var notificationBigPictureIconWidth = -1L
private set
var offlineActionsVideoDeletedUndoSnackbarText = -1L
private set
var playerCollapseButton = -1L
private set
var playerControlPreviousButtonTouchArea = -1L
@ -352,10 +348,6 @@ internal val sharedResourceIdPatch = resourcePatch(
LAYOUT,
"compact_list_item"
]
componentLongClickListener = resourceMappings[
ID,
"component_long_click_listener"
]
contentPill = resourceMappings[
LAYOUT,
"content_pill"
@ -520,10 +512,6 @@ internal val sharedResourceIdPatch = resourcePatch(
DIMEN,
"notification_big_picture_icon_width"
]
offlineActionsVideoDeletedUndoSnackbarText = resourceMappings[
STRING,
"offline_actions_video_deleted_undo_snackbar_text"
]
playerCollapseButton = resourceMappings[
ID,
"player_collapse_button"