Skip to content

Commit

Permalink
chore(YouTube): move TextComponentPatch to a shared path
Browse files Browse the repository at this point in the history
  • Loading branch information
inotia00 committed Oct 12, 2024
1 parent b219e0d commit 4bc6303
Show file tree
Hide file tree
Showing 8 changed files with 180 additions and 142 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package app.revanced.patches.shared.textcomponent

import app.revanced.patcher.data.BytecodeContext
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.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patches.shared.textcomponent.fingerprints.SpannableStringBuilderFingerprint
import app.revanced.patches.shared.textcomponent.fingerprints.TextComponentConstructorFingerprint
import app.revanced.patches.shared.textcomponent.fingerprints.TextComponentContextFingerprint
import app.revanced.util.alsoResolve
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
import app.revanced.util.indexOfFirstInstructionOrThrow
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.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
import com.android.tools.smali.dexlib2.iface.reference.MethodReference

object TextComponentPatch : BytecodePatch(
setOf(
SpannableStringBuilderFingerprint,
TextComponentConstructorFingerprint,
)
) {
override fun execute(context: BytecodeContext) {

SpannableStringBuilderFingerprint.resultOrThrow().mutableMethod.apply {
spannedMethod = this
spannedIndex = SpannableStringBuilderFingerprint.indexOfSpannableStringInstruction(this)
spannedRegister = getInstruction<FiveRegisterInstruction>(spannedIndex).registerC
spannedContextRegister =
getInstruction<TwoRegisterInstruction>(0).registerA

replaceInstruction(
spannedIndex,
"nop"
)
addInstruction(
++spannedIndex,
"invoke-static {v$spannedRegister}, ${SpannableStringBuilderFingerprint.SPANNABLE_STRING_REFERENCE}"
)
}

TextComponentContextFingerprint.alsoResolve(
context, TextComponentConstructorFingerprint
).let {
it.mutableMethod.apply {
textComponentMethod = this
val conversionContextFieldIndex = indexOfFirstInstructionOrThrow {
getReference<FieldReference>()?.type == "Ljava/util/Map;"
} - 1
val conversionContextFieldReference =
getInstruction<ReferenceInstruction>(conversionContextFieldIndex).reference

// ~ YouTube 19.32.xx
val legacyCharSequenceIndex = indexOfFirstInstruction {
getReference<FieldReference>()?.type == "Ljava/util/BitSet;"
} - 1
val charSequenceIndex = indexOfFirstInstruction {
val reference = getReference<MethodReference>()
opcode == Opcode.INVOKE_VIRTUAL &&
reference?.returnType == "V" &&
reference.parameterTypes.firstOrNull() == "Ljava/lang/CharSequence;"
}

val insertIndex: Int

if (legacyCharSequenceIndex > -2) {
textComponentRegister =
getInstruction<TwoRegisterInstruction>(legacyCharSequenceIndex).registerA
insertIndex = legacyCharSequenceIndex - 1
} else if (charSequenceIndex > -1) {
textComponentRegister =
getInstruction<FiveRegisterInstruction>(charSequenceIndex).registerD
insertIndex = charSequenceIndex
} else {
throw PatchException("Could not find insert index")
}

textComponentContextRegister = getInstruction<TwoRegisterInstruction>(
indexOfFirstInstructionOrThrow(insertIndex, Opcode.IGET_OBJECT)
).registerA

addInstructions(
insertIndex, """
move-object/from16 v$textComponentContextRegister, p0
iget-object v$textComponentContextRegister, v$textComponentContextRegister, $conversionContextFieldReference
"""
)
textComponentIndex = insertIndex + 2
}
}
}

private lateinit var spannedMethod: MutableMethod
private var spannedIndex = 0
private var spannedRegister = 0
private var spannedContextRegister = 0

private lateinit var textComponentMethod: MutableMethod
private var textComponentIndex = 0
private var textComponentRegister = 0
private var textComponentContextRegister = 0

fun hookSpannableString(
classDescriptor: String,
methodName: String
) = spannedMethod.addInstructions(
spannedIndex, """
invoke-static {v$spannedContextRegister, v$spannedRegister}, $classDescriptor->$methodName(Ljava/lang/Object;Ljava/lang/CharSequence;)Ljava/lang/CharSequence;
move-result-object v$spannedRegister
"""
)

fun hookTextComponent(
classDescriptor: String,
methodName: String = "onLithoTextLoaded"
) = textComponentMethod.apply {
addInstructions(
textComponentIndex, """
invoke-static {v$textComponentContextRegister, v$textComponentRegister}, $classDescriptor->$methodName(Ljava/lang/Object;Ljava/lang/CharSequence;)Ljava/lang/CharSequence;
move-result-object v$textComponentRegister
"""
)
textComponentIndex += 2
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package app.revanced.patches.shared.textcomponent.fingerprints

import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patches.shared.textcomponent.fingerprints.SpannableStringBuilderFingerprint.indexOfSpannableStringInstruction
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
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 object SpannableStringBuilderFingerprint : MethodFingerprint(
returnType = "Ljava/lang/CharSequence;",
strings = listOf("Failed to set PB Style Run Extension in TextComponentSpec. Extension id: %s"),
customFingerprint = { methodDef, _ ->
indexOfSpannableStringInstruction(methodDef) >= 0
}
) {
const val SPANNABLE_STRING_REFERENCE =
"Landroid/text/SpannableString;->valueOf(Ljava/lang/CharSequence;)Landroid/text/SpannableString;"

fun indexOfSpannableStringInstruction(methodDef: Method) =
methodDef.indexOfFirstInstruction {
opcode == Opcode.INVOKE_STATIC &&
getReference<MethodReference>()?.toString() == SPANNABLE_STRING_REFERENCE
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package app.revanced.patches.youtube.utils.returnyoutubedislike.general.fingerprints
package app.revanced.patches.shared.textcomponent.fingerprints

import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package app.revanced.patches.youtube.utils.returnyoutubedislike.general.fingerprints
package app.revanced.patches.shared.textcomponent.fingerprints

import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.shared.litho.LithoFilterPatch
import app.revanced.patches.shared.textcomponent.TextComponentPatch
import app.revanced.patches.youtube.shorts.components.fingerprints.ShortsButtonFingerprint
import app.revanced.patches.youtube.shorts.components.fingerprints.ShortsPaidPromotionFingerprint
import app.revanced.patches.youtube.shorts.components.fingerprints.ShortsPausedHeaderFingerprint
import app.revanced.patches.youtube.shorts.components.fingerprints.ShortsPivotLegacyFingerprint
import app.revanced.patches.youtube.shorts.components.fingerprints.ShortsSubscriptionsTabletFingerprint
import app.revanced.patches.youtube.shorts.components.fingerprints.ShortsSubscriptionsTabletParentFingerprint
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
import app.revanced.patches.youtube.utils.fingerprints.TextComponentSpecFingerprint
import app.revanced.patches.youtube.utils.integrations.Constants.COMPONENTS_PATH
import app.revanced.patches.youtube.utils.integrations.Constants.SHORTS_CLASS_DESCRIPTOR
import app.revanced.patches.youtube.utils.integrations.Constants.UTILS_PATH
Expand All @@ -35,7 +35,6 @@ import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.Right
import app.revanced.patches.youtube.utils.settings.SettingsPatch
import app.revanced.patches.youtube.video.information.VideoInformationPatch
import app.revanced.util.REGISTER_TEMPLATE_REPLACEMENT
import app.revanced.util.getReference
import app.revanced.util.getWalkerMethod
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
Expand All @@ -44,7 +43,6 @@ import app.revanced.util.patch.BaseBytecodePatch
import app.revanced.util.replaceLiteralInstructionCall
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.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
Expand All @@ -65,7 +63,8 @@ object ShortsComponentPatch : BaseBytecodePatch(
ShortsRepeatPatch::class,
ShortsTimeStampPatch::class,
ShortsToolBarPatch::class,
VideoInformationPatch::class
TextComponentPatch::class,
VideoInformationPatch::class,
),
compatiblePackages = COMPATIBLE_PACKAGE,
fingerprints = setOf(
Expand All @@ -74,7 +73,6 @@ object ShortsComponentPatch : BaseBytecodePatch(
ShortsPausedHeaderFingerprint,
ShortsPivotLegacyFingerprint,
ShortsSubscriptionsTabletParentFingerprint,
TextComponentSpecFingerprint
)
) {
private const val INTEGRATION_CLASS_DESCRIPTOR =
Expand Down Expand Up @@ -324,29 +322,7 @@ object ShortsComponentPatch : BaseBytecodePatch(

// region patch for return shorts channel name

TextComponentSpecFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val insertIndex = indexOfFirstInstructionOrThrow {
getReference<MethodReference>()?.toString() == "Landroid/text/SpannableString;->valueOf(Ljava/lang/CharSequence;)Landroid/text/SpannableString;"
}
val charSequenceRegister =
getInstruction<FiveRegisterInstruction>(insertIndex).registerC
val conversionContextRegister =
getInstruction<TwoRegisterInstruction>(0).registerA

val replaceReference =
getInstruction<ReferenceInstruction>(insertIndex).reference

addInstructions(
insertIndex + 1, """
invoke-static {v$conversionContextRegister, v$charSequenceRegister}, $INTEGRATION_CLASS_DESCRIPTOR->onCharSequenceLoaded(Ljava/lang/Object;Ljava/lang/CharSequence;)Ljava/lang/CharSequence;
move-result-object v$charSequenceRegister
invoke-static {v$charSequenceRegister}, $replaceReference
"""
)
removeInstruction(insertIndex)
}
}
TextComponentPatch.hookSpannableString(INTEGRATION_CLASS_DESCRIPTOR, "onCharSequenceLoaded")

VideoInformationPatch.hookShorts("$INTEGRATION_CLASS_DESCRIPTOR->newShortsVideoStarted(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;JZ)V")

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,22 @@ package app.revanced.patches.youtube.utils.returnyoutubedislike.general

import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patcher.patch.PatchException
import app.revanced.patches.shared.litho.LithoFilterPatch
import app.revanced.patches.shared.textcomponent.TextComponentPatch
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
import app.revanced.patches.youtube.utils.integrations.Constants.COMPONENTS_PATH
import app.revanced.patches.youtube.utils.integrations.Constants.UTILS_PATH
import app.revanced.patches.youtube.utils.returnyoutubedislike.general.fingerprints.DislikeFingerprint
import app.revanced.patches.youtube.utils.returnyoutubedislike.general.fingerprints.LikeFingerprint
import app.revanced.patches.youtube.utils.returnyoutubedislike.general.fingerprints.RemoveLikeFingerprint
import app.revanced.patches.youtube.utils.returnyoutubedislike.general.fingerprints.TextComponentConstructorFingerprint
import app.revanced.patches.youtube.utils.returnyoutubedislike.general.fingerprints.TextComponentContextFingerprint
import app.revanced.patches.youtube.utils.returnyoutubedislike.rollingnumber.ReturnYouTubeDislikeRollingNumberPatch
import app.revanced.patches.youtube.utils.returnyoutubedislike.shorts.ReturnYouTubeDislikeShortsPatch
import app.revanced.patches.youtube.utils.settings.SettingsPatch
import app.revanced.patches.youtube.video.information.VideoInformationPatch
import app.revanced.patches.youtube.video.videoid.VideoIdPatch
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.patch.BaseBytecodePatch
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.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
import com.android.tools.smali.dexlib2.iface.reference.MethodReference

@Suppress("unused")
object ReturnYouTubeDislikePatch : BaseBytecodePatch(
Expand All @@ -40,14 +28,14 @@ object ReturnYouTubeDislikePatch : BaseBytecodePatch(
ReturnYouTubeDislikeRollingNumberPatch::class,
ReturnYouTubeDislikeShortsPatch::class,
SettingsPatch::class,
TextComponentPatch::class,
VideoInformationPatch::class
),
compatiblePackages = COMPATIBLE_PACKAGE,
fingerprints = setOf(
DislikeFingerprint,
LikeFingerprint,
RemoveLikeFingerprint,
TextComponentConstructorFingerprint
)
) {
private const val INTEGRATIONS_RYD_CLASS_DESCRIPTOR =
Expand All @@ -70,59 +58,7 @@ object ReturnYouTubeDislikePatch : BaseBytecodePatch(
)
}


TextComponentConstructorFingerprint.resultOrThrow().let { parentResult ->
// Resolves fingerprints
TextComponentContextFingerprint.resolve(context, parentResult.classDef)

TextComponentContextFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val conversionContextFieldIndex = indexOfFirstInstructionOrThrow {
getReference<FieldReference>()?.type == "Ljava/util/Map;"
} - 1
val conversionContextFieldReference =
getInstruction<ReferenceInstruction>(conversionContextFieldIndex).reference

val charSequenceIndex1932 = indexOfFirstInstruction {
getReference<FieldReference>()?.type == "Ljava/util/BitSet;"
} - 1
val charSequenceIndex1933 = indexOfFirstInstruction {
val reference = getReference<MethodReference>()
opcode == Opcode.INVOKE_VIRTUAL &&
reference?.returnType == "V" &&
reference.parameterTypes.firstOrNull() == "Ljava/lang/CharSequence;"
}

val insertIndex: Int
val charSequenceRegister: Int

if (charSequenceIndex1932 > -2) {
charSequenceRegister =
getInstruction<TwoRegisterInstruction>(charSequenceIndex1932).registerA
insertIndex = charSequenceIndex1932 - 1
} else if (charSequenceIndex1933 > -1) {
charSequenceRegister =
getInstruction<FiveRegisterInstruction>(charSequenceIndex1933).registerD
insertIndex = charSequenceIndex1933
} else {
throw PatchException("Could not find insert index")
}

val freeRegister = getInstruction<TwoRegisterInstruction>(
indexOfFirstInstructionOrThrow(insertIndex, Opcode.IGET_OBJECT)
).registerA

addInstructions(
insertIndex, """
move-object/from16 v$freeRegister, p0
iget-object v$freeRegister, v$freeRegister, $conversionContextFieldReference
invoke-static {v$freeRegister, v$charSequenceRegister}, $INTEGRATIONS_RYD_CLASS_DESCRIPTOR->onLithoTextLoaded(Ljava/lang/Object;Ljava/lang/CharSequence;)Ljava/lang/CharSequence;
move-result-object v$charSequenceRegister
"""
)
}
}
}
TextComponentPatch.hookTextComponent(INTEGRATIONS_RYD_CLASS_DESCRIPTOR)

// region Inject newVideoLoaded event handler to update dislikes when a new video is loaded.
VideoIdPatch.hookVideoId("$INTEGRATIONS_RYD_CLASS_DESCRIPTOR->newVideoLoaded(Ljava/lang/String;)V")
Expand Down
Loading

0 comments on commit 4bc6303

Please sign in to comment.