From c9ea5a2f19b98df283383c926a68f849ae684800 Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Wed, 29 Jan 2025 20:22:57 +0900 Subject: [PATCH] fix(YouTube - Settings): All patches fail due to patch in some environments https://github.com/inotia00/ReVanced_Extended/issues/2730 --- .../utils/fix/cairo/CairoFragmentPatch.kt | 152 +++++++++--------- .../youtube/utils/fix/cairo/Fingerprints.kt | 23 +++ 2 files changed, 100 insertions(+), 75 deletions(-) diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/fix/cairo/CairoFragmentPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/fix/cairo/CairoFragmentPatch.kt index 7dcb6f3bf..ae2d3c8cf 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/fix/cairo/CairoFragmentPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/fix/cairo/CairoFragmentPatch.kt @@ -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()?.toString() == cairoFragmentConfigMethodCall + } + 2 + val insertRegister = getInstruction(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()?.toString() == cairoFragmentConfigMethodCall - } + 2 - val insertRegister = getInstruction(insertIndex - 1).registerA - - addInstruction(insertIndex, "const/4 v$insertRegister, 0x0") - } - - settingsFragmentSyntheticFingerprint.methodOrThrow().apply { - val literalIndex = indexOfFirstLiteralInstructionOrThrow(settingsFragmentCairo) - val fragmentStylePrimaryIndex = indexOfFirstInstructionOrThrow(literalIndex) { - val reference = getReference() - opcode == Opcode.INVOKE_VIRTUAL_RANGE && - reference?.returnType == "V" && - reference.parameterTypes.firstOrNull() == "Ljava/lang/String;" - } - val fragmentStyleSecondaryIndex = indexOfFirstInstructionOrThrow(literalIndex) { - val reference = getReference() - 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() - } - } - } } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/fix/cairo/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/fix/cairo/Fingerprints.kt index 1e592cbc8..d96edd681 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/fix/cairo/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/fix/cairo/Fingerprints.kt @@ -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;", + ), +) \ No newline at end of file