some more migrations

This commit is contained in:
oSumAtrIX
2026-01-25 01:49:03 +01:00
parent 56eff2a625
commit 3a3fe5ed9b
15 changed files with 168 additions and 261 deletions

View File

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

View File

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

View File

@@ -1,25 +1,22 @@
package app.revanced.patches.shared.layout.branding
import app.revanced.patcher.accessFlags
import app.revanced.patcher.gettingFirstMethodDeclaratively
import app.revanced.patcher.parameterTypes
import app.revanced.patcher.*
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
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)
returnType("I")
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"),
// 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)
parameterTypes("L")
strings("key_action_priority")
}

View File

@@ -1,13 +1,10 @@
package app.revanced.patches.shared.misc.gms
import app.revanced.patcher.accessFlags
import app.revanced.patcher.gettingFirstMethodDeclaratively
import app.revanced.patcher.parameterTypes
import app.revanced.patcher.*
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.AccessFlags
internal val BytecodePatchContext.googlePlayUtilityMethod by gettingFirstMethodDeclaratively(
internal val BytecodePatchContext.googlePlayUtilityMethod by gettingFirstMutableMethodDeclarativelyOrNull(
"This should never happen.",
"MetadataValueReader",
"com.google.android.gms",
@@ -17,7 +14,7 @@ internal val BytecodePatchContext.googlePlayUtilityMethod by gettingFirstMethodD
parameterTypes("L", "I")
}
internal val BytecodePatchContext.serviceCheckMethod by gettingFirstMethodDeclaratively(
internal val BytecodePatchContext.serviceCheckMethod by gettingFirstMutableMethodDeclaratively(
"Google Play Services not available",
) {
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
@@ -25,20 +22,18 @@ internal val BytecodePatchContext.serviceCheckMethod by gettingFirstMethodDeclar
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)
returnType("Ljava/lang/String;")
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)
returnType("Ljava/lang/String;")
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.replaceInstruction
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.setOrGetFallbackPackageName
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 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 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 extensionPatch The patch responsible for the extension.
* @param gmsCoreSupportResourcePatchFactory The factory for the corresponding resource patch
@@ -48,7 +47,7 @@ fun gmsCoreSupportPatch(
fromPackageName: String,
toPackageName: String,
getPrimeMethod: (BytecodePatchContext.() -> MutableMethod)? = null,
getEarlyReturnMethods: Set<BytecodePatchContext.() -> MutableMethod> = emptySet(),
earlyReturnMethods: Set<BytecodePatchContext.() -> MutableMethod> = emptySet(),
getMainActivityOnCreateMethod: BytecodePatchContext.() -> MutableMethod,
extensionPatch: Patch,
gmsCoreSupportResourcePatchFactory: (gmsCoreVendorGroupIdOption: Option<String>) -> Patch,
@@ -203,13 +202,11 @@ fun gmsCoreSupportPatch(
getPrimeMethod?.let { transformPrimeMethod(packageName) }
// Return these methods early to prevent the app from crashing.
getEarlyReturnMethods().forEach { it.returnEarly() }
earlyReturnMethods.forEach { it().returnEarly() }
serviceCheckMethod.returnEarly()
// 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.
originalPackageNameExtensionMethod.returnEarly(fromPackageName)

View File

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

View File

@@ -1,21 +1,14 @@
package app.revanced.patches.youtube.misc.playercontrols
import app.revanced.patcher.accessFlags
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.*
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import app.revanced.patches.shared.misc.mapping.ResourceType
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.ClassDef
internal val BytecodePatchContext.playerControlsVisibilityEntityModelMethod by gettingFirstMethodDeclaratively {
name("getPlayerControlsVisibility")
accessFlags(AccessFlags.PUBLIC)
returnType("L")
parameterTypes()
@@ -23,131 +16,113 @@ internal val BytecodePatchContext.playerControlsVisibilityEntityModelMethod by g
Opcode.IGET,
Opcode.INVOKE_STATIC,
)
custom { method, _ ->
method.name == "getPlayerControlsVisibility"
}
}
internal val BytecodePatchContext.youtubeControlsOverlayMethod by gettingFirstMethodDeclaratively {
returnType("V")
parameterTypes()
instructions(
methodCall(name = "setFocusableInTouchMode"),
method("setFocusableInTouchMode"),
ResourceType.ID("inset_overlay_view_layout"),
ResourceType.ID("scrim_overlay"),
)
}
internal val BytecodePatchContext.motionEventMethod by gettingFirstMethodDeclaratively {
internal val motionEventMethodMatch = firstMethodComposite {
returnType("V")
parameterTypes("Landroid/view/MotionEvent;")
instructions(
methodCall(name = "setTranslationY"),
)
instructions(method("setTranslationY"))
}
internal val BytecodePatchContext.playerControlsExtensionHookListenersExistMethod by gettingFirstMethodDeclaratively {
internal val BytecodePatchContext.playerControlsExtensionHookListenersExistMethod by gettingFirstMutableMethodDeclaratively {
name("fullscreenButtonVisibilityCallbacksExist")
definingClass(EXTENSION_CLASS_DESCRIPTOR)
accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC)
returnType("Z")
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)
returnType("V")
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)
returnType("V")
parameterTypes()
instructions(
ResourceType.ID("controls_layout_stub"),
methodCall("Landroid/view/ViewStub;", "inflate"),
method { name == "inflate" && definingClass == "Landroid/view/ViewStub;" },
after(Opcode.MOVE_RESULT_OBJECT()),
)
}
internal val BytecodePatchContext.playerBottomControlsInflateMethod by gettingFirstMethodDeclaratively {
internal val playerBottomControlsInflateMethodMatch = firstMethodComposite {
returnType("Ljava/lang/Object;")
parameterTypes()
instructions(
ResourceType.ID("bottom_ui_container_stub"),
methodCall("Landroid/view/ViewStub;", "inflate"),
method { name == "inflate" && definingClass == "Landroid/view/ViewStub;" },
after(Opcode.MOVE_RESULT_OBJECT()),
)
}
internal val BytecodePatchContext.overlayViewInflateMethod by gettingFirstMethodDeclaratively {
internal val overlayViewInflateMethodMatch = firstMethodComposite {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("V")
parameterTypes("Landroid/view/View;")
instructions(
ResourceType.ID("heatseeker_viewstub"),
ResourceType.ID("fullscreen_button"),
checkCast("Landroid/widget/ImageView;"),
allOf(Opcode.CHECK_CAST(), type("Landroid/widget/ImageView;")),
)
}
/**
* 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)
returnType("V")
parameterTypes("Z", "Z")
}
internal val BytecodePatchContext.playerBottomControlsExploderFeatureFlagMethod by gettingFirstMethodDeclaratively {
internal val BytecodePatchContext.playerBottomControlsExploderFeatureFlagMethod by gettingFirstMutableMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("Z")
parameterTypes()
instructions(
45643739L(),
)
instructions(45643739L())
}
internal val BytecodePatchContext.playerTopControlsExperimentalLayoutFeatureFlagMethod by gettingFirstMethodDeclaratively {
internal val BytecodePatchContext.playerTopControlsExperimentalLayoutFeatureFlagMethod by gettingFirstMutableMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("I")
parameterTypes()
instructions(
45629424L(),
)
instructions(45629424L())
}
internal val BytecodePatchContext.playerControlsLargeOverlayButtonsFeatureFlagMethod by gettingFirstMethodDeclaratively {
internal val BytecodePatchContext.playerControlsLargeOverlayButtonsFeatureFlagMethod by gettingFirstMutableMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("Z")
parameterTypes()
instructions(
45709810L(),
)
instructions(45709810L())
}
internal val BytecodePatchContext.playerControlsFullscreenLargeButtonsFeatureFlagMethod by gettingFirstMethodDeclaratively {
internal val BytecodePatchContext.playerControlsFullscreenLargeButtonsFeatureFlagMethod by gettingFirstMutableMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("Z")
parameterTypes()
instructions(
45686474L(),
)
instructions(45686474L())
}
internal val BytecodePatchContext.playerControlsButtonStrokeFeatureFlagMethod by gettingFirstMethodDeclaratively {
internal val BytecodePatchContext.playerControlsButtonStrokeFeatureFlagMethod by gettingFirstMutableMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("Z")
parameterTypes()
instructions(
45713296L(),
)
instructions(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.getInstruction
import app.revanced.patcher.immutableClassDef
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.resourcePatch
import app.revanced.patcher.util.Document
import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
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.is_19_35_or_greater
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 app.revanced.patches.youtube.misc.playservice.*
import app.revanced.util.*
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.mutable.MutableMethod
@@ -244,51 +233,44 @@ val playerControlsPatch = bytecodePatch(
)
apply {
playerBottomControlsInflateMethod.let {
it.method.apply {
inflateBottomControlMethod = this
playerBottomControlsInflateMethodMatch.method.apply {
inflateBottomControlMethod = this
val inflateReturnObjectIndex = it.indices.last()
inflateBottomControlRegister = getInstruction<OneRegisterInstruction>(inflateReturnObjectIndex).registerA
inflateBottomControlInsertIndex = inflateReturnObjectIndex + 1
}
val inflateReturnObjectIndex = playerBottomControlsInflateMethodMatch.indices.last()
inflateBottomControlRegister = getInstruction<OneRegisterInstruction>(inflateReturnObjectIndex).registerA
inflateBottomControlInsertIndex = inflateReturnObjectIndex + 1
}
playerTopControlsInflateMethod.let {
it.method.apply {
inflateTopControlMethod = this
playerTopControlsInflateMethod.method.apply {
inflateTopControlMethod = this
val inflateReturnObjectIndex = it.indices.last()
inflateTopControlRegister = getInstruction<OneRegisterInstruction>(inflateReturnObjectIndex).registerA
inflateTopControlInsertIndex = inflateReturnObjectIndex + 1
}
val inflateReturnObjectIndex = playerTopControlsInflateMethod.indices.last()
inflateTopControlRegister = getInstruction<OneRegisterInstruction>(inflateReturnObjectIndex).registerA
inflateTopControlInsertIndex = inflateReturnObjectIndex + 1
}
visibilityMethod = controlsOverlayVisibilityMethod.match(
playerTopControlsInflateMethod.originalClassDef,
).method
visibilityMethod =
playerTopControlsInflateMethod.immutableClassDef.getControlsOverlayVisibilityMethod()
// Hook the fullscreen close button. Used to fix visibility
// when seeking and other situations.
overlayViewInflateMethod.let {
it.method.apply {
val index = it.indices.last()
val register = getInstruction<OneRegisterInstruction>(index).registerA
overlayViewInflateMethodMatch.method.apply {
val index = overlayViewInflateMethodMatch.indices.last()
val register = getInstruction<OneRegisterInstruction>(index).registerA
addInstruction(
index + 1,
"invoke-static { v$register }, " +
"$EXTENSION_CLASS_DESCRIPTOR->setFullscreenCloseButton(Landroid/widget/ImageView;)V",
)
}
addInstruction(
index + 1,
"invoke-static { v$register }, " +
"$EXTENSION_CLASS_DESCRIPTOR->setFullscreenCloseButton(Landroid/widget/ImageView;)V",
)
}
visibilityImmediateCallbacksExistMethod = playerControlsExtensionHookListenersExistMethod
visibilityImmediateMethod = playerControlsExtensionHookMethod
motionEventMethod.match(youtubeControlsOverlayMethod.originalClassDef).let {
motionEventMethodMatch.match(youtubeControlsOverlayMethod.immutableClassDef).let {
visibilityNegatedImmediateMethod = it.method
visibilityNegatedImmediateInsertIndex = it.instructionMatches.first().index + 1
visibilityNegatedImmediateInsertIndex = it.indices.first() + 1
}
// A/B test for a slightly different bottom overlay controls,

View File

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

View File

@@ -1,50 +1,38 @@
package app.revanced.patches.youtube.misc.settings
import app.revanced.patcher.accessFlags
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.*
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import app.revanced.patches.shared.misc.mapping.ResourceType
import com.android.tools.smali.dexlib2.AccessFlags
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)
returnType("V")
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)
returnType("L")
parameterTypes()
instructions(
ResourceType.STRING("app_theme_appearance_dark"),
)
instructions(ResourceType.STRING("app_theme_appearance_dark"))
}
internal val BytecodePatchContext.cairoFragmentConfigMethod by gettingFirstMethodDeclaratively {
internal val cairoFragmentConfigMethodMatch = firstMethodComposite {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("Z")
instructions(
45532100L(),
afterAtMost(10, Opcode.MOVE_RESULT()),
)
}
// 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.
internal val BytecodePatchContext.boldIconsFeatureFlagMethod by gettingFirstMethodDeclaratively {
internal val boldIconsFeatureFlagMethod = firstMethodComposite {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("Z")
parameterTypes()

View File

@@ -1,5 +1,6 @@
package app.revanced.patches.youtube.misc.settings
import app.revanced.patcher.classDef
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.patch.bytecodePatch
@@ -239,8 +240,8 @@ val settingsPatch = bytecodePatch(
}
// Add setting to force Cairo settings fragment on/off.
cairoFragmentConfigMethod.insertLiteralOverride(
cairoFragmentConfigMethod.instructionMatches.first().index,
cairoFragmentConfigMethodMatch.method.insertLiteralOverride(
cairoFragmentConfigMethodMatch.indices.first(),
"$YOUTUBE_ACTIVITY_HOOK_CLASS_DESCRIPTOR->useCairoSettingsFragment(Z)Z",
)
@@ -249,7 +250,7 @@ val settingsPatch = bytecodePatch(
if (is_20_31_or_greater) {
boldIconsFeatureFlagMethod.let {
it.method.insertLiteralOverride(
it.instructionMatches.first().index,
it.indices.first(),
"$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.
videoQualityBottomSheetListFragmentname = getResourceId(
ResourceType.LAYOUT,
"video_quality_bottom_sheet_list_fragment_title",
)
videoQualityQuickMenuAdvancedMenuDescription = getResourceId(
ResourceType.STRING,
"video_quality_quick_menu_advanced_menu_description",
)
videoQualityBottomSheetListFragmentname =
ResourceType.LAYOUT["video_quality_bottom_sheet_list_fragment_title"]
videoQualityQuickMenuAdvancedMenuDescription =
ResourceType.STRING["video_quality_quick_menu_advanced_menu_description"]
// region Patch for the old type of the video quality menu.
// Used for regular videos when spoofing to old app version,
// and for the Shorts quality flyout on newer app versions.
videoQualityMenuViewInflateMethod.let {
videoQualityMenuViewInflateMethodMatch.let {
it.method.apply {
val checkCastIndex = it.indices.last()
val listViewRegister = getInstruction<OneRegisterInstruction>(checkCastIndex).registerA
@@ -74,10 +69,10 @@ internal val advancedVideoQualityMenuPatch = bytecodePatch {
}
// Force YT to add the 'advanced' quality menu for Shorts.
videoQualityMenuOptionsMethod.let {
val patternMatch = it.instructionMatches
val startIndex = patternMatch.first().index
val insertIndex = patternMatch.last().index
videoQualityMenuOptionsMethodMatch.let {
val startIndex = it.indices.first()
val insertIndex = it.indices.last()
if (startIndex != 0) throw PatchException("Unexpected opcode start index: $startIndex")
it.method.apply {

View File

@@ -1,9 +1,10 @@
package app.revanced.patches.youtube.video.quality
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.instructions
import app.revanced.patcher.name
import app.revanced.patcher.opcodes
import app.revanced.patcher.parameterTypes
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.Opcode
internal val BytecodePatchContext.videoQualityItemOnClickParentMethod by gettingFirstMethodDeclaratively {
internal val BytecodePatchContext.videoQualityItemOnClickParentMethod by gettingFirstMethodDeclaratively(
"VIDEO_QUALITIES_MENU_BOTTOM_SHEET_FRAGMENT",
) {
returnType("V")
instructions(
"VIDEO_QUALITIES_MENU_BOTTOM_SHEET_FRAGMENT"(),
)
}
/**
* Resolves to class found in [videoQualityItemOnClickMethod].
*/
internal val BytecodePatchContext.videoQualityItemOnClickMethod by gettingFirstMethodDeclaratively {
context(_: BytecodePatchContext)
internal fun com.android.tools.smali.dexlib2.iface.ClassDef.getVideoQualityItemOnClickMethod() = firstMutableMethodDeclaratively {
name("onItemClick")
returnType("V")
parameterTypes(
"Landroid/widget/AdapterView;",
@@ -30,12 +29,9 @@ internal val BytecodePatchContext.videoQualityItemOnClickMethod by gettingFirstM
"I",
"J",
)
custom { method, _ ->
method.name == "onItemClick"
}
}
internal val BytecodePatchContext.videoQualityMenuOptionsMethod by gettingFirstMethodDeclaratively {
internal val videoQualityMenuOptionsMethodMatch = firstMethodComposite {
accessFlags(AccessFlags.STATIC)
returnType("[L")
parameterTypes("Landroid/content/Context", "L", "L")
@@ -49,7 +45,7 @@ internal val BytecodePatchContext.videoQualityMenuOptionsMethod by gettingFirstM
literal { videoQualityQuickMenuAdvancedMenuDescription }
}
internal val BytecodePatchContext.videoQualityMenuViewInflateMethod by gettingFirstMethodDeclaratively {
internal val videoQualityMenuViewInflateMethodMatch = firstMethodComposite {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("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.getInstruction
import app.revanced.patcher.immutableClassDef
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch
@@ -64,9 +65,7 @@ val rememberVideoQualityPatch = bytecodePatch {
onCreateHook(EXTENSION_CLASS_DESCRIPTOR, "newVideoStarted")
// Inject a call to remember the selected quality for Shorts.
videoQualityItemOnClickMethod.match(
videoQualityItemOnClickParentMethod.classDef,
).method.addInstruction(
videoQualityItemOnClickParentMethod.immutableClassDef.getVideoQualityItemOnClickMethod().addInstruction(
0,
"invoke-static { p3 }, $EXTENSION_CLASS_DESCRIPTOR->userChangedShortsQuality(I)V",
)