some more migrations

This commit is contained in:
oSumAtrIX 2026-01-25 01:49:03 +01:00
parent 56eff2a625
commit 3a3fe5ed9b
No known key found for this signature in database
GPG key ID: A9B3094ACDB604B4
15 changed files with 168 additions and 261 deletions

View file

@ -1,5 +1,6 @@
package app.revanced.patches.music.misc.gms package app.revanced.patches.music.misc.gms
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.patch.Option import app.revanced.patcher.patch.Option
import app.revanced.patches.all.misc.resources.addResources import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch import app.revanced.patches.all.misc.resources.addResourcesPatch
@ -19,7 +20,7 @@ val gmsCoreSupportPatch = gmsCoreSupportPatch(
fromPackageName = MUSIC_PACKAGE_NAME, fromPackageName = MUSIC_PACKAGE_NAME,
toPackageName = REVANCED_MUSIC_PACKAGE_NAME, toPackageName = REVANCED_MUSIC_PACKAGE_NAME,
getPrimeMethod = { primeMethod }, getPrimeMethod = { primeMethod },
getEarlyReturnMethods = { setOf(castContextFetchMethod) }, earlyReturnMethods = setOf(BytecodePatchContext::castContextFetchMethod::get),
getMainActivityOnCreateMethod = { musicActivityOnCreateMethod }, getMainActivityOnCreateMethod = { musicActivityOnCreateMethod },
extensionPatch = sharedExtensionPatch, extensionPatch = sharedExtensionPatch,
gmsCoreSupportResourcePatchFactory = ::gmsCoreSupportResourcePatch, gmsCoreSupportResourcePatchFactory = ::gmsCoreSupportResourcePatch,
@ -28,8 +29,8 @@ val gmsCoreSupportPatch = gmsCoreSupportPatch(
compatibleWith( compatibleWith(
MUSIC_PACKAGE_NAME( MUSIC_PACKAGE_NAME(
"7.29.52", "7.29.52",
"8.10.52" "8.10.52",
) ),
) )
} }
@ -50,17 +51,17 @@ private fun gmsCoreSupportResourcePatch(
"microg_settings", "microg_settings",
intent = IntentPreference.Intent("", "org.microg.gms.ui.SettingsActivity") { intent = IntentPreference.Intent("", "org.microg.gms.ui.SettingsActivity") {
"$gmsCoreVendorGroupId.android.gms" "$gmsCoreVendorGroupId.android.gms"
} },
) ),
) )
} },
) { ) {
dependsOn( dependsOn(
addResourcesPatch, addResourcesPatch,
settingsPatch, settingsPatch,
fileProviderPatch( fileProviderPatch(
MUSIC_PACKAGE_NAME, MUSIC_PACKAGE_NAME,
REVANCED_MUSIC_PACKAGE_NAME REVANCED_MUSIC_PACKAGE_NAME,
) ),
) )
} }

View file

@ -334,7 +334,7 @@ internal fun baseCustomBrandingPatch(
) )
// Bundled icons. // Bundled icons.
iconStyleNames.forEachIndexed { index, style -> iconStyleNames.forEach { style ->
application.appendChild( application.appendChild(
createAlias( createAlias(
aliasName = aliasName(style), aliasName = aliasName(style),

View file

@ -1,25 +1,22 @@
package app.revanced.patches.shared.layout.branding package app.revanced.patches.shared.layout.branding
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.numberOfPresetAppNamesExtensionMethod by gettingFirstMethodDeclaratively { internal val BytecodePatchContext.numberOfPresetAppNamesExtensionMethod by gettingFirstMutableMethodDeclaratively {
name("numberOfPresetAppNames")
definingClass(EXTENSION_CLASS_DESCRIPTOR)
accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC) accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC)
returnType("I") returnType("I")
parameterTypes() parameterTypes()
custom { method, classDef ->
method.name == "numberOfPresetAppNames" && classDef.type == EXTENSION_CLASS_DESCRIPTOR
}
} }
// A much simpler fingerprint exists that can set the small icon (contains string "414843287017"), // A much simpler fingerprint exists that can set the small icon (contains string "414843287017"),
// but that has limited usage and this fingerprint allows changing any part of the notification. // but that has limited usage and this fingerprint allows changing any part of the notification.
internal val BytecodePatchContext.notificationMethod by gettingFirstMethodDeclaratively { internal val BytecodePatchContext.notificationMethod by gettingFirstMutableMethodDeclaratively(
"key_action_priority",
) {
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
parameterTypes("L") parameterTypes("L")
strings("key_action_priority")
} }

View file

@ -1,13 +1,10 @@
package app.revanced.patches.shared.misc.gms package app.revanced.patches.shared.misc.gms
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.googlePlayUtilityMethod by gettingFirstMethodDeclaratively( internal val BytecodePatchContext.googlePlayUtilityMethod by gettingFirstMutableMethodDeclarativelyOrNull(
"This should never happen.", "This should never happen.",
"MetadataValueReader", "MetadataValueReader",
"com.google.android.gms", "com.google.android.gms",
@ -17,7 +14,7 @@ internal val BytecodePatchContext.googlePlayUtilityMethod by gettingFirstMethodD
parameterTypes("L", "I") parameterTypes("L", "I")
} }
internal val BytecodePatchContext.serviceCheckMethod by gettingFirstMethodDeclaratively( internal val BytecodePatchContext.serviceCheckMethod by gettingFirstMutableMethodDeclaratively(
"Google Play Services not available", "Google Play Services not available",
) { ) {
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
@ -25,20 +22,18 @@ internal val BytecodePatchContext.serviceCheckMethod by gettingFirstMethodDeclar
parameterTypes("L", "I") parameterTypes("L", "I")
} }
internal val BytecodePatchContext.gmsCoreSupportMethod by gettingFirstMethodDeclaratively { internal val BytecodePatchContext.gmsCoreSupportMethod by gettingFirstMutableMethodDeclaratively {
name("getGmsCoreVendorGroupId")
definingClass(EXTENSION_CLASS_DESCRIPTOR)
accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC) accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC)
returnType("Ljava/lang/String;") returnType("Ljava/lang/String;")
parameterTypes() parameterTypes()
custom { method, classDef ->
method.name == "getGmsCoreVendorGroupId" && classDef.type == EXTENSION_CLASS_DESCRIPTOR
}
} }
internal val BytecodePatchContext.originalPackageNameExtensionMethod by gettingFirstMethodDeclaratively { internal val BytecodePatchContext.originalPackageNameExtensionMethod by gettingFirstMutableMethodDeclaratively {
name("getOriginalPackageName")
definingClass(EXTENSION_CLASS_DESCRIPTOR)
accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC) accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC)
returnType("Ljava/lang/String;") returnType("Ljava/lang/String;")
parameterTypes() parameterTypes()
custom { methodDef, classDef ->
methodDef.name == "getOriginalPackageName" && classDef.type == EXTENSION_CLASS_DESCRIPTOR
}
} }

View file

@ -4,7 +4,6 @@ import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.extensions.instructions import app.revanced.patcher.extensions.instructions
import app.revanced.patcher.extensions.replaceInstruction import app.revanced.patcher.extensions.replaceInstruction
import app.revanced.patcher.patch.* import app.revanced.patcher.patch.*
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patches.all.misc.packagename.`Change package name` import app.revanced.patches.all.misc.packagename.`Change package name`
import app.revanced.patches.all.misc.packagename.setOrGetFallbackPackageName import app.revanced.patches.all.misc.packagename.setOrGetFallbackPackageName
import app.revanced.patches.all.misc.resources.addResources import app.revanced.patches.all.misc.resources.addResources
@ -36,7 +35,7 @@ private const val PACKAGE_NAME_REGEX_PATTERN = "^[a-z]\\w*(\\.[a-z]\\w*)+\$"
* @param fromPackageName The package name of the original app. * @param fromPackageName The package name of the original app.
* @param toPackageName The package name to fall back to if no custom package name is specified in patch options. * @param toPackageName The package name to fall back to if no custom package name is specified in patch options.
* @param getPrimeMethod The "prime" method that needs to be patched. * @param getPrimeMethod The "prime" method that needs to be patched.
* @param getEarlyReturnMethods The methods that need to be returned early. * @param earlyReturnMethods The methods that need to be returned early.
* @param getMainActivityOnCreateMethod The main activity onCreate method. * @param getMainActivityOnCreateMethod The main activity onCreate method.
* @param extensionPatch The patch responsible for the extension. * @param extensionPatch The patch responsible for the extension.
* @param gmsCoreSupportResourcePatchFactory The factory for the corresponding resource patch * @param gmsCoreSupportResourcePatchFactory The factory for the corresponding resource patch
@ -48,7 +47,7 @@ fun gmsCoreSupportPatch(
fromPackageName: String, fromPackageName: String,
toPackageName: String, toPackageName: String,
getPrimeMethod: (BytecodePatchContext.() -> MutableMethod)? = null, getPrimeMethod: (BytecodePatchContext.() -> MutableMethod)? = null,
getEarlyReturnMethods: Set<BytecodePatchContext.() -> MutableMethod> = emptySet(), earlyReturnMethods: Set<BytecodePatchContext.() -> MutableMethod> = emptySet(),
getMainActivityOnCreateMethod: BytecodePatchContext.() -> MutableMethod, getMainActivityOnCreateMethod: BytecodePatchContext.() -> MutableMethod,
extensionPatch: Patch, extensionPatch: Patch,
gmsCoreSupportResourcePatchFactory: (gmsCoreVendorGroupIdOption: Option<String>) -> Patch, gmsCoreSupportResourcePatchFactory: (gmsCoreVendorGroupIdOption: Option<String>) -> Patch,
@ -203,13 +202,11 @@ fun gmsCoreSupportPatch(
getPrimeMethod?.let { transformPrimeMethod(packageName) } getPrimeMethod?.let { transformPrimeMethod(packageName) }
// Return these methods early to prevent the app from crashing. // Return these methods early to prevent the app from crashing.
getEarlyReturnMethods().forEach { it.returnEarly() } earlyReturnMethods.forEach { it().returnEarly() }
serviceCheckMethod.returnEarly() serviceCheckMethod.returnEarly()
// Google Play Utility is not present in all apps, so we need to check if it's present. // Google Play Utility is not present in all apps, so we need to check if it's present.
if (googlePlayUtilityMethodOrNull != null) { googlePlayUtilityMethod?.returnEarly(0)
googlePlayUtilityMethod.returnEarly(0)
}
// Set original and patched package names for extension to use. // Set original and patched package names for extension to use.
originalPackageNameExtensionMethod.returnEarly(fromPackageName) originalPackageNameExtensionMethod.returnEarly(fromPackageName)

View file

@ -22,7 +22,7 @@ val gmsCoreSupportPatch = gmsCoreSupportPatch(
fromPackageName = YOUTUBE_PACKAGE_NAME, fromPackageName = YOUTUBE_PACKAGE_NAME,
toPackageName = REVANCED_YOUTUBE_PACKAGE_NAME, toPackageName = REVANCED_YOUTUBE_PACKAGE_NAME,
getPrimeMethod = BytecodePatchContext::primeMethod::get, getPrimeMethod = BytecodePatchContext::primeMethod::get,
getEarlyReturnMethods = setOf(BytecodePatchContext::castContextFetchMethod::get), earlyReturnMethods = setOf(BytecodePatchContext::castContextFetchMethod::get),
getMainActivityOnCreateMethod = BytecodePatchContext::mainActivityOnCreateMethod::get, getMainActivityOnCreateMethod = BytecodePatchContext::mainActivityOnCreateMethod::get,
extensionPatch = sharedExtensionPatch, extensionPatch = sharedExtensionPatch,
gmsCoreSupportResourcePatchFactory = ::gmsCoreSupportResourcePatch, gmsCoreSupportResourcePatchFactory = ::gmsCoreSupportResourcePatch,
@ -38,7 +38,7 @@ val gmsCoreSupportPatch = gmsCoreSupportPatch(
"20.14.43", "20.14.43",
"20.21.37", "20.21.37",
"20.31.40", "20.31.40",
) ),
) )
} }
@ -59,14 +59,14 @@ private fun gmsCoreSupportResourcePatch(
"microg_settings", "microg_settings",
intent = IntentPreference.Intent("", "org.microg.gms.ui.SettingsActivity") { intent = IntentPreference.Intent("", "org.microg.gms.ui.SettingsActivity") {
"$gmsCoreVendorGroupId.android.gms" "$gmsCoreVendorGroupId.android.gms"
} },
) ),
) )
} },
) { ) {
dependsOn( dependsOn(
addResourcesPatch, addResourcesPatch,
settingsPatch, settingsPatch,
accountCredentialsInvalidTextPatch accountCredentialsInvalidTextPatch,
) )
} }

View file

@ -1,21 +1,14 @@
package app.revanced.patches.youtube.misc.playercontrols package app.revanced.patches.youtube.misc.playercontrols
import app.revanced.patcher.accessFlags import app.revanced.patcher.*
import app.revanced.patcher.checkCast
import app.revanced.patcher.gettingFirstMethodDeclaratively
import app.revanced.patcher.instructions
import app.revanced.patcher.invoke
import app.revanced.patcher.methodCall
import app.revanced.patcher.opcode
import app.revanced.patcher.opcodes
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
import com.android.tools.smali.dexlib2.iface.ClassDef
internal val BytecodePatchContext.playerControlsVisibilityEntityModelMethod by gettingFirstMethodDeclaratively { internal val BytecodePatchContext.playerControlsVisibilityEntityModelMethod by gettingFirstMethodDeclaratively {
name("getPlayerControlsVisibility")
accessFlags(AccessFlags.PUBLIC) accessFlags(AccessFlags.PUBLIC)
returnType("L") returnType("L")
parameterTypes() parameterTypes()
@ -23,131 +16,113 @@ internal val BytecodePatchContext.playerControlsVisibilityEntityModelMethod by g
Opcode.IGET, Opcode.IGET,
Opcode.INVOKE_STATIC, Opcode.INVOKE_STATIC,
) )
custom { method, _ ->
method.name == "getPlayerControlsVisibility"
}
} }
internal val BytecodePatchContext.youtubeControlsOverlayMethod by gettingFirstMethodDeclaratively { internal val BytecodePatchContext.youtubeControlsOverlayMethod by gettingFirstMethodDeclaratively {
returnType("V") returnType("V")
parameterTypes() parameterTypes()
instructions( instructions(
methodCall(name = "setFocusableInTouchMode"), method("setFocusableInTouchMode"),
ResourceType.ID("inset_overlay_view_layout"), ResourceType.ID("inset_overlay_view_layout"),
ResourceType.ID("scrim_overlay"), ResourceType.ID("scrim_overlay"),
) )
} }
internal val BytecodePatchContext.motionEventMethod by gettingFirstMethodDeclaratively { internal val motionEventMethodMatch = firstMethodComposite {
returnType("V") returnType("V")
parameterTypes("Landroid/view/MotionEvent;") parameterTypes("Landroid/view/MotionEvent;")
instructions( instructions(method("setTranslationY"))
methodCall(name = "setTranslationY"),
)
} }
internal val BytecodePatchContext.playerControlsExtensionHookListenersExistMethod by gettingFirstMethodDeclaratively { internal val BytecodePatchContext.playerControlsExtensionHookListenersExistMethod by gettingFirstMutableMethodDeclaratively {
name("fullscreenButtonVisibilityCallbacksExist")
definingClass(EXTENSION_CLASS_DESCRIPTOR)
accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC) accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC)
returnType("Z") returnType("Z")
parameterTypes() parameterTypes()
custom { methodDef, classDef ->
methodDef.name == "fullscreenButtonVisibilityCallbacksExist" &&
classDef.type == EXTENSION_CLASS_DESCRIPTOR
}
} }
internal val BytecodePatchContext.playerControlsExtensionHookMethod by gettingFirstMethodDeclaratively { internal val BytecodePatchContext.playerControlsExtensionHookMethod by gettingFirstMutableMethodDeclaratively {
name("fullscreenButtonVisibilityChanged")
definingClass(EXTENSION_CLASS_DESCRIPTOR)
accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC) accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC)
returnType("V") returnType("V")
parameterTypes("Z") parameterTypes("Z")
custom { methodDef, classDef ->
methodDef.name == "fullscreenButtonVisibilityChanged" &&
classDef.type == EXTENSION_CLASS_DESCRIPTOR
}
} }
internal val BytecodePatchContext.playerTopControlsInflateMethod by gettingFirstMethodDeclaratively { internal val playerTopControlsInflateMethod = firstMethodComposite {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("V") returnType("V")
parameterTypes() parameterTypes()
instructions( instructions(
ResourceType.ID("controls_layout_stub"), ResourceType.ID("controls_layout_stub"),
methodCall("Landroid/view/ViewStub;", "inflate"), method { name == "inflate" && definingClass == "Landroid/view/ViewStub;" },
after(Opcode.MOVE_RESULT_OBJECT()), after(Opcode.MOVE_RESULT_OBJECT()),
) )
} }
internal val BytecodePatchContext.playerBottomControlsInflateMethod by gettingFirstMethodDeclaratively { internal val playerBottomControlsInflateMethodMatch = firstMethodComposite {
returnType("Ljava/lang/Object;") returnType("Ljava/lang/Object;")
parameterTypes() parameterTypes()
instructions( instructions(
ResourceType.ID("bottom_ui_container_stub"), ResourceType.ID("bottom_ui_container_stub"),
methodCall("Landroid/view/ViewStub;", "inflate"), method { name == "inflate" && definingClass == "Landroid/view/ViewStub;" },
after(Opcode.MOVE_RESULT_OBJECT()), after(Opcode.MOVE_RESULT_OBJECT()),
) )
} }
internal val BytecodePatchContext.overlayViewInflateMethod by gettingFirstMethodDeclaratively { internal val overlayViewInflateMethodMatch = firstMethodComposite {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("V") returnType("V")
parameterTypes("Landroid/view/View;") parameterTypes("Landroid/view/View;")
instructions( instructions(
ResourceType.ID("heatseeker_viewstub"), ResourceType.ID("heatseeker_viewstub"),
ResourceType.ID("fullscreen_button"), ResourceType.ID("fullscreen_button"),
checkCast("Landroid/widget/ImageView;"), allOf(Opcode.CHECK_CAST(), type("Landroid/widget/ImageView;")),
) )
} }
/** /**
* Resolves to the class found in [playerTopControlsInflateMethod]. * Resolves to the class found in [playerTopControlsInflateMethod].
*/ */
internal val BytecodePatchContext.controlsOverlayVisibilityMethod by gettingFirstMethodDeclaratively { context(_: BytecodePatchContext)
internal fun ClassDef.getControlsOverlayVisibilityMethod() = firstMutableMethodDeclaratively {
accessFlags(AccessFlags.PRIVATE, AccessFlags.FINAL) accessFlags(AccessFlags.PRIVATE, AccessFlags.FINAL)
returnType("V") returnType("V")
parameterTypes("Z", "Z") parameterTypes("Z", "Z")
} }
internal val BytecodePatchContext.playerBottomControlsExploderFeatureFlagMethod by gettingFirstMethodDeclaratively { internal val BytecodePatchContext.playerBottomControlsExploderFeatureFlagMethod by gettingFirstMutableMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("Z") returnType("Z")
parameterTypes() parameterTypes()
instructions( instructions(45643739L())
45643739L(),
)
} }
internal val BytecodePatchContext.playerTopControlsExperimentalLayoutFeatureFlagMethod by gettingFirstMethodDeclaratively { internal val BytecodePatchContext.playerTopControlsExperimentalLayoutFeatureFlagMethod by gettingFirstMutableMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("I") returnType("I")
parameterTypes() parameterTypes()
instructions( instructions(45629424L())
45629424L(),
)
} }
internal val BytecodePatchContext.playerControlsLargeOverlayButtonsFeatureFlagMethod by gettingFirstMethodDeclaratively { internal val BytecodePatchContext.playerControlsLargeOverlayButtonsFeatureFlagMethod by gettingFirstMutableMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("Z") returnType("Z")
parameterTypes() parameterTypes()
instructions( instructions(45709810L())
45709810L(),
)
} }
internal val BytecodePatchContext.playerControlsFullscreenLargeButtonsFeatureFlagMethod by gettingFirstMethodDeclaratively { internal val BytecodePatchContext.playerControlsFullscreenLargeButtonsFeatureFlagMethod by gettingFirstMutableMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("Z") returnType("Z")
parameterTypes() parameterTypes()
instructions( instructions(45686474L())
45686474L(),
)
} }
internal val BytecodePatchContext.playerControlsButtonStrokeFeatureFlagMethod by gettingFirstMethodDeclaratively { internal val BytecodePatchContext.playerControlsButtonStrokeFeatureFlagMethod by gettingFirstMutableMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("Z") returnType("Z")
parameterTypes() parameterTypes()
instructions( instructions(45713296L())
45713296L(),
)
} }

View file

@ -2,26 +2,15 @@ package app.revanced.patches.youtube.misc.playercontrols
import app.revanced.patcher.extensions.addInstruction import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.extensions.getInstruction import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.immutableClassDef
import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.resourcePatch import app.revanced.patcher.patch.resourcePatch
import app.revanced.patcher.util.Document import app.revanced.patcher.util.Document
import app.revanced.patches.shared.misc.mapping.resourceMappingPatch import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.playservice.is_19_25_or_greater import app.revanced.patches.youtube.misc.playservice.*
import app.revanced.patches.youtube.misc.playservice.is_19_35_or_greater import app.revanced.util.*
import app.revanced.patches.youtube.misc.playservice.is_20_19_or_greater
import app.revanced.patches.youtube.misc.playservice.is_20_20_or_greater
import app.revanced.patches.youtube.misc.playservice.is_20_28_or_greater
import app.revanced.patches.youtube.misc.playservice.is_20_30_or_greater
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
import app.revanced.util.copyXmlNode
import app.revanced.util.findElementByAttributeValue
import app.revanced.util.findElementByAttributeValueOrThrow
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.inputStreamFromBundledResource
import app.revanced.util.returnEarly
import app.revanced.util.returnLate
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.mutable.MutableMethod import com.android.tools.smali.dexlib2.mutable.MutableMethod
@ -244,51 +233,44 @@ val playerControlsPatch = bytecodePatch(
) )
apply { apply {
playerBottomControlsInflateMethod.let { playerBottomControlsInflateMethodMatch.method.apply {
it.method.apply { inflateBottomControlMethod = this
inflateBottomControlMethod = this
val inflateReturnObjectIndex = it.indices.last() val inflateReturnObjectIndex = playerBottomControlsInflateMethodMatch.indices.last()
inflateBottomControlRegister = getInstruction<OneRegisterInstruction>(inflateReturnObjectIndex).registerA inflateBottomControlRegister = getInstruction<OneRegisterInstruction>(inflateReturnObjectIndex).registerA
inflateBottomControlInsertIndex = inflateReturnObjectIndex + 1 inflateBottomControlInsertIndex = inflateReturnObjectIndex + 1
}
} }
playerTopControlsInflateMethod.let { playerTopControlsInflateMethod.method.apply {
it.method.apply { inflateTopControlMethod = this
inflateTopControlMethod = this
val inflateReturnObjectIndex = it.indices.last() val inflateReturnObjectIndex = playerTopControlsInflateMethod.indices.last()
inflateTopControlRegister = getInstruction<OneRegisterInstruction>(inflateReturnObjectIndex).registerA inflateTopControlRegister = getInstruction<OneRegisterInstruction>(inflateReturnObjectIndex).registerA
inflateTopControlInsertIndex = inflateReturnObjectIndex + 1 inflateTopControlInsertIndex = inflateReturnObjectIndex + 1
}
} }
visibilityMethod = controlsOverlayVisibilityMethod.match( visibilityMethod =
playerTopControlsInflateMethod.originalClassDef, playerTopControlsInflateMethod.immutableClassDef.getControlsOverlayVisibilityMethod()
).method
// Hook the fullscreen close button. Used to fix visibility // Hook the fullscreen close button. Used to fix visibility
// when seeking and other situations. // when seeking and other situations.
overlayViewInflateMethod.let { overlayViewInflateMethodMatch.method.apply {
it.method.apply { val index = overlayViewInflateMethodMatch.indices.last()
val index = it.indices.last() val register = getInstruction<OneRegisterInstruction>(index).registerA
val register = getInstruction<OneRegisterInstruction>(index).registerA
addInstruction( addInstruction(
index + 1, index + 1,
"invoke-static { v$register }, " + "invoke-static { v$register }, " +
"$EXTENSION_CLASS_DESCRIPTOR->setFullscreenCloseButton(Landroid/widget/ImageView;)V", "$EXTENSION_CLASS_DESCRIPTOR->setFullscreenCloseButton(Landroid/widget/ImageView;)V",
) )
}
} }
visibilityImmediateCallbacksExistMethod = playerControlsExtensionHookListenersExistMethod visibilityImmediateCallbacksExistMethod = playerControlsExtensionHookListenersExistMethod
visibilityImmediateMethod = playerControlsExtensionHookMethod visibilityImmediateMethod = playerControlsExtensionHookMethod
motionEventMethod.match(youtubeControlsOverlayMethod.originalClassDef).let { motionEventMethodMatch.match(youtubeControlsOverlayMethod.immutableClassDef).let {
visibilityNegatedImmediateMethod = it.method visibilityNegatedImmediateMethod = it.method
visibilityNegatedImmediateInsertIndex = it.instructionMatches.first().index + 1 visibilityNegatedImmediateInsertIndex = it.indices.first() + 1
} }
// A/B test for a slightly different bottom overlay controls, // A/B test for a slightly different bottom overlay controls,

View file

@ -1,36 +1,28 @@
package app.revanced.patches.youtube.misc.playertype package app.revanced.patches.youtube.misc.playertype
import app.revanced.patcher.accessFlags import app.revanced.patcher.*
import app.revanced.patcher.after
import app.revanced.patcher.afterAtMost
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.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.playerTypeEnumMethod by gettingFirstMethodDeclaratively { internal val BytecodePatchContext.playerTypeEnumMethod by gettingFirstMethodDeclaratively(
"NONE",
"HIDDEN",
"WATCH_WHILE_MINIMIZED",
"WATCH_WHILE_MAXIMIZED",
"WATCH_WHILE_FULLSCREEN",
"WATCH_WHILE_SLIDING_MAXIMIZED_FULLSCREEN",
"WATCH_WHILE_SLIDING_MINIMIZED_MAXIMIZED",
"WATCH_WHILE_SLIDING_MINIMIZED_DISMISSED",
"INLINE_MINIMAL",
"VIRTUAL_REALITY_FULLSCREEN",
"WATCH_WHILE_PICTURE_IN_PICTURE",
) {
accessFlags(AccessFlags.STATIC, AccessFlags.CONSTRUCTOR) accessFlags(AccessFlags.STATIC, AccessFlags.CONSTRUCTOR)
strings(
"NONE",
"HIDDEN",
"WATCH_WHILE_MINIMIZED",
"WATCH_WHILE_MAXIMIZED",
"WATCH_WHILE_FULLSCREEN",
"WATCH_WHILE_SLIDING_MAXIMIZED_FULLSCREEN",
"WATCH_WHILE_SLIDING_MINIMIZED_MAXIMIZED",
"WATCH_WHILE_SLIDING_MINIMIZED_DISMISSED",
"INLINE_MINIMAL",
"VIRTUAL_REALITY_FULLSCREEN",
"WATCH_WHILE_PICTURE_IN_PICTURE",
)
} }
internal val BytecodePatchContext.reelWatchPagerMethod by gettingFirstMethodDeclaratively { internal val reelWatchPagerMethodMatch = firstMethodComposite {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("Landroid/view/View;") returnType("Landroid/view/View;")
instructions( instructions(
@ -39,17 +31,16 @@ internal val BytecodePatchContext.reelWatchPagerMethod by gettingFirstMethodDecl
) )
} }
internal val BytecodePatchContext.videoStateEnumMethod by gettingFirstMethodDeclaratively { internal val BytecodePatchContext.videoStateEnumMethod by gettingFirstMethodDeclaratively(
"NEW",
"PLAYING",
"PAUSED",
"RECOVERABLE_ERROR",
"UNRECOVERABLE_ERROR",
"ENDED",
) {
accessFlags(AccessFlags.STATIC, AccessFlags.CONSTRUCTOR) accessFlags(AccessFlags.STATIC, AccessFlags.CONSTRUCTOR)
parameterTypes() parameterTypes()
strings(
"NEW",
"PLAYING",
"PAUSED",
"RECOVERABLE_ERROR",
"UNRECOVERABLE_ERROR",
"ENDED",
)
} }
// 20.33 and lower class name ControlsState. 20.34+ class name is obfuscated. // 20.33 and lower class name ControlsState. 20.34+ class name is obfuscated.

View file

@ -1,9 +1,9 @@
package app.revanced.patches.youtube.misc.playertype package app.revanced.patches.youtube.misc.playertype
import app.revanced.patcher.*
import app.revanced.patcher.extensions.addInstruction import app.revanced.patcher.extensions.addInstruction
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.fieldAccess
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.shared.misc.mapping.ResourceType import app.revanced.patches.shared.misc.mapping.ResourceType
import app.revanced.patches.shared.misc.mapping.resourceMappingPatch import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
@ -20,54 +20,44 @@ val playerTypeHookPatch = bytecodePatch(
dependsOn(sharedExtensionPatch, resourceMappingPatch) dependsOn(sharedExtensionPatch, resourceMappingPatch)
apply { apply {
val playerOverlaysSetPlayerTypeFingerprint = fingerprint { firstMutableMethodDeclaratively {
definingClass { endsWith("/YouTubePlayerOverlaysLayout;") }
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("V") returnType("V")
parameterTypes(playerTypeEnumMethod.originalClassDef.type) parameterTypes(playerTypeEnumMethod.immutableClassDef.type)
custom { _, classDef -> }.addInstruction(
classDef.endsWith("/YouTubePlayerOverlaysLayout;")
}
}
playerOverlaysSetPlayerTypeFingerprint.method.addInstruction(
0, 0,
"invoke-static { p1 }, $EXTENSION_CLASS_DESCRIPTOR->setPlayerType(Ljava/lang/Enum;)V", "invoke-static { p1 }, $EXTENSION_CLASS_DESCRIPTOR->setPlayerType(Ljava/lang/Enum;)V",
) )
reelWatchPagerMethod.let { reelWatchPagerMethodMatch.method.apply {
it.method.apply { val index = reelWatchPagerMethodMatch.indices.last()
val index = it.indices.last() val register = getInstruction<OneRegisterInstruction>(index).registerA
val register = getInstruction<OneRegisterInstruction>(index).registerA
addInstruction( addInstruction(
index + 1, index + 1,
"invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->onShortsCreate(Landroid/view/View;)V", "invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->onShortsCreate(Landroid/view/View;)V",
) )
}
} }
val controlStateType = controlsStateToStringMethod.originalClassDef.type val controlStateType = controlsStateToStringMethod.immutableClassDef.type
val videoStateFingerprint = fingerprint { val videoStateEnumMethod = videoStateEnumMethod
firstMethodComposite {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("V") returnType("V")
parameterTypes(controlStateType) parameterTypes(controlStateType)
instructions( instructions(
field {
definingClass == controlStateType && type == videoStateEnumMethod.immutableClassDef.type
},
// Obfuscated parameter field name. // Obfuscated parameter field name.
fieldAccess(
definingClass = controlStateType,
type = videoStateEnumMethod.originalClassDef.type,
),
ResourceType.STRING("accessibility_play"), ResourceType.STRING("accessibility_play"),
ResourceType.STRING("accessibility_pause"), ResourceType.STRING("accessibility_pause"),
) )
} }.let {
videoStateFingerprint.let {
it.method.apply { it.method.apply {
val videoStateFieldName = getInstruction<ReferenceInstruction>( val videoStateFieldName = getInstruction<ReferenceInstruction>(it.indices.first()).reference
it.instructionMatches.first().index,
).reference
addInstructions( addInstructions(
0, 0,

View file

@ -1,50 +1,38 @@
package app.revanced.patches.youtube.misc.settings package app.revanced.patches.youtube.misc.settings
import app.revanced.patcher.accessFlags import app.revanced.patcher.*
import app.revanced.patcher.after
import app.revanced.patcher.afterAtMost
import app.revanced.patcher.gettingFirstMethodDeclaratively
import app.revanced.patcher.instructions
import app.revanced.patcher.invoke
import app.revanced.patcher.opcode
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.licenseActivityOnCreateMethod by gettingFirstMethodDeclaratively { internal val BytecodePatchContext.licenseActivityOnCreateMethod by gettingFirstMutableMethodDeclaratively {
name("onCreate")
definingClass("/LicenseActivity;")
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("V") returnType("V")
parameterTypes("Landroid/os/Bundle;") parameterTypes("Landroid/os/Bundle;")
custom { method, classDef ->
method.name == "onCreate" && classDef.endsWith("/LicenseActivity;")
}
} }
internal val BytecodePatchContext.setThemeMethod by gettingFirstMethodDeclaratively { internal val BytecodePatchContext.setThemeMethod by gettingFirstMutableMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("L") returnType("L")
parameterTypes() parameterTypes()
instructions( instructions(ResourceType.STRING("app_theme_appearance_dark"))
ResourceType.STRING("app_theme_appearance_dark"),
)
} }
internal val BytecodePatchContext.cairoFragmentConfigMethod by gettingFirstMethodDeclaratively { internal val cairoFragmentConfigMethodMatch = firstMethodComposite {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("Z") returnType("Z")
instructions( instructions(
45532100L(), 45532100L(),
afterAtMost(10, Opcode.MOVE_RESULT()), afterAtMost(10, Opcode.MOVE_RESULT()),
) )
} }
// Flag is present in 20.23, but bold icons are missing and forcing them crashes the app. // Flag is present in 20.23, but bold icons are missing and forcing them crashes the app.
// 20.31 is the first target with all the bold icons present. // 20.31 is the first target with all the bold icons present.
internal val BytecodePatchContext.boldIconsFeatureFlagMethod by gettingFirstMethodDeclaratively { internal val boldIconsFeatureFlagMethod = firstMethodComposite {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("Z") returnType("Z")
parameterTypes() parameterTypes()

View file

@ -1,5 +1,6 @@
package app.revanced.patches.youtube.misc.settings package app.revanced.patches.youtube.misc.settings
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.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
@ -239,8 +240,8 @@ val settingsPatch = bytecodePatch(
} }
// Add setting to force Cairo settings fragment on/off. // Add setting to force Cairo settings fragment on/off.
cairoFragmentConfigMethod.insertLiteralOverride( cairoFragmentConfigMethodMatch.method.insertLiteralOverride(
cairoFragmentConfigMethod.instructionMatches.first().index, cairoFragmentConfigMethodMatch.indices.first(),
"$YOUTUBE_ACTIVITY_HOOK_CLASS_DESCRIPTOR->useCairoSettingsFragment(Z)Z", "$YOUTUBE_ACTIVITY_HOOK_CLASS_DESCRIPTOR->useCairoSettingsFragment(Z)Z",
) )
@ -249,7 +250,7 @@ val settingsPatch = bytecodePatch(
if (is_20_31_or_greater) { if (is_20_31_or_greater) {
boldIconsFeatureFlagMethod.let { boldIconsFeatureFlagMethod.let {
it.method.insertLiteralOverride( it.method.insertLiteralOverride(
it.instructionMatches.first().index, it.indices.first(),
"$YOUTUBE_ACTIVITY_HOOK_CLASS_DESCRIPTOR->useBoldIcons(Z)Z", "$YOUTUBE_ACTIVITY_HOOK_CLASS_DESCRIPTOR->useBoldIcons(Z)Z",
) )
} }

View file

@ -47,20 +47,15 @@ internal val advancedVideoQualityMenuPatch = bytecodePatch {
) )
// Used for the old type of the video quality menu. // Used for the old type of the video quality menu.
videoQualityBottomSheetListFragmentname = getResourceId( videoQualityBottomSheetListFragmentname =
ResourceType.LAYOUT, ResourceType.LAYOUT["video_quality_bottom_sheet_list_fragment_title"]
"video_quality_bottom_sheet_list_fragment_title", videoQualityQuickMenuAdvancedMenuDescription =
) ResourceType.STRING["video_quality_quick_menu_advanced_menu_description"]
videoQualityQuickMenuAdvancedMenuDescription = getResourceId(
ResourceType.STRING,
"video_quality_quick_menu_advanced_menu_description",
)
// region Patch for the old type of the video quality menu. // region Patch for the old type of the video quality menu.
// Used for regular videos when spoofing to old app version, // Used for regular videos when spoofing to old app version,
// and for the Shorts quality flyout on newer app versions. // and for the Shorts quality flyout on newer app versions.
videoQualityMenuViewInflateMethod.let { videoQualityMenuViewInflateMethodMatch.let {
it.method.apply { it.method.apply {
val checkCastIndex = it.indices.last() val checkCastIndex = it.indices.last()
val listViewRegister = getInstruction<OneRegisterInstruction>(checkCastIndex).registerA val listViewRegister = getInstruction<OneRegisterInstruction>(checkCastIndex).registerA
@ -74,10 +69,10 @@ internal val advancedVideoQualityMenuPatch = bytecodePatch {
} }
// Force YT to add the 'advanced' quality menu for Shorts. // Force YT to add the 'advanced' quality menu for Shorts.
videoQualityMenuOptionsMethod.let { videoQualityMenuOptionsMethodMatch.let {
val patternMatch = it.instructionMatches val startIndex = it.indices.first()
val startIndex = patternMatch.first().index val insertIndex = it.indices.last()
val insertIndex = patternMatch.last().index
if (startIndex != 0) throw PatchException("Unexpected opcode start index: $startIndex") if (startIndex != 0) throw PatchException("Unexpected opcode start index: $startIndex")
it.method.apply { it.method.apply {

View file

@ -1,9 +1,10 @@
package app.revanced.patches.youtube.video.quality package app.revanced.patches.youtube.video.quality
import app.revanced.patcher.accessFlags import app.revanced.patcher.accessFlags
import app.revanced.patcher.addString import app.revanced.patcher.firstMethodComposite
import app.revanced.patcher.firstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstMethodDeclaratively import app.revanced.patcher.gettingFirstMethodDeclaratively
import app.revanced.patcher.instructions import app.revanced.patcher.name
import app.revanced.patcher.opcodes import app.revanced.patcher.opcodes
import app.revanced.patcher.parameterTypes import app.revanced.patcher.parameterTypes
import app.revanced.patcher.patch.BytecodePatchContext import app.revanced.patcher.patch.BytecodePatchContext
@ -12,17 +13,15 @@ import app.revanced.util.literal
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.videoQualityItemOnClickParentMethod by gettingFirstMethodDeclaratively { internal val BytecodePatchContext.videoQualityItemOnClickParentMethod by gettingFirstMethodDeclaratively(
"VIDEO_QUALITIES_MENU_BOTTOM_SHEET_FRAGMENT",
) {
returnType("V") returnType("V")
instructions(
"VIDEO_QUALITIES_MENU_BOTTOM_SHEET_FRAGMENT"(),
)
} }
/** context(_: BytecodePatchContext)
* Resolves to class found in [videoQualityItemOnClickMethod]. internal fun com.android.tools.smali.dexlib2.iface.ClassDef.getVideoQualityItemOnClickMethod() = firstMutableMethodDeclaratively {
*/ name("onItemClick")
internal val BytecodePatchContext.videoQualityItemOnClickMethod by gettingFirstMethodDeclaratively {
returnType("V") returnType("V")
parameterTypes( parameterTypes(
"Landroid/widget/AdapterView;", "Landroid/widget/AdapterView;",
@ -30,12 +29,9 @@ internal val BytecodePatchContext.videoQualityItemOnClickMethod by gettingFirstM
"I", "I",
"J", "J",
) )
custom { method, _ ->
method.name == "onItemClick"
}
} }
internal val BytecodePatchContext.videoQualityMenuOptionsMethod by gettingFirstMethodDeclaratively { internal val videoQualityMenuOptionsMethodMatch = firstMethodComposite {
accessFlags(AccessFlags.STATIC) accessFlags(AccessFlags.STATIC)
returnType("[L") returnType("[L")
parameterTypes("Landroid/content/Context", "L", "L") parameterTypes("Landroid/content/Context", "L", "L")
@ -49,7 +45,7 @@ internal val BytecodePatchContext.videoQualityMenuOptionsMethod by gettingFirstM
literal { videoQualityQuickMenuAdvancedMenuDescription } literal { videoQualityQuickMenuAdvancedMenuDescription }
} }
internal val BytecodePatchContext.videoQualityMenuViewInflateMethod by gettingFirstMethodDeclaratively { internal val videoQualityMenuViewInflateMethodMatch = firstMethodComposite {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("L") returnType("L")
parameterTypes("L", "L", "L") parameterTypes("L", "L", "L")

View file

@ -2,6 +2,7 @@ package app.revanced.patches.youtube.video.quality
import app.revanced.patcher.extensions.addInstruction import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.extensions.getInstruction import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.immutableClassDef
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.all.misc.resources.addResources import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch import app.revanced.patches.all.misc.resources.addResourcesPatch
@ -64,9 +65,7 @@ val rememberVideoQualityPatch = bytecodePatch {
onCreateHook(EXTENSION_CLASS_DESCRIPTOR, "newVideoStarted") onCreateHook(EXTENSION_CLASS_DESCRIPTOR, "newVideoStarted")
// Inject a call to remember the selected quality for Shorts. // Inject a call to remember the selected quality for Shorts.
videoQualityItemOnClickMethod.match( videoQualityItemOnClickParentMethod.immutableClassDef.getVideoQualityItemOnClickMethod().addInstruction(
videoQualityItemOnClickParentMethod.classDef,
).method.addInstruction(
0, 0,
"invoke-static { p3 }, $EXTENSION_CLASS_DESCRIPTOR->userChangedShortsQuality(I)V", "invoke-static { p3 }, $EXTENSION_CLASS_DESCRIPTOR->userChangedShortsQuality(I)V",
) )