refactor(YouTube - Hide end screen suggested video): Use more idiomatic APIs

This commit is contained in:
oSumAtrIX 2026-03-07 23:35:17 +01:00
parent 11bd06d374
commit b826db02e3
No known key found for this signature in database
GPG key ID: A9B3094ACDB604B4
2 changed files with 74 additions and 34 deletions

View file

@ -1,14 +1,25 @@
package app.revanced.patches.youtube.layout.hide.endscreensuggestedvideo
import app.revanced.patcher.*
import app.revanced.patcher.extensions.instructions
import app.revanced.patcher.accessFlags
import app.revanced.patcher.definingClass
import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.extensions.methodReference
import app.revanced.patcher.firstMethodComposite
import app.revanced.patcher.instructions
import app.revanced.patcher.name
import app.revanced.patcher.parameterTypes
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.ClassDef
import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
internal val BytecodePatchContext.autoNavConstructorMethod by gettingFirstImmutableMethodDeclaratively("main_app_autonav") {
internal val BytecodePatchContext.autoNavConstructorMethod by gettingFirstImmutableMethodDeclaratively(
"main_app_autonav"
) {
returnType("V")
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
}
@ -24,15 +35,50 @@ internal val BytecodePatchContext.removeOnLayoutChangeListenerMethodMatch by com
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("V")
parameterTypes()
opcodes(
Opcode.IPUT,
Opcode.INVOKE_VIRTUAL,
instructions(
allOf(Opcode.IPUT(), field { type == "I" }),
afterAtMost(
3,
allOf(
Opcode.INVOKE_VIRTUAL(),
method { returnType == "V" && parameterTypes.isEmpty() }
)
),
allOf(Opcode.INVOKE_VIRTUAL(), method {
name == "removeOnLayoutChangeListener" &&
returnType == "Z" &&
definingClass == "Lcom/google/android/apps/youtube/app/common/" +
"player/overlay/YouTubePlayerOverlaysLayout;"
}),
)
// This is the only reference present in the entire smali.
custom {
instructions.anyInstruction {
val reference = methodReference
reference?.name == "removeOnLayoutChangeListener" && reference.definingClass.endsWith("/YouTubePlayerOverlaysLayout;")
}
}
internal fun BytecodePatchContext.getEndScreenSuggestedVideoMethodMatch(autoNavStatusMethod: Method): CompositeMatch {
val endScreenMethod = removeOnLayoutChangeListenerMethodMatch.let {
firstMethod(it.method.getInstruction<ReferenceInstruction>(it[1]).methodReference!!)
}
return firstMethodComposite {
name(endScreenMethod.name)
definingClass(endScreenMethod.definingClass)
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("V")
parameterTypes()
instructions(
allOf(
Opcode.IGET_OBJECT(),
field {
definingClass == endScreenMethod.definingClass &&
type == autoNavStatusMethod.definingClass
}
),
afterAtMost(
3,
allOf(
Opcode.INVOKE_VIRTUAL(),
method { this == autoNavStatusMethod }
)
),
)
}
}

View file

@ -2,8 +2,10 @@ package app.revanced.patches.youtube.layout.hide.endscreensuggestedvideo
import app.revanced.patcher.extensions.ExternalLabel
import app.revanced.patcher.extensions.addInstructionsWithLabels
import app.revanced.patcher.extensions.fieldReference
import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.extensions.methodReference
import app.revanced.patcher.firstMethod
import app.revanced.patcher.immutableClassDef
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.all.misc.resources.addResources
@ -11,9 +13,6 @@ import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
private const val EXTENSION_CLASS_DESCRIPTOR =
@ -41,32 +40,27 @@ val hideEndScreenSuggestedVideoPatch = bytecodePatch(
)
apply {
addResources("youtube", "layout.hide.endscreensuggestedvideo.hideEndScreenSuggestedVideoPatch")
addResources(
"youtube",
"layout.hide.endscreensuggestedvideo.hideEndScreenSuggestedVideoPatch"
)
PreferenceScreen.PLAYER.addPreferences(
SwitchPreference("revanced_end_screen_suggested_video"),
)
removeOnLayoutChangeListenerMethodMatch.let {
val endScreenMethod = navigate(it.immutableMethod).to(it[-1]).stop()
endScreenMethod.apply {
val autoNavStatusMethodName =
autoNavConstructorMethod.immutableClassDef.getAutoNavStatusMethod().name
val autoNavStatusMethod =
autoNavConstructorMethod.immutableClassDef.getAutoNavStatusMethod()
val invokeIndex = indexOfFirstInstructionOrThrow {
val reference = methodReference
reference?.name == autoNavStatusMethodName &&
reference.returnType == "Z" &&
reference.parameterTypes.isEmpty()
}
val endScreenMethod = removeOnLayoutChangeListenerMethodMatch.let {
firstMethod(it.method.getInstruction<ReferenceInstruction>(it[1]).methodReference!!)
}
val iGetObjectIndex =
indexOfFirstInstructionReversedOrThrow(invokeIndex, Opcode.IGET_OBJECT)
val invokeReference = getInstruction<ReferenceInstruction>(invokeIndex).reference
val iGetObjectReference =
getInstruction<ReferenceInstruction>(iGetObjectIndex).reference
val opcodeName = getInstruction(invokeIndex).opcode.name
getEndScreenSuggestedVideoMethodMatch(autoNavStatusMethod).let { match ->
match.method.apply {
val autoNavField = getInstruction(match[0]).fieldReference!!
addInstructionsWithLabels(
0,
@ -75,10 +69,10 @@ val hideEndScreenSuggestedVideoPatch = bytecodePatch(
move-result v0
if-eqz v0, :show_end_screen_recommendation
iget-object v0, p0, $iGetObjectReference
iget-object v0, p0, $autoNavField
# This reference checks whether autoplay is turned on.
$opcodeName { v0 }, $invokeReference
invoke-virtual { v0 }, $autoNavStatusMethod
move-result v0
# Hide suggested video end screen only when autoplay is turned off.