fix(YouTube - Settings): All patches fail due to patch in some environments https://github.com/inotia00/ReVanced_Extended/issues/2730

This commit is contained in:
inotia00 2025-01-29 20:22:57 +09:00
parent 52318b194e
commit c9ea5a2f19
2 changed files with 100 additions and 75 deletions

View File

@ -5,26 +5,32 @@ import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.resourcePatch
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patches.youtube.utils.extension.sharedExtensionPatch
import app.revanced.patches.youtube.utils.playservice.is_19_34_or_greater
import app.revanced.patches.youtube.utils.playservice.versionCheckPatch
import app.revanced.patches.youtube.utils.resourceid.settingsFragmentCairo
import app.revanced.patches.youtube.utils.resourceid.sharedResourceIdPatch
import app.revanced.util.Utils.printWarn
import app.revanced.util.fingerprint.methodCall
import app.revanced.util.fingerprint.methodOrThrow
import app.revanced.util.getReference
import app.revanced.util.getWalkerMethod
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstLiteralInstructionOrThrow
import app.revanced.util.insertNode
import app.revanced.util.returnEarly
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
import org.w3c.dom.Element
private val cairoFragmentResourcePatch = resourcePatch(
description = "cairoFragmentResourcePatch"
private var cairoFragmentDisabled = false
private val cairoFragmentBytecodePatch = bytecodePatch(
description = "cairoFragmentBytecodePatch"
) {
dependsOn(versionCheckPatch)
dependsOn(
sharedExtensionPatch,
sharedResourceIdPatch,
versionCheckPatch
)
execute {
/**
@ -34,6 +40,71 @@ private val cairoFragmentResourcePatch = resourcePatch(
return@execute
}
// Instead of disabling all Cairo fragment configs,
// Just disable 'Load Cairo fragment xml' and 'Set style to Cairo preference'.
fun MutableMethod.disableCairoFragmentConfig() {
val cairoFragmentConfigMethodCall = cairoFragmentConfigFingerprint
.methodCall()
val insertIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.INVOKE_VIRTUAL &&
getReference<MethodReference>()?.toString() == cairoFragmentConfigMethodCall
} + 2
val insertRegister = getInstruction<OneRegisterInstruction>(insertIndex - 1).registerA
addInstruction(insertIndex, "const/4 v$insertRegister, 0x0")
}
try {
arrayOf(
// Load cairo fragment xml.
settingsFragmentSyntheticFingerprint
.methodOrThrow(),
// Set style to cairo preference.
settingsFragmentStylePrimaryFingerprint
.methodOrThrow(),
settingsFragmentStyleSecondaryFingerprint
.methodOrThrow(settingsFragmentStylePrimaryFingerprint),
).forEach { method ->
method.disableCairoFragmentConfig()
}
cairoFragmentDisabled = true
} catch (_: Exception) {
cairoFragmentConfigFingerprint
.methodOrThrow()
.returnEarly()
printWarn("Failed to restore 'Playback' settings. 'Autoplay next video' setting may not appear in the YouTube settings.")
}
}
}
/**
* What [cairoFragmentPatch] does:
* 1. Disable Cairo fragment settings.
* 2. Fix - When spoofing the app version to 19.20 or earlier, the app crashes or the Notifications tab is inaccessible.
* 3. Fix - Preference 'Playback' is hidden.
* 4. Some settings that were in Preference 'General' are moved to Preference 'Playback'.
*/
val cairoFragmentPatch = resourcePatch(
description = "cairoFragmentPatch"
) {
dependsOn(
cairoFragmentBytecodePatch,
versionCheckPatch,
)
execute {
/**
* Cairo fragment have been widely rolled out in YouTube 19.34+.
*/
if (!is_19_34_or_greater) {
return@execute
}
if (!cairoFragmentDisabled) {
return@execute
}
/**
* The Preference key for 'Playback' is '@string/playback_key'.
* Copy the node to add the Preference 'Playback' to the legacy settings fragment.
@ -53,74 +124,5 @@ private val cairoFragmentResourcePatch = resourcePatch(
}
}
}
}
}
/**
* What [cairoFragmentPatch] does:
* 1. Disable Cairo fragment settings.
* 2. Fix - When spoofing the app version to 19.20 or earlier, the app crashes or the Notifications tab is inaccessible.
* 3. Fix - Preference 'Playback' is hidden.
* 4. Some settings that were in Preference 'General' are moved to Preference 'Playback'.
*/
val cairoFragmentPatch = bytecodePatch(
description = "cairoFragmentPatch"
) {
dependsOn(
cairoFragmentResourcePatch,
sharedResourceIdPatch,
versionCheckPatch
)
execute {
/**
* Cairo fragment have been widely rolled out in YouTube 19.34+.
*/
if (!is_19_34_or_greater) {
return@execute
}
// Instead of disabling all Cairo fragment configs,
// Just disable 'Load Cairo fragment xml' and 'Set style to Cairo preference'.
val cairoFragmentConfigMethodCall = cairoFragmentConfigFingerprint
.methodCall()
fun MutableMethod.disableCairoFragmentConfig() {
val insertIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.INVOKE_VIRTUAL &&
getReference<MethodReference>()?.toString() == cairoFragmentConfigMethodCall
} + 2
val insertRegister = getInstruction<OneRegisterInstruction>(insertIndex - 1).registerA
addInstruction(insertIndex, "const/4 v$insertRegister, 0x0")
}
settingsFragmentSyntheticFingerprint.methodOrThrow().apply {
val literalIndex = indexOfFirstLiteralInstructionOrThrow(settingsFragmentCairo)
val fragmentStylePrimaryIndex = indexOfFirstInstructionOrThrow(literalIndex) {
val reference = getReference<MethodReference>()
opcode == Opcode.INVOKE_VIRTUAL_RANGE &&
reference?.returnType == "V" &&
reference.parameterTypes.firstOrNull() == "Ljava/lang/String;"
}
val fragmentStyleSecondaryIndex = indexOfFirstInstructionOrThrow(literalIndex) {
val reference = getReference<MethodReference>()
opcode == Opcode.INVOKE_VIRTUAL &&
reference?.returnType == "V" &&
reference.parameterTypes == listOf("Ljava/util/List;", "Landroidx/preference/Preference;")
}
arrayOf(
// Load cairo fragment xml.
this,
// Set style to cairo preference.
getWalkerMethod(fragmentStylePrimaryIndex),
getWalkerMethod(fragmentStyleSecondaryIndex)
).forEach { method ->
method.disableCairoFragmentConfig()
}
}
}
}

View File

@ -29,3 +29,26 @@ internal val settingsFragmentSyntheticFingerprint = legacyFingerprint(
opcodes = listOf(Opcode.INVOKE_VIRTUAL_RANGE),
literals = listOf(settingsFragment, settingsFragmentCairo),
)
internal val settingsFragmentStylePrimaryFingerprint = legacyFingerprint(
name = "settingsFragmentStylePrimaryFingerprint",
returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf(
"Ljava/lang/String;",
"Ljava/util/List;",
"Landroidx/preference/Preference;",
"Lj${'$'}/util/Optional;",
"Lj${'$'}/util/Optional;",
),
)
internal val settingsFragmentStyleSecondaryFingerprint = legacyFingerprint(
name = "settingsFragmentStyleSecondaryFingerprint",
returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf(
"Ljava/util/List;",
"Landroidx/preference/Preference;",
),
)