made by AI

This commit is contained in:
oSumAtrIX 2026-01-25 21:39:35 +01:00
parent bae293e3dd
commit 7302d29383
No known key found for this signature in database
GPG key ID: A9B3094ACDB604B4
30 changed files with 256 additions and 302 deletions

View file

@ -1,8 +1,9 @@
package app.revanced.patches.instagram.feed package app.revanced.patches.instagram.feed
import app.revanced.patcher.classDef
import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.getInstruction import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.firstMutableMethodDeclaratively
import app.revanced.patcher.name
import app.revanced.patcher.patch.creatingBytecodePatch import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.patches.instagram.misc.extension.sharedExtensionPatch import app.revanced.patches.instagram.misc.extension.sharedExtensionPatch
import app.revanced.util.getReference import app.revanced.util.getReference
@ -33,20 +34,16 @@ val `Limit feed to followed profiles` by creatingBytecodePatch(
mainFeedRequestHeaderFieldName = indexOfFirstInstructionOrThrow { mainFeedRequestHeaderFieldName = indexOfFirstInstructionOrThrow {
getReference<FieldReference>().let { ref -> getReference<FieldReference>().let { ref ->
ref?.type == "Ljava/util/Map;" && ref?.type == "Ljava/util/Map;" &&
ref.definingClass == mainFeedRequestClassMethod.classDef.toString() ref.definingClass == mainFeedRequestClassMethod.immutableClassDef.toString()
} }
}.let { instructionIndex -> }.let { instructionIndex ->
getInstruction(instructionIndex).getReference<FieldReference>()!!.name getInstruction(instructionIndex).getReference<FieldReference>()!!.name
} }
} }
val initMainFeedRequestMethod = fingerprint { mainFeedRequestClassMethod.immutableClassDef.firstMutableMethodDeclaratively {
custom { method, classDef -> name("<init>")
method.name == "<init>" && }.apply {
classDef == mainFeedRequestClassMethod.classDef
}
}
initMainFeedRequestMethod.apply {
// Finds the instruction where the map is being initialized in the constructor // Finds the instruction where the map is being initialized in the constructor
val getHeaderIndex = indexOfFirstInstructionOrThrow { val getHeaderIndex = indexOfFirstInstructionOrThrow {
getReference<FieldReference>().let { getReference<FieldReference>().let {

View file

@ -1,19 +1,16 @@
package app.revanced.patches.instagram.hide.navigation package app.revanced.patches.instagram.hide.navigation
import app.revanced.patcher.accessFlags import app.revanced.patcher.*
import app.revanced.patcher.gettingFirstMethodDeclaratively
import app.revanced.patcher.parameterTypes
import app.revanced.patcher.patch.BytecodePatchContext import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
internal val BytecodePatchContext.initializeNavigationButtonsListMethod by gettingFirstMethodDeclaratively { internal val BytecodePatchContext.initializeNavigationButtonsListMethod by gettingFirstMutableMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
parameterTypes("Lcom/instagram/common/session/UserSession;", "Z") parameterTypes("Lcom/instagram/common/session/UserSession;", "Z")
returnType("Ljava/util/List;") returnType("Ljava/util/List;")
} }
internal val navigationButtonsEnumClassDef = fingerprint { internal val navigationButtonsEnumClassDefMatch = firstMethodComposite(
strings("FEED", "fragment_feed", "SEARCH", "fragment_search") "FEED", "fragment_feed", "SEARCH", "fragment_search",
} )

View file

@ -1,6 +1,8 @@
package app.revanced.patches.instagram.hide.navigation package app.revanced.patches.instagram.hide.navigation
import app.revanced.patcher.extensions.getInstruction import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.firstMutableMethodDeclaratively
import app.revanced.patcher.name
import app.revanced.patcher.patch.booleanOption import app.revanced.patcher.patch.booleanOption
import app.revanced.patcher.patch.creatingBytecodePatch import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.patches.instagram.misc.extension.sharedExtensionPatch import app.revanced.patches.instagram.misc.extension.sharedExtensionPatch
@ -71,20 +73,14 @@ val `Hide navigation buttons` by creatingBytecodePatch(
// Get the field name which contains the name of the enum for the navigation button // Get the field name which contains the name of the enum for the navigation button
// ("fragment_clips", "fragment_share", ...) // ("fragment_clips", "fragment_share", ...)
val navigationButtonsEnumInitFingerprint = fingerprint { val enumNameField = navigationButtonsEnumClassDefMatch.classDef.firstMutableMethodDeclaratively {
custom { method, classDef -> name("<init>")
method.name == "<init>" && }.let { method ->
classDef == navigationButtonsEnumClassDef.classDef method.indexOfFirstInstructionOrThrow {
}
}
val enumNameField: String
with(navigationButtonsEnumInitFingerprint.method) {
enumNameField = indexOfFirstInstructionOrThrow {
opcode == Opcode.IPUT_OBJECT && opcode == Opcode.IPUT_OBJECT &&
(this as TwoRegisterInstruction).registerA == 2 // p2 register. (this as TwoRegisterInstruction).registerA == 2 // p2 register.
}.let { }.let {
getInstruction(it).getReference<FieldReference>()!!.name method.getInstruction(it).getReference<FieldReference>()!!.name
} }
} }

View file

@ -3,7 +3,7 @@ package app.revanced.patches.instagram.hide.stories
import app.revanced.patcher.* import app.revanced.patcher.*
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
internal val getOrCreateAvatarViewMethod = firstMethodComposite { internal val getOrCreateAvatarViewMethodMatch = firstMethodComposite {
definingClass("Lcom/instagram/reels/ui/views/reelavatar/RecyclerReelAvatarView;") definingClass("Lcom/instagram/reels/ui/views/reelavatar/RecyclerReelAvatarView;")
parameterTypes() parameterTypes()
returnType("L") returnType("L")

View file

@ -11,9 +11,11 @@ val `Hide Stories from Home` by creatingBytecodePatch(
compatibleWith("com.instagram.android") compatibleWith("com.instagram.android")
apply { apply {
val addStoryEndIndex = getOrCreateAvatarViewMethod.indices.last() getOrCreateAvatarViewMethodMatch.let {
val addStoryEndIndex = it.indices.last()
// Remove addView of Story. // Remove addView of Story.
getOrCreateAvatarViewMethod.removeInstruction(addStoryEndIndex) it.method.removeInstruction(addStoryEndIndex)
}
} }
} }

View file

@ -4,6 +4,7 @@ import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.util.Utils.trimIndentMultiline import app.revanced.util.Utils.trimIndentMultiline
import app.revanced.util.getReference import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionReversedOrThrow import app.revanced.util.indexOfFirstInstructionReversedOrThrow
import app.revanced.util.indexOfFirstStringInstruction
import app.revanced.util.returnEarly import app.revanced.util.returnEarly
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.reference.MethodReference import com.android.tools.smali.dexlib2.iface.reference.MethodReference
@ -20,8 +21,9 @@ val `Enable developer menu` by creatingBytecodePatch(
compatibleWith("com.instagram.android") compatibleWith("com.instagram.android")
apply { apply {
with(clearNotificationReceiverMethod) { clearNotificationReceiverMethod.apply {
indexOfFirstInstructionReversedOrThrow(clearNotificationReceiverMethod.stringMatches.first().index) { val stringIndex = indexOfFirstStringInstruction("NOTIFICATION_DISMISSED")
indexOfFirstInstructionReversedOrThrow(stringIndex) {
val reference = getReference<MethodReference>() val reference = getReference<MethodReference>()
opcode in listOf(Opcode.INVOKE_STATIC, Opcode.INVOKE_STATIC_RANGE) && opcode in listOf(Opcode.INVOKE_STATIC, Opcode.INVOKE_STATIC_RANGE) &&
reference?.parameterTypes?.size == 1 && reference?.parameterTypes?.size == 1 &&

View file

@ -1,10 +1,11 @@
package app.revanced.patches.instagram.misc.devmenu package app.revanced.patches.instagram.misc.devmenu
internal val BytecodePatchContext.clearNotificationReceiverMethod by gettingFirstMethodDeclaratively { import app.revanced.patcher.*
custom { method, classDef -> import app.revanced.patcher.patch.BytecodePatchContext
method.name == "onReceive" &&
classDef.type == "Lcom/instagram/notifications/push/ClearNotificationReceiver;" internal val BytecodePatchContext.clearNotificationReceiverMethod by gettingFirstMutableMethodDeclaratively(
} "NOTIFICATION_DISMISSED",
strings("NOTIFICATION_DISMISSED") ) {
name("onReceive")
definingClass("Lcom/instagram/notifications/push/ClearNotificationReceiver;")
} }

View file

@ -21,27 +21,25 @@ val `Open links externally` by creatingBytecodePatch(
compatibleWith("com.instagram.android") compatibleWith("com.instagram.android")
apply { apply {
inAppBrowserFunctionMethodMatch.let { inAppBrowserFunctionMethodMatch.method.apply {
val stringMatchIndex = it.stringMatches?.first { match -> match.string == TARGET_STRING }!!.index val stringMatchIndex = inAppBrowserFunctionMethodMatch.indices.first()
it.method.apply { val urlResultObjIndex = indexOfFirstInstructionOrThrow(
val urlResultObjIndex = indexOfFirstInstructionOrThrow( stringMatchIndex,
stringMatchIndex, Opcode.MOVE_OBJECT_FROM16,
Opcode.MOVE_OBJECT_FROM16, )
)
// Register that contains the url after moving from a higher register. // Register that contains the url after moving from a higher register.
val urlRegister = getInstruction<TwoRegisterInstruction>(urlResultObjIndex).registerA val urlRegister = getInstruction<TwoRegisterInstruction>(urlResultObjIndex).registerA
addInstructions( addInstructions(
urlResultObjIndex + 1, urlResultObjIndex + 1,
""" """
invoke-static { v$urlRegister }, $EXTENSION_CLASS_DESCRIPTOR->openExternally(Ljava/lang/String;)Z invoke-static { v$urlRegister }, $EXTENSION_CLASS_DESCRIPTOR->openExternally(Ljava/lang/String;)Z
move-result v$urlRegister move-result v$urlRegister
return v$urlRegister return v$urlRegister
""", """,
) )
}
} }
} }
} }

View file

@ -3,23 +3,24 @@ package app.revanced.patches.instagram.misc.share
import app.revanced.patcher.extensions.getInstruction import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.patch.BytecodePatchContext import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.util.indexOfFirstInstruction import app.revanced.util.indexOfFirstInstruction
import app.revanced.util.indexOfFirstStringInstruction
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
import com.android.tools.smali.dexlib2.mutable.MutableMethod import com.android.tools.smali.dexlib2.mutable.MutableMethod
context(BytecodePatchContext) context(_: BytecodePatchContext)
internal fun editShareLinksPatch(block: MutableMethod.(index: Int, register: Int) -> Unit) { internal fun editShareLinksPatch(block: MutableMethod.(index: Int, register: Int) -> Unit) {
val fingerprintsToPatch = arrayOf( val methodsToPatch = arrayOf(
permalinkResponseJsonParserMethod, permalinkResponseJsonParserMethod,
storyUrlResponseJsonParserMethod, storyUrlResponseJsonParserMethod,
profileUrlResponseJsonParserMethod, profileUrlResponseJsonParserMethod,
liveUrlResponseJsonParserMethod, liveUrlResponseJsonParserMethod,
) )
for (fingerprint in fingerprintsToPatch) { for (method in methodsToPatch) {
fingerprint.method.apply { method.apply {
val putSharingUrlIndex = indexOfFirstInstruction( val putSharingUrlIndex = indexOfFirstInstruction(
permalinkResponseJsonParserMethod.stringMatches.first().index, indexOfFirstStringInstruction("permalink"),
Opcode.IPUT_OBJECT, Opcode.IPUT_OBJECT,
) )

View file

@ -1,23 +1,28 @@
package app.revanced.patches.instagram.misc.share package app.revanced.patches.instagram.misc.share
import com.google.common.util.concurrent.Striped.custom import app.revanced.patcher.*
import app.revanced.patcher.patch.BytecodePatchContext
internal val BytecodePatchContext.permalinkResponseJsonParserMethod by gettingFirstMethodDeclaratively { internal val BytecodePatchContext.permalinkResponseJsonParserMethod by gettingFirstMutableMethodDeclaratively(
strings("permalink", "PermalinkResponse") "permalink", "PermalinkResponse",
custom { method, _ -> method.name == "parseFromJson" } ) {
name("parseFromJson")
} }
internal val BytecodePatchContext.storyUrlResponseJsonParserMethod by gettingFirstMethodDeclaratively { internal val BytecodePatchContext.storyUrlResponseJsonParserMethod by gettingFirstMutableMethodDeclaratively(
strings("story_item_to_share_url", "StoryItemUrlResponse") "story_item_to_share_url", "StoryItemUrlResponse",
custom { method, _ -> method.name == "parseFromJson" } ) {
name("parseFromJson")
} }
internal val BytecodePatchContext.profileUrlResponseJsonParserMethod by gettingFirstMethodDeclaratively { internal val BytecodePatchContext.profileUrlResponseJsonParserMethod by gettingFirstMutableMethodDeclaratively(
strings("profile_to_share_url", "ProfileUrlResponse") "profile_to_share_url", "ProfileUrlResponse",
custom { method, _ -> method.name == "parseFromJson" } ) {
name("parseFromJson")
} }
internal val BytecodePatchContext.liveUrlResponseJsonParserMethod by gettingFirstMethodDeclaratively { internal val BytecodePatchContext.liveUrlResponseJsonParserMethod by gettingFirstMutableMethodDeclaratively(
strings("live_to_share_url", "LiveItemLinkUrlResponse") "live_to_share_url", "LiveItemLinkUrlResponse",
custom { method, _ -> method.name == "parseFromJson" } ) {
name("parseFromJson")
} }

View file

@ -1,17 +1,13 @@
package app.revanced.patches.instagram.misc.share.domain package app.revanced.patches.instagram.misc.share.domain
import app.revanced.patcher.accessFlags import app.revanced.patcher.*
import app.revanced.patcher.gettingFirstMethodDeclaratively
import app.revanced.patcher.parameterTypes
import app.revanced.patcher.patch.BytecodePatchContext import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
internal val BytecodePatchContext.getCustomShareDomainMethod by gettingFirstMethodDeclaratively { internal val BytecodePatchContext.getCustomShareDomainMethod by gettingFirstMutableMethodDeclaratively {
accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC) accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC)
returnType("Ljava/lang/String;") returnType("Ljava/lang/String;")
parameterTypes() parameterTypes()
custom { method, classDef -> name("getCustomShareDomain")
method.name == "getCustomShareDomain" && classDef.type == EXTENSION_CLASS_DESCRIPTOR definingClass(EXTENSION_CLASS_DESCRIPTOR)
}
} }

View file

@ -1,22 +1,20 @@
package app.revanced.patches.instagram.misc.signature package app.revanced.patches.instagram.misc.signature
import app.revanced.patcher.gettingFirstMethodDeclaratively import app.revanced.patcher.*
import app.revanced.patcher.parameterTypes
import app.revanced.patcher.patch.BytecodePatchContext import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import app.revanced.util.getReference import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction import app.revanced.util.indexOfFirstInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference import com.android.tools.smali.dexlib2.iface.reference.MethodReference
internal val BytecodePatchContext.isValidSignatureClassMethod by gettingFirstMethodDeclaratively { internal val isValidSignatureClassMethodMatch = firstMethodComposite(
strings("The provider for uri '", "' is not trusted: ") "The provider for uri '", "' is not trusted: ",
} )
internal val BytecodePatchContext.isValidSignatureMethodMethod by gettingFirstMethodDeclaratively { internal val BytecodePatchContext.isValidSignatureMethodMethod by gettingFirstMutableMethodDeclaratively {
parameterTypes("L", "Z") parameterTypes("L", "Z")
returnType("Z") returnType("Z")
custom { method, _ -> custom {
method.indexOfFirstInstruction { indexOfFirstInstruction {
getReference<MethodReference>()?.name == "keySet" getReference<MethodReference>()?.name == "keySet"
} >= 0 } >= 0
} }

View file

@ -13,7 +13,7 @@ val `Disable signature check` by creatingBytecodePatch(
apply { apply {
isValidSignatureMethodMethod isValidSignatureMethodMethod
.match(isValidSignatureClassMethod.classDef) .match(isValidSignatureClassMethodMatch.classDef)
.method .method
.returnEarly(true) .returnEarly(true)
} }

View file

@ -1,19 +1,19 @@
package app.revanced.patches.messenger.metaai package app.revanced.patches.messenger.metaai
import app.revanced.patcher.* import app.revanced.patcher.*
import app.revanced.patcher.patch.BytecodePatchContext
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
internal val BytecodePatchContext.getMobileConfigBoolMethod by gettingFirstMutableMethodDeclaratively { internal val getMobileConfigBoolMethodMatch = firstMethodComposite {
returnType("Z") returnType("Z")
opcodes(Opcode.RETURN) opcodes(Opcode.RETURN)
custom { "Lcom/facebook/mobileconfig/factory/MobileConfigUnsafeContext;" in immutableClassDef.interfaces } custom { "Lcom/facebook/mobileconfig/factory/MobileConfigUnsafeContext;" in immutableClassDef.interfaces }
} }
internal val BytecodePatchContext.metaAIKillSwitchCheckMethod by gettingFirstMutableMethodDeclaratively("SearchAiagentImplementationsKillSwitch") { internal val metaAIKillSwitchCheckMethodMatch = firstMethodComposite("SearchAiagentImplementationsKillSwitch") {
opcodes(Opcode.CONST_WIDE) opcodes(Opcode.CONST_WIDE)
} }
internal val BytecodePatchContext.extensionMethodMethod by gettingFirstMutableMethodDeclaratively("REPLACED_BY_PATCH") {
internal val extensionMethodMethodMatch = firstMethodComposite("REPLACED_BY_PATCH") {
name(EXTENSION_METHOD_NAME) name(EXTENSION_METHOD_NAME)
definingClass(EXTENSION_CLASS_DESCRIPTOR) definingClass(EXTENSION_CLASS_DESCRIPTOR)
} }

View file

@ -3,7 +3,6 @@ package app.revanced.patches.messenger.metaai
import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.getInstruction import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.extensions.replaceInstruction import app.revanced.patcher.extensions.replaceInstruction
import app.revanced.patcher.method
import app.revanced.patcher.patch.creatingBytecodePatch import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.patches.messenger.misc.extension.sharedExtensionPatch import app.revanced.patches.messenger.misc.extension.sharedExtensionPatch
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
@ -21,11 +20,11 @@ val `Remove Meta AI` by creatingBytecodePatch(
dependsOn(sharedExtensionPatch) dependsOn(sharedExtensionPatch)
apply { apply {
getMobileConfigBoolMethod.apply { getMobileConfigBoolMethodMatch.let {
val returnIndex = getMobileConfigBoolMethod.patternMatch.startIndex // TODO val returnIndex = it.indices.first()
val returnRegister = getInstruction<OneRegisterInstruction>(returnIndex).registerA val returnRegister = it.method.getInstruction<OneRegisterInstruction>(returnIndex).registerA
addInstructions( it.method.addInstructions(
returnIndex, returnIndex,
""" """
invoke-static { p1, p2, v$returnRegister }, $EXTENSION_CLASS_DESCRIPTOR->$EXTENSION_METHOD_NAME(JZ)Z invoke-static { p1, p2, v$returnRegister }, $EXTENSION_CLASS_DESCRIPTOR->$EXTENSION_METHOD_NAME(JZ)Z
@ -35,16 +34,18 @@ val `Remove Meta AI` by creatingBytecodePatch(
} }
// Extract the common starting digits of Meta AI flag IDs from a flag found in code. // Extract the common starting digits of Meta AI flag IDs from a flag found in code.
val relevantDigits = with(metaAIKillSwitchCheckMethod) { val relevantDigits = metaAIKillSwitchCheckMethodMatch.let {
method.getInstruction<WideLiteralInstruction>(patternMatch.startIndex).wideLiteral // TODO it.method.getInstruction<WideLiteralInstruction>(it.indices.first()).wideLiteral
}.toString().substring(0, 7) }.toString().substring(0, 7)
// Replace placeholder in the extension method. // Replace placeholder in the extension method.
extensionMethodMethod.replaceInstruction( extensionMethodMethodMatch.let {
stringM.first().index, // TODO it.method.replaceInstruction(
""" it.indices.first(),
"""
const-string v1, "$relevantDigits" const-string v1, "$relevantDigits"
""", """,
) )
}
} }
} }

View file

@ -1,27 +1,22 @@
package app.revanced.patches.youtube.layout.startpage package app.revanced.patches.youtube.layout.startpage
import app.revanced.patcher.gettingFirstMethodDeclaratively import app.revanced.patcher.*
import app.revanced.patcher.instructions
import app.revanced.patcher.invoke
import app.revanced.patcher.parameterTypes
import app.revanced.patcher.patch.BytecodePatchContext import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
internal val BytecodePatchContext.intentActionMethod by gettingFirstMethodDeclaratively { internal val BytecodePatchContext.intentActionMethod by gettingFirstMutableMethodDeclaratively(
"has_handled_intent",
) {
parameterTypes("Landroid/content/Intent;") parameterTypes("Landroid/content/Intent;")
instructions(
"has_handled_intent"(),
)
} }
internal val BytecodePatchContext.browseIdMethod by gettingFirstMethodDeclaratively { internal val BytecodePatchContext.browseIdMethod by gettingFirstMutableMethodDeclaratively(
"FEwhat_to_watch",
) {
returnType("Lcom/google/android/apps/youtube/app/common/ui/navigation/PaneDescriptor;") returnType("Lcom/google/android/apps/youtube/app/common/ui/navigation/PaneDescriptor;")
// parameterTypes() // 20.30 and earlier is no parameters. 20.31+ parameter is L. // parameterTypes() // 20.30 and earlier is no parameters. 20.31+ parameter is L.
instructions( instructions(
"FEwhat_to_watch"(), 512L(),
512(), allOf(Opcode.IPUT_OBJECT(), field { type == "Ljava/lang/String;" }),
fieldAccess(opcode = Opcode.IPUT_OBJECT, type = "Ljava/lang/String;"),
) )
} }

View file

@ -1,21 +1,16 @@
package app.revanced.patches.youtube.layout.theme package app.revanced.patches.youtube.layout.theme
import app.revanced.patcher.anyInstruction import app.revanced.patcher.*
import app.revanced.patcher.gettingFirstMethodDeclaratively
import app.revanced.patcher.instructions
import app.revanced.patcher.invoke
import app.revanced.patcher.parameterTypes
import app.revanced.patcher.patch.BytecodePatchContext import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import app.revanced.patches.youtube.shared.YOUTUBE_MAIN_ACTIVITY_CLASS_TYPE import app.revanced.patches.youtube.shared.YOUTUBE_MAIN_ACTIVITY_CLASS_TYPE
internal val BytecodePatchContext.useGradientLoadingScreenMethod by gettingFirstMethodDeclaratively { internal val BytecodePatchContext.useGradientLoadingScreenMethod by gettingFirstMutableMethodDeclaratively {
instructions( instructions(
45412406L(), 45412406L(),
) )
} }
internal val BytecodePatchContext.splashScreenStyleMethod by gettingFirstMethodDeclaratively { internal val BytecodePatchContext.splashScreenStyleMethod by gettingFirstMutableMethodDeclaratively {
returnType("V") returnType("V")
parameterTypes("Landroid/os/Bundle;") parameterTypes("Landroid/os/Bundle;")
instructions( instructions(
@ -24,7 +19,6 @@ internal val BytecodePatchContext.splashScreenStyleMethod by gettingFirstMethodD
269032877L(), // 20.29 and lower. 269032877L(), // 20.29 and lower.
), ),
) )
custom { method, classDef -> definingClass(YOUTUBE_MAIN_ACTIVITY_CLASS_TYPE)
method.name == "onCreate" && classDef.type == YOUTUBE_MAIN_ACTIVITY_CLASS_TYPE name("onCreate")
}
} }

View file

@ -200,21 +200,17 @@ val themePatch = baseThemePatch(
) )
} }
useGradientLoadingScreenMethod.let { useGradientLoadingScreenMethod.insertLiteralOverride(
it.method.insertLiteralOverride( 45412406L,
it.instructionMatches.first().index, "$EXTENSION_CLASS_DESCRIPTOR->gradientLoadingScreenEnabled(Z)Z",
"$EXTENSION_CLASS_DESCRIPTOR->gradientLoadingScreenEnabled(Z)Z", )
)
}
if (is_19_47_or_greater) { if (is_19_47_or_greater) {
// Lottie splash screen exists in earlier versions, but it may not be always on. // Lottie splash screen exists in earlier versions, but it may not be always on.
splashScreenStyleMethod.let { splashScreenStyleMethod.insertLiteralOverride(
it.method.insertLiteralOverride( 1074339245L,
it.instructionMatches.first().index, "$EXTENSION_CLASS_DESCRIPTOR->getLoadingScreenType(I)I",
"$EXTENSION_CLASS_DESCRIPTOR->getLoadingScreenType(I)I", )
)
}
} }
}, },
) )

View file

@ -1,14 +1,13 @@
package app.revanced.patches.youtube.misc.dimensions.spoof package app.revanced.patches.youtube.misc.dimensions.spoof
import app.revanced.patcher.gettingFirstMethodDeclaratively import app.revanced.patcher.*
import app.revanced.patcher.instructions
import app.revanced.patcher.patch.BytecodePatchContext import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
internal val BytecodePatchContext.deviceDimensionsModelToStringMethod by gettingFirstMethodDeclaratively { // Strings are partial matches (format delimiters), so keep in instructions block.
internal val deviceDimensionsModelToStringMethodMatch = firstMethodComposite {
returnType("L") returnType("L")
instructions( strings {
"minh."(), +"minh."
";maxh."(), +";maxh."
) }
} }

View file

@ -38,8 +38,7 @@ val `Spoof device dimensions` by creatingBytecodePatch(
SwitchPreference("revanced_spoof_device_dimensions"), SwitchPreference("revanced_spoof_device_dimensions"),
) )
deviceDimensionsModelToStringMethod deviceDimensionsModelToStringMethodMatch.classDef.methods.first { method -> method.name == "<init>" }
.classDef.methods.first { method -> method.name == "<init>" }
// Override the parameters containing the dimensions. // Override the parameters containing the dimensions.
.addInstructions( .addInstructions(
1, // Add after super call. 1, // Add after super call.

View file

@ -30,21 +30,19 @@ internal val accountCredentialsInvalidTextPatch = bytecodePatch {
// MicroG accounts look almost identical to Google device accounts // MicroG accounts look almost identical to Google device accounts
// and it's more foolproof to instead uninstall/reinstall. // and it's more foolproof to instead uninstall/reinstall.
arrayOf( arrayOf(
specificNetworkErrorViewControllerMethod, specificNetworkErrorViewControllerMethodMatch,
loadingFrameLayoutControllerMethod, loadingFrameLayoutControllerMethodMatch,
).forEach { fingerprint -> ).forEach { match ->
fingerprint.apply { val index = match.indices.last()
val index = indices.last() val register = match.method.getInstruction<OneRegisterInstruction>(index).registerA
val register = method.getInstruction<OneRegisterInstruction>(index).registerA
method.addInstructions( match.method.addInstructions(
index + 1, index + 1,
""" """
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->getOfflineNetworkErrorString(Ljava/lang/String;)Ljava/lang/String; invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->getOfflineNetworkErrorString(Ljava/lang/String;)Ljava/lang/String;
move-result-object v$register move-result-object v$register
""", """,
) )
}
} }
} }
} }

View file

@ -1,37 +1,33 @@
package app.revanced.patches.youtube.misc.gms package app.revanced.patches.youtube.misc.gms
import app.revanced.patcher.accessFlags import app.revanced.patcher.*
import app.revanced.patcher.gettingFirstMethodDeclaratively
import app.revanced.patcher.instructions
import app.revanced.patcher.parameterTypes
import app.revanced.patcher.patch.BytecodePatchContext import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import app.revanced.patches.shared.misc.mapping.ResourceType import app.revanced.patches.shared.misc.mapping.ResourceType
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
internal val BytecodePatchContext.specificNetworkErrorViewControllerMethod by gettingFirstMethodDeclaratively { internal val specificNetworkErrorViewControllerMethodMatch = firstMethodComposite {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("V") returnType("V")
parameterTypes() parameterTypes()
instructions( instructions(
ResourceType.DRAWABLE("ic_offline_no_content_upside_down"), ResourceType.DRAWABLE("ic_offline_no_content_upside_down"),
ResourceType.STRING("offline_no_content_body_text_not_offline_eligible"), ResourceType.STRING("offline_no_content_body_text_not_offline_eligible"),
methodCall(name = "getString", returnType = "Ljava/lang/String;"), method { name == "getString" && returnType == "Ljava/lang/String;" },
after(Opcode.MOVE_RESULT_OBJECT()), Opcode.MOVE_RESULT_OBJECT(),
) )
} }
// It's not clear if this second class is ever used and it may be dead code, // It's not clear if this second class is ever used and it may be dead code,
// but it the layout image/text is identical to the network error fingerprint above. // but it the layout image/text is identical to the network error fingerprint above.
internal val BytecodePatchContext.loadingFrameLayoutControllerMethod by gettingFirstMethodDeclaratively { internal val loadingFrameLayoutControllerMethodMatch = firstMethodComposite {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("V") returnType("V")
parameterTypes("L") parameterTypes("L")
instructions( instructions(
ResourceType.DRAWABLE("ic_offline_no_content_upside_down"), ResourceType.DRAWABLE("ic_offline_no_content_upside_down"),
ResourceType.STRING("offline_no_content_body_text_not_offline_eligible"), ResourceType.STRING("offline_no_content_body_text_not_offline_eligible"),
methodCall(name = "getString", returnType = "Ljava/lang/String;"), method { name == "getString" && returnType == "Ljava/lang/String;" },
after(Opcode.MOVE_RESULT_OBJECT()), Opcode.MOVE_RESULT_OBJECT(),
) )
} }

View file

@ -52,19 +52,17 @@ val `Disable haptic feedback` by creatingBytecodePatch(
scrubbingHapticsMethod to "disablePreciseSeekingVibrate", scrubbingHapticsMethod to "disablePreciseSeekingVibrate",
seekUndoHapticsMethod to "disableSeekUndoVibrate", seekUndoHapticsMethod to "disableSeekUndoVibrate",
zoomHapticsMethod to "disableZoomVibrate", zoomHapticsMethod to "disableZoomVibrate",
).forEach { (fingerprint, methodName) -> ).forEach { (method, methodName) ->
fingerprint.method.apply { method.addInstructionsWithLabels(
addInstructionsWithLabels( 0,
0, """
""" invoke-static {}, $EXTENSION_CLASS_DESCRIPTOR->$methodName()Z
invoke-static {}, $EXTENSION_CLASS_DESCRIPTOR->$methodName()Z move-result v0
move-result v0 if-eqz v0, :vibrate
if-eqz v0, :vibrate return-void
return-void """,
""", ExternalLabel("vibrate", method.getInstruction(0)),
ExternalLabel("vibrate", getInstruction(0)), )
)
}
} }
} }
} }

View file

@ -1,21 +1,28 @@
package app.revanced.patches.youtube.misc.hapticfeedback package app.revanced.patches.youtube.misc.hapticfeedback
internal val BytecodePatchContext.markerHapticsMethod by gettingFirstMethodDeclaratively { import app.revanced.patcher.*
import app.revanced.patcher.patch.BytecodePatchContext
internal val BytecodePatchContext.markerHapticsMethod by gettingFirstMutableMethodDeclaratively(
"Failed to execute markers haptics vibrate.",
) {
returnType("V") returnType("V")
strings("Failed to execute markers haptics vibrate.")
} }
internal val BytecodePatchContext.scrubbingHapticsMethod by gettingFirstMethodDeclaratively { internal val BytecodePatchContext.scrubbingHapticsMethod by gettingFirstMutableMethodDeclaratively(
"Failed to haptics vibrate for fine scrubbing.",
) {
returnType("V") returnType("V")
strings("Failed to haptics vibrate for fine scrubbing.")
} }
internal val BytecodePatchContext.seekUndoHapticsMethod by gettingFirstMethodDeclaratively { internal val BytecodePatchContext.seekUndoHapticsMethod by gettingFirstMutableMethodDeclaratively(
"Failed to execute seek undo haptics vibrate.",
) {
returnType("V") returnType("V")
strings("Failed to execute seek undo haptics vibrate.")
} }
internal val BytecodePatchContext.zoomHapticsMethod by gettingFirstMethodDeclaratively { internal val BytecodePatchContext.zoomHapticsMethod by gettingFirstMutableMethodDeclaratively(
"Failed to haptics vibrate for video zoom",
) {
returnType("V") returnType("V")
strings("Failed to haptics vibrate for video zoom")
} }

View file

@ -31,13 +31,13 @@ val cronetImageUrlHookPatch = bytecodePatch(
apply { apply {
loadImageUrlMethod = messageDigestImageUrlMethod loadImageUrlMethod = messageDigestImageUrlMethod
.match(messageDigestImageUrlParentMethod.immutableClassDef).method .match(messageDigestImageUrlParentMethodMatch.classDef)
loadImageSuccessCallbackMethod = onSucceededMethod loadImageSuccessCallbackMethod = onSucceededMethod
.match(onResponseStartedMethod.immutableClassDef).method .match(onResponseStartedMethodMatch.classDef)
loadImageErrorCallbackMethod = onFailureMethod loadImageErrorCallbackMethod = onFailureMethod
.match(onResponseStartedMethod.immutableClassDef).method .match(onResponseStartedMethodMatch.classDef)
// The URL is required for the failure callback hook, but the URL field is obfuscated. // The URL is required for the failure callback hook, but the URL field is obfuscated.
// Add a helper get method that returns the URL field. // Add a helper get method that returns the URL field.

View file

@ -1,15 +1,10 @@
package app.revanced.patches.youtube.misc.imageurlhook package app.revanced.patches.youtube.misc.imageurlhook
import app.revanced.patcher.accessFlags import app.revanced.patcher.*
import app.revanced.patcher.anyInstruction
import app.revanced.patcher.gettingFirstMethodDeclaratively
import app.revanced.patcher.instructions
import app.revanced.patcher.parameterTypes
import app.revanced.patcher.patch.BytecodePatchContext import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
internal val BytecodePatchContext.onFailureMethod by gettingFirstMethodDeclaratively { internal val BytecodePatchContext.onFailureMethod by gettingFirstMutableMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("V") returnType("V")
parameterTypes( parameterTypes(
@ -17,58 +12,49 @@ internal val BytecodePatchContext.onFailureMethod by gettingFirstMethodDeclarati
"Lorg/chromium/net/UrlResponseInfo;", "Lorg/chromium/net/UrlResponseInfo;",
"Lorg/chromium/net/CronetException;", "Lorg/chromium/net/CronetException;",
) )
custom { method, _ -> name("onFailed")
method.name == "onFailed"
}
} }
// Acts as a parent fingerprint. // Acts as a parent fingerprint.
internal val BytecodePatchContext.onResponseStartedMethod by gettingFirstMethodDeclaratively { internal val onResponseStartedMethodMatch = firstMethodComposite(
"Content-Length",
"Content-Type",
"identity",
"application/x-protobuf",
) {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("V") returnType("V")
parameterTypes("Lorg/chromium/net/UrlRequest;", "Lorg/chromium/net/UrlResponseInfo;") parameterTypes("Lorg/chromium/net/UrlRequest;", "Lorg/chromium/net/UrlResponseInfo;")
strings( name("onResponseStarted")
"Content-Length",
"Content-Type",
"identity",
"application/x-protobuf",
)
custom { method, _ ->
method.name == "onResponseStarted"
}
} }
internal val BytecodePatchContext.onSucceededMethod by gettingFirstMethodDeclaratively { internal val BytecodePatchContext.onSucceededMethod by gettingFirstMutableMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("V") returnType("V")
parameterTypes("Lorg/chromium/net/UrlRequest;", "Lorg/chromium/net/UrlResponseInfo;") parameterTypes("Lorg/chromium/net/UrlRequest;", "Lorg/chromium/net/UrlResponseInfo;")
custom { method, _ -> name("onSucceeded")
method.name == "onSucceeded"
}
} }
internal const val CRONET_URL_REQUEST_CLASS_DESCRIPTOR = "Lorg/chromium/net/impl/CronetUrlRequest;" internal const val CRONET_URL_REQUEST_CLASS_DESCRIPTOR = "Lorg/chromium/net/impl/CronetUrlRequest;"
internal val BytecodePatchContext.requestMethod by gettingFirstMethodDeclaratively { internal val BytecodePatchContext.requestMethod by gettingFirstMutableMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
custom { _, classDef -> definingClass(CRONET_URL_REQUEST_CLASS_DESCRIPTOR)
classDef.type == CRONET_URL_REQUEST_CLASS_DESCRIPTOR
}
} }
internal val BytecodePatchContext.messageDigestImageUrlMethod by gettingFirstMethodDeclaratively { internal val BytecodePatchContext.messageDigestImageUrlMethod by gettingFirstMutableMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
parameterTypes("Ljava/lang/String;", "L") parameterTypes("Ljava/lang/String;", "L")
} }
internal val BytecodePatchContext.messageDigestImageUrlParentMethod by gettingFirstMethodDeclaratively { internal val messageDigestImageUrlParentMethodMatch = firstMethodComposite {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("Ljava/lang/String;") returnType("Ljava/lang/String;")
parameterTypes() parameterTypes()
instructions( strings {
anyInstruction( anyOf(
"@#&=*+-_.,:!?()/~'%;\$"(), "@#&=*+-_.,:!?()/~'%;\$",
"@#&=*+-_.,:!?()/~'%;\$[]"(), // 20.38+ "@#&=*+-_.,:!?()/~'%;\$[]", // 20.38+
), )
) }
} }

View file

@ -1,12 +1,6 @@
package app.revanced.patches.youtube.misc.links package app.revanced.patches.youtube.misc.links
import app.revanced.patcher.StringComparisonType import app.revanced.patcher.*
import app.revanced.patcher.accessFlags
import app.revanced.patcher.firstMethodComposite
import app.revanced.patcher.gettingFirstMethodDeclaratively
import app.revanced.patcher.instructions
import app.revanced.patcher.parameterTypes
import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
/** /**
@ -16,10 +10,13 @@ internal val abUriParserLegacyMethodMatch = firstMethodComposite {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("Ljava/lang/Object;") returnType("Ljava/lang/Object;")
parameterTypes("Ljava/lang/Object;") parameterTypes("Ljava/lang/Object;")
strings {
// Partial string match - keep in instructions block
+"Found entityKey=`"
// "that does not contain a PlaylistVideoEntityId" - partial, skipped
}
instructions( instructions(
"Found entityKey=`"(), method { smali == "Landroid/net/Uri;->parse(Ljava/lang/String;)Landroid/net/Uri;" },
addString("that does not contain a PlaylistVideoEntityId", comparison = StringComparisonType.CONTAINS),
methodCall(smali = "Landroid/net/Uri;->parse(Ljava/lang/String;)Landroid/net/Uri;"),
) )
} }
@ -33,10 +30,10 @@ internal val abUriParserMethodMatch = firstMethodComposite {
instructions( instructions(
// Method is a switch statement of unrelated code, // Method is a switch statement of unrelated code,
// and there's no strings or anything unique to fingerprint. // and there's no strings or anything unique to fingerprint.
methodCall(smali = "Ljava/lang/Boolean;->valueOf(Z)Ljava/lang/Boolean;"), method { smali == "Ljava/lang/Boolean;->valueOf(Z)Ljava/lang/Boolean;" },
methodCall(smali = "Ljava/lang/Boolean;->valueOf(Z)Ljava/lang/Boolean;"), method { smali == "Ljava/lang/Boolean;->valueOf(Z)Ljava/lang/Boolean;" },
methodCall(smali = "Landroid/net/Uri;->parse(Ljava/lang/String;)Landroid/net/Uri;"), method { smali == "Landroid/net/Uri;->parse(Ljava/lang/String;)Landroid/net/Uri;" },
methodCall(smali = "Ljava/util/List;->get(I)Ljava/lang/Object;"), method { smali == "Ljava/util/List;->get(I)Ljava/lang/Object;" },
) )
} }
@ -45,9 +42,11 @@ internal val httpUriParserMethodMatch = firstMethodComposite {
returnType("Landroid/net/Uri;") returnType("Landroid/net/Uri;")
parameterTypes("Ljava/lang/String;") parameterTypes("Ljava/lang/String;")
instructions( instructions(
methodCall(smali = "Landroid/net/Uri;->parse(Ljava/lang/String;)Landroid/net/Uri;"), method { smali == "Landroid/net/Uri;->parse(Ljava/lang/String;)Landroid/net/Uri;" },
"https"(),
"://"(),
"https:"(),
) )
strings {
+"https"
+"://"
+"https:"
}
} }

View file

@ -1,13 +1,10 @@
package app.revanced.patches.youtube.video.speed.remember package app.revanced.patches.youtube.video.speed.remember
import app.revanced.patcher.gettingFirstMethodDeclaratively import app.revanced.patcher.*
import app.revanced.patcher.instructions
import app.revanced.patcher.parameterTypes
import app.revanced.patcher.patch.BytecodePatchContext import app.revanced.patcher.patch.BytecodePatchContext
internal val BytecodePatchContext.initializePlaybackSpeedValuesMethod by gettingFirstMethodDeclaratively { internal val BytecodePatchContext.initializePlaybackSpeedValuesMethod by gettingFirstMutableMethodDeclaratively(
"menu_item_playback_speed",
) {
parameterTypes("[L", "I") parameterTypes("[L", "I")
instructions(
"menu_item_playback_speed"(),
)
} }

View file

@ -1,37 +1,37 @@
package app.revanced.patches.youtube.video.videoid package app.revanced.patches.youtube.video.videoid
import app.revanced.patcher.accessFlags import app.revanced.patcher.*
import app.revanced.patcher.gettingFirstMethodDeclaratively
import app.revanced.patcher.instructions
import app.revanced.patcher.invoke
import app.revanced.patcher.parameterTypes
import app.revanced.patcher.patch.BytecodePatchContext import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.ClassDef
internal val BytecodePatchContext.videoIdMethod by gettingFirstMethodDeclaratively { /**
* Matches using the class found in [videoIdParentMethodMatch].
*/
context(_: BytecodePatchContext)
internal fun ClassDef.getVideoIdMethodMatch() = firstMethodComposite {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("V") returnType("V")
parameterTypes("L") parameterTypes("L")
instructions( instructions(
methodCall( method {
definingClass = "Lcom/google/android/libraries/youtube/innertube/model/player/PlayerResponseModel;", definingClass == "Lcom/google/android/libraries/youtube/innertube/model/player/PlayerResponseModel;"
returnType = "Ljava/lang/String;", && returnType == "Ljava/lang/String;"
), },
Opcode.MOVE_RESULT_OBJECT(), Opcode.MOVE_RESULT_OBJECT(),
) )
} }
internal val BytecodePatchContext.videoIdBackgroundPlayMethod by gettingFirstMethodDeclaratively { internal val videoIdBackgroundPlayMethodMatch = firstMethodComposite {
accessFlags(AccessFlags.DECLARED_SYNCHRONIZED, AccessFlags.FINAL, AccessFlags.PUBLIC) accessFlags(AccessFlags.DECLARED_SYNCHRONIZED, AccessFlags.FINAL, AccessFlags.PUBLIC)
returnType("V") returnType("V")
parameterTypes("L") parameterTypes("L")
instructions( instructions(
methodCall( method {
definingClass = "Lcom/google/android/libraries/youtube/innertube/model/player/PlayerResponseModel;", definingClass == "Lcom/google/android/libraries/youtube/innertube/model/player/PlayerResponseModel;"
returnType = "Ljava/lang/String;", && returnType == "Ljava/lang/String;"
), },
Opcode.MOVE_RESULT_OBJECT(), Opcode.MOVE_RESULT_OBJECT(),
Opcode.IPUT_OBJECT(), Opcode.IPUT_OBJECT(),
Opcode.MONITOR_EXIT(), Opcode.MONITOR_EXIT(),
@ -39,16 +39,16 @@ internal val BytecodePatchContext.videoIdBackgroundPlayMethod by gettingFirstMet
Opcode.MONITOR_EXIT(), Opcode.MONITOR_EXIT(),
Opcode.RETURN_VOID(), Opcode.RETURN_VOID(),
) )
custom { method, classDef -> custom {
method.implementation != null && implementation != null &&
( (
classDef.methods.count() == 17 || // 20.39 and lower. definingClass.methods.count() == 17 || // 20.39 and lower.
classDef.methods.count() == 16 definingClass.methods.count() == 16
) // 20.40+ ) // 20.40+
} }
} }
internal val videoIdParentFingerprint = fingerprint { internal val videoIdParentMethodMatch = firstMethodComposite {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("[L") returnType("[L")
parameterTypes("L") parameterTypes("L")

View file

@ -92,22 +92,18 @@ val videoIdPatch = bytecodePatch(
) )
apply { apply {
videoIdMethod.match(videoIdParentFingerprint.immutableClassDef).let { videoIdParentMethodMatch.classDef.getVideoIdMethodMatch().let {
it.method.apply { videoIdMethod = it.method
videoIdMethod = this val index = it.indices.first()
val index = it.instructionMatches.first().index videoIdRegister = videoIdMethod.getInstruction<OneRegisterInstruction>(index + 1).registerA
videoIdRegister = getInstruction<OneRegisterInstruction>(index + 1).registerA videoIdInsertIndex = index + 2
videoIdInsertIndex = index + 2
}
} }
videoIdBackgroundPlayMethod.let { videoIdBackgroundPlayMethodMatch.let {
it.method.apply { backgroundPlaybackMethod = it.method
backgroundPlaybackMethod = this val index = it.indices.first()
val index = it.instructionMatches.first().index backgroundPlaybackVideoIdRegister = backgroundPlaybackMethod.getInstruction<OneRegisterInstruction>(index + 1).registerA
backgroundPlaybackVideoIdRegister = getInstruction<OneRegisterInstruction>(index + 1).registerA backgroundPlaybackInsertIndex = index + 2
backgroundPlaybackInsertIndex = index + 2
}
} }
} }
} }