feat(YouTube): Support version 19.12, 19.13, 19.14, 19.15 and 19.16 (#3239)

Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
This commit is contained in:
LisoUseInAIKyrios 2024-06-01 22:03:06 +04:00
parent 999cf733f7
commit 99b07e0e18
67 changed files with 491 additions and 196 deletions

View file

@ -1889,7 +1889,11 @@ public final class app/revanced/util/BytecodeUtilsKt {
public static final fun containsWideLiteralInstructionValue (Lcom/android/tools/smali/dexlib2/iface/Method;J)Z public static final fun containsWideLiteralInstructionValue (Lcom/android/tools/smali/dexlib2/iface/Method;J)Z
public static final fun findMutableMethodOf (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableClass;Lcom/android/tools/smali/dexlib2/iface/Method;)Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod; public static final fun findMutableMethodOf (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableClass;Lcom/android/tools/smali/dexlib2/iface/Method;)Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;
public static final fun getException (Lapp/revanced/patcher/fingerprint/MethodFingerprint;)Lapp/revanced/patcher/patch/PatchException; public static final fun getException (Lapp/revanced/patcher/fingerprint/MethodFingerprint;)Lapp/revanced/patcher/patch/PatchException;
public static final fun indexOfFirstInstruction (Lcom/android/tools/smali/dexlib2/iface/Method;ILkotlin/jvm/functions/Function1;)I
public static final fun indexOfFirstInstruction (Lcom/android/tools/smali/dexlib2/iface/Method;Lkotlin/jvm/functions/Function1;)I public static final fun indexOfFirstInstruction (Lcom/android/tools/smali/dexlib2/iface/Method;Lkotlin/jvm/functions/Function1;)I
public static synthetic fun indexOfFirstInstruction$default (Lcom/android/tools/smali/dexlib2/iface/Method;ILkotlin/jvm/functions/Function1;ILjava/lang/Object;)I
public static final fun indexOfFirstInstructionOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;ILkotlin/jvm/functions/Function1;)I
public static synthetic fun indexOfFirstInstructionOrThrow$default (Lcom/android/tools/smali/dexlib2/iface/Method;ILkotlin/jvm/functions/Function1;ILjava/lang/Object;)I
public static final fun indexOfFirstWideLiteralInstructionValue (Lcom/android/tools/smali/dexlib2/iface/Method;J)I public static final fun indexOfFirstWideLiteralInstructionValue (Lcom/android/tools/smali/dexlib2/iface/Method;J)I
public static final fun indexOfIdResource (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/String;)I public static final fun indexOfIdResource (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/String;)I
public static final fun indexOfIdResourceOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/String;)I public static final fun indexOfIdResourceOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/String;)I

View file

@ -11,7 +11,7 @@ import app.revanced.patches.reddit.customclients.redditisfun.api.fingerprints.Ba
import app.revanced.patches.reddit.customclients.redditisfun.api.fingerprints.BuildAuthorizationStringFingerprint import app.revanced.patches.reddit.customclients.redditisfun.api.fingerprints.BuildAuthorizationStringFingerprint
import app.revanced.patches.reddit.customclients.redditisfun.api.fingerprints.GetUserAgentFingerprint import app.revanced.patches.reddit.customclients.redditisfun.api.fingerprints.GetUserAgentFingerprint
import app.revanced.util.getReference import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction import app.revanced.util.indexOfFirstInstructionOrThrow
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.StringReference import com.android.tools.smali.dexlib2.iface.reference.StringReference
@Suppress("unused") @Suppress("unused")
@ -68,7 +68,7 @@ object SpoofClientPatch : BaseSpoofClientPatch(
// Reddit messed up and does not append a redirect uri to the authorization url to old.reddit.com/login. // Reddit messed up and does not append a redirect uri to the authorization url to old.reddit.com/login.
// Replace old.reddit.com with ssl.reddit.com to fix this. // Replace old.reddit.com with ssl.reddit.com to fix this.
BuildAuthorizationStringFingerprint.result!!.mutableMethod.apply { BuildAuthorizationStringFingerprint.result!!.mutableMethod.apply {
val index = indexOfFirstInstruction { val index = indexOfFirstInstructionOrThrow {
getReference<StringReference>()?.contains("old.reddit.com") == true getReference<StringReference>()?.contains("old.reddit.com") == true
} }

View file

@ -11,7 +11,7 @@ import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.tiktok.interaction.cleardisplay.fingerprints.OnClearDisplayEventFingerprint import app.revanced.patches.tiktok.interaction.cleardisplay.fingerprints.OnClearDisplayEventFingerprint
import app.revanced.patches.tiktok.interaction.cleardisplay.fingerprints.OnRenderFirstFrameFingerprint import app.revanced.patches.tiktok.interaction.cleardisplay.fingerprints.OnRenderFirstFrameFingerprint
import app.revanced.util.exception import app.revanced.util.exception
import app.revanced.util.indexOfFirstInstruction import app.revanced.util.indexOfFirstInstructionOrThrow
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction22c import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction22c
@ -34,7 +34,7 @@ object RememberClearDisplayPatch : BytecodePatch(
OnClearDisplayEventFingerprint.result?.mutableMethod?.let { OnClearDisplayEventFingerprint.result?.mutableMethod?.let {
// region Hook the "Clear display" configuration save event to remember the state of clear display. // region Hook the "Clear display" configuration save event to remember the state of clear display.
val isEnabledIndex = it.indexOfFirstInstruction { opcode == Opcode.IGET_BOOLEAN } + 1 val isEnabledIndex = it.indexOfFirstInstructionOrThrow { opcode == Opcode.IGET_BOOLEAN } + 1
val isEnabledRegister = it.getInstruction<Instruction22c>(isEnabledIndex - 1).registerA val isEnabledRegister = it.getInstruction<Instruction22c>(isEnabledIndex - 1).registerA
it.addInstructions( it.addInstructions(

View file

@ -18,7 +18,7 @@ import app.revanced.patches.tiktok.misc.integrations.IntegrationsPatch
import app.revanced.patches.tiktok.misc.settings.SettingsPatch import app.revanced.patches.tiktok.misc.settings.SettingsPatch
import app.revanced.patches.tiktok.misc.settings.fingerprints.SettingsStatusLoadFingerprint import app.revanced.patches.tiktok.misc.settings.fingerprints.SettingsStatusLoadFingerprint
import app.revanced.util.exception import app.revanced.util.exception
import app.revanced.util.indexOfFirstInstruction import app.revanced.util.indexOfFirstInstructionOrThrow
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c
import com.android.tools.smali.dexlib2.iface.reference.MethodReference import com.android.tools.smali.dexlib2.iface.reference.MethodReference
@ -81,16 +81,16 @@ object DownloadsPatch : BytecodePatch(
}, },
// Change the download path patch. // Change the download path patch.
DownloadPathParentFingerprint to { DownloadPathParentFingerprint to {
val targetIndex = indexOfFirstInstruction { opcode == Opcode.INVOKE_STATIC } val targetIndex = indexOfFirstInstructionOrThrow { opcode == Opcode.INVOKE_STATIC }
val downloadUriMethod = context val downloadUriMethod = context
.toMethodWalker(this) .toMethodWalker(this)
.nextMethod(targetIndex, true) .nextMethod(targetIndex, true)
.getMethod() as MutableMethod .getMethod() as MutableMethod
val firstIndex = downloadUriMethod.indexOfFirstInstruction { val firstIndex = downloadUriMethod.indexOfFirstInstructionOrThrow {
opcode == Opcode.INVOKE_DIRECT && ((this as Instruction35c).reference as MethodReference).name == "<init>" opcode == Opcode.INVOKE_DIRECT && ((this as Instruction35c).reference as MethodReference).name == "<init>"
} }
val secondIndex = downloadUriMethod.indexOfFirstInstruction { val secondIndex = downloadUriMethod.indexOfFirstInstructionOrThrow {
opcode == Opcode.INVOKE_STATIC && ((this as Instruction35c).reference as MethodReference).returnType.contains( opcode == Opcode.INVOKE_STATIC && ((this as Instruction35c).reference as MethodReference).returnType.contains(
"Uri" "Uri"
) )

View file

@ -14,6 +14,7 @@ import app.revanced.patches.tiktok.interaction.speed.fingerprints.SetSpeedFinger
import app.revanced.util.exception import app.revanced.util.exception
import app.revanced.util.getReference import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction import app.revanced.util.indexOfFirstInstruction
import app.revanced.util.indexOfFirstInstructionOrThrow
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction11x import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction11x
import com.android.tools.smali.dexlib2.iface.reference.MethodReference import com.android.tools.smali.dexlib2.iface.reference.MethodReference
@ -38,7 +39,7 @@ object PlaybackSpeedPatch : BytecodePatch(
SetSpeedFingerprint.result?.let { onVideoSwiped -> SetSpeedFingerprint.result?.let { onVideoSwiped ->
// Remember the playback speed of the current video. // Remember the playback speed of the current video.
GetSpeedFingerprint.result?.mutableMethod?.apply { GetSpeedFingerprint.result?.mutableMethod?.apply {
val injectIndex = indexOfFirstInstruction { getReference<MethodReference>()?.returnType == "F" } + 2 val injectIndex = indexOfFirstInstructionOrThrow { getReference<MethodReference>()?.returnType == "F" } + 2
val register = getInstruction<Instruction11x>(injectIndex - 1).registerA val register = getInstruction<Instruction11x>(injectIndex - 1).registerA
addInstruction( addInstruction(

View file

@ -44,7 +44,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
], ],
), ),
], ],

View file

@ -38,7 +38,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
] ]
) )
] ]

View file

@ -43,7 +43,12 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
] ]
) )
] ]

View file

@ -31,7 +31,12 @@ import app.revanced.patches.youtube.video.information.VideoInformationPatch
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
], ],
), ),
], ],

View file

@ -40,7 +40,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
] ]
) )
] ]

View file

@ -37,7 +37,12 @@ import app.revanced.util.resultOrThrow
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
], ],
), ),
], ],

View file

@ -40,7 +40,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
] ]
) )
] ]

View file

@ -42,7 +42,12 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
] ]
) )
] ]

View file

@ -38,7 +38,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
] ]
) )
], ],

View file

@ -44,10 +44,12 @@ import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43", // 19.12.x has an issue with opening YT using external links, "19.11.43",
// and the app then crashes if double tap to skip forward/back is immediately used. "19.12.41",
// The stack trace shows a call coming from integrations SwipeController, "19.13.37",
// but it may be a bug in YT itself as other target versions do not have this issue. "19.14.43",
"19.15.36",
"19.16.39",
], ],
), ),
], ],

View file

@ -42,7 +42,12 @@ import app.revanced.util.exception
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
] ]
) )
], ],

View file

@ -41,7 +41,12 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
] ]
) )
] ]

View file

@ -13,11 +13,12 @@ import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
import app.revanced.patches.youtube.misc.settings.SettingsPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch
import app.revanced.patches.youtube.shared.fingerprints.LayoutConstructorFingerprint import app.revanced.patches.youtube.shared.fingerprints.LayoutConstructorFingerprint
import app.revanced.util.exception import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfIdResourceOrThrow import app.revanced.util.indexOfIdResourceOrThrow
import com.android.tools.smali.dexlib2.iface.instruction.Instruction import app.revanced.util.resultOrThrow
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.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference import com.android.tools.smali.dexlib2.iface.reference.MethodReference
@Patch( @Patch(
@ -52,6 +53,11 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43", "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
], ],
), ),
], ],
@ -60,6 +66,10 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
object HideAutoplayButtonPatch : BytecodePatch( object HideAutoplayButtonPatch : BytecodePatch(
setOf(LayoutConstructorFingerprint), setOf(LayoutConstructorFingerprint),
) { ) {
private const val INTEGRATIONS_CLASS_DESCRIPTOR =
"Lapp/revanced/integrations/youtube/patches/HideAutoplayButtonPatch;"
override fun execute(context: BytecodeContext) { override fun execute(context: BytecodeContext) {
AddResourcesPatch(this::class) AddResourcesPatch(this::class)
@ -67,33 +77,27 @@ object HideAutoplayButtonPatch : BytecodePatch(
SwitchPreference("revanced_hide_autoplay_button"), SwitchPreference("revanced_hide_autoplay_button"),
) )
LayoutConstructorFingerprint.result?.mutableMethod?.apply { LayoutConstructorFingerprint.resultOrThrow().mutableMethod.apply {
val layoutGenMethodInstructions = implementation!!.instructions val constIndex = indexOfIdResourceOrThrow("autonav_toggle")
val constRegister = getInstruction<OneRegisterInstruction>(constIndex).registerA
// resolve the offsets of where to insert the branch instructions and ... // Add a conditional branch around the code that inflates and adds the auto repeat button.
val insertIndex = indexOfIdResourceOrThrow("autonav_preview_stub") val gotoIndex = indexOfFirstInstructionOrThrow(constIndex) {
val parameterTypes = getReference<MethodReference>()?.parameterTypes
// where to branch away opcode == Opcode.INVOKE_VIRTUAL &&
val branchIndex = parameterTypes?.size == 2 &&
layoutGenMethodInstructions.subList(insertIndex + 1, layoutGenMethodInstructions.size - 1) parameterTypes.first() == "Landroid/view/ViewStub;"
.indexOfFirst { } + 1
((it as? ReferenceInstruction)?.reference as? MethodReference)?.name == "addOnLayoutChangeListener"
} + 2
val jumpInstruction = layoutGenMethodInstructions[insertIndex + branchIndex] as Instruction
// can be clobbered because this register is overwritten after the injected code
val clobberRegister = getInstruction<OneRegisterInstruction>(insertIndex).registerA
addInstructionsWithLabels( addInstructionsWithLabels(
insertIndex, constIndex,
""" """
invoke-static {}, Lapp/revanced/integrations/youtube/patches/HideAutoplayButtonPatch;->isButtonShown()Z invoke-static {}, $INTEGRATIONS_CLASS_DESCRIPTOR->hideAutoPlayButton()Z
move-result v$clobberRegister move-result v$constRegister
if-eqz v$clobberRegister, :hidden if-nez v$constRegister, :hidden
""", """,
ExternalLabel("hidden", jumpInstruction), ExternalLabel("hidden", getInstruction(gotoIndex)),
) )
} ?: throw LayoutConstructorFingerprint.exception }
} }
} }

View file

@ -42,7 +42,12 @@ import com.android.tools.smali.dexlib2.Opcode
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
] ]
) )
] ]

View file

@ -19,7 +19,7 @@ import app.revanced.patches.youtube.misc.navigation.NavigationBarHookPatch
import app.revanced.patches.youtube.misc.settings.SettingsPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch
import app.revanced.util.exception import app.revanced.util.exception
import app.revanced.util.getReference import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction import app.revanced.util.indexOfFirstInstructionOrThrow
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference import com.android.tools.smali.dexlib2.iface.reference.MethodReference
@ -56,6 +56,11 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43", "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
], ],
), ),
], ],
@ -111,7 +116,7 @@ object NavigationButtonsPatch : BytecodePatch(
// Hide navigation button labels. // Hide navigation button labels.
CreatePivotBarFingerprint.result?.mutableMethod?.apply { CreatePivotBarFingerprint.result?.mutableMethod?.apply {
val setTextIndex = indexOfFirstInstruction { val setTextIndex = indexOfFirstInstructionOrThrow {
getReference<MethodReference>()?.name == "setText" getReference<MethodReference>()?.name == "setText"
} }

View file

@ -46,7 +46,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction3rc
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
] ]
) )
] ]

View file

@ -40,7 +40,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
] ]
) )
] ]

View file

@ -40,7 +40,12 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
] ]
) )
] ]

View file

@ -40,7 +40,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
] ]
) )
] ]

View file

@ -43,7 +43,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction21c
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
] ]
) )
] ]

View file

@ -40,7 +40,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
] ]
) )
] ]

View file

@ -36,7 +36,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
] ]
) )
] ]

View file

@ -36,7 +36,12 @@ import app.revanced.util.exception
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
] ]
) )
] ]

View file

@ -23,7 +23,6 @@ import app.revanced.patches.youtube.misc.navigation.NavigationBarHookPatch
import app.revanced.patches.youtube.misc.settings.SettingsPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
@ -59,7 +58,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
], ],
), ),
], ],
@ -164,20 +168,21 @@ object HideLayoutComponentsPatch : BytecodePatch(
// region Mix playlists // region Mix playlists
ParseElementFromBufferFingerprint.resultOrThrow().let { result -> ParseElementFromBufferFingerprint.resultOrThrow().let { result ->
val consumeByteBufferIndex = result.scanResult.patternScanResult!!.startIndex val startIndex = result.scanResult.patternScanResult!!.startIndex
result.mutableMethod.apply { result.mutableMethod.apply {
val conversionContextRegister = val freeRegister = "v0"
getInstruction<TwoRegisterInstruction>(consumeByteBufferIndex - 2).registerA val byteArrayParameter = "p3"
val byteBufferRegister = getInstruction<FiveRegisterInstruction>(consumeByteBufferIndex).registerD val conversionContextRegister = getInstruction<TwoRegisterInstruction>(startIndex).registerA
val returnEmptyComponentInstruction = getInstructions().last { it.opcode == Opcode.INVOKE_STATIC } val returnEmptyComponentInstruction = getInstructions().last { it.opcode == Opcode.INVOKE_STATIC }
addInstructionsWithLabels( addInstructionsWithLabels(
consumeByteBufferIndex, startIndex + 1,
""" """
invoke-static {v$conversionContextRegister, v$byteBufferRegister}, $LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR->filterMixPlaylists(Ljava/lang/Object;[B)Z invoke-static { v$conversionContextRegister, $byteArrayParameter }, $LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR->filterMixPlaylists(Ljava/lang/Object;[B)Z
move-result v0 # Conveniently same register happens to be free. move-result $freeRegister
if-nez v0, :return_empty_component if-nez $freeRegister, :return_empty_component
const/4 $freeRegister, 0x0 # Restore register, required for 19.16
""", """,
ExternalLabel("return_empty_component", returnEmptyComponentInstruction), ExternalLabel("return_empty_component", returnEmptyComponentInstruction),
) )

View file

@ -4,7 +4,11 @@ import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
internal object ParseElementFromBufferFingerprint : MethodFingerprint( internal object ParseElementFromBufferFingerprint : MethodFingerprint(
parameters = listOf("L","L","[B", "L","L"), parameters = listOf("L", "L", "[B", "L", "L"),
opcodes = listOf(Opcode.INVOKE_INTERFACE, Opcode.MOVE_RESULT_OBJECT), opcodes = listOf(
strings = listOf("Failed to parse Element") Opcode.IGET_OBJECT,
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT_OBJECT
),
strings = listOf("Failed to parse Element") // String is a partial match.
) )

View file

@ -47,7 +47,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
] ]
) )
] ]

View file

@ -41,7 +41,12 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
] ]
) )
] ]

View file

@ -38,7 +38,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
] ]
) )
] ]

View file

@ -43,7 +43,12 @@ import app.revanced.patches.youtube.shared.fingerprints.SeekbarOnDrawFingerprint
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
] ]
) )
] ]

View file

@ -55,6 +55,11 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43", "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
], ],
), ),
], ],

View file

@ -35,7 +35,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
] ]
) )
] ]

View file

@ -36,7 +36,12 @@ import app.revanced.util.exception
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
] ]
) )
] ]

View file

@ -37,7 +37,12 @@ import app.revanced.util.exception
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
] ]
) )
] ]

View file

@ -32,7 +32,12 @@ import org.w3c.dom.Element
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
], ],
), ),
], ],

View file

@ -31,7 +31,7 @@ import app.revanced.patches.youtube.shared.fingerprints.RollingNumberTextViewAni
import app.revanced.patches.youtube.video.videoid.VideoIdPatch import app.revanced.patches.youtube.video.videoid.VideoIdPatch
import app.revanced.util.exception import app.revanced.util.exception
import app.revanced.util.getReference import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
@ -66,7 +66,12 @@ import com.android.tools.smali.dexlib2.iface.reference.TypeReference
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
] ]
) )
] ]
@ -142,11 +147,10 @@ object ReturnYouTubeDislikePatch : BytecodePatch(
TextComponentLookupFingerprint.resultOrThrow().mutableMethod.apply { TextComponentLookupFingerprint.resultOrThrow().mutableMethod.apply {
// Find the instruction for creating the text data object. // Find the instruction for creating the text data object.
val textDataClassType = TextComponentDataFingerprint.resultOrThrow().classDef.type val textDataClassType = TextComponentDataFingerprint.resultOrThrow().classDef.type
val insertIndex = indexOfFirstInstruction { val insertIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.NEW_INSTANCE && opcode == Opcode.NEW_INSTANCE &&
getReference<TypeReference>()?.type == textDataClassType getReference<TypeReference>()?.type == textDataClassType
} }
if (insertIndex < 0) throw PatchException("Could not find data creation instruction")
val tempRegister = getInstruction<OneRegisterInstruction>(insertIndex).registerA val tempRegister = getInstruction<OneRegisterInstruction>(insertIndex).registerA
// Find the instruction that sets the span to an instance field. // Find the instruction that sets the span to an instance field.
@ -335,7 +339,7 @@ object ReturnYouTubeDislikePatch : BytecodePatch(
realTimeUpdateTextViewMethod realTimeUpdateTextViewMethod
).forEach { insertMethod -> ).forEach { insertMethod ->
insertMethod.apply { insertMethod.apply {
val setTextIndex = indexOfFirstInstruction { val setTextIndex = indexOfFirstInstructionOrThrow {
getReference<MethodReference>()?.name == "setText" getReference<MethodReference>()?.name == "setText"
} }

View file

@ -41,7 +41,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
] ]
) )
] ]

View file

@ -37,7 +37,12 @@ import app.revanced.util.exception
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
] ]
) )
] ]

View file

@ -52,6 +52,11 @@ import com.android.tools.smali.dexlib2.iface.reference.StringReference
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43", "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
], ],
), ),
], ],

View file

@ -40,7 +40,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
] ]
) )
] ]

View file

@ -5,7 +5,6 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWith
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.all.misc.resources.AddResourcesPatch import app.revanced.patches.all.misc.resources.AddResourcesPatch
@ -15,7 +14,7 @@ import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
import app.revanced.patches.youtube.misc.settings.SettingsPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch
import app.revanced.util.exception import app.revanced.util.exception
import app.revanced.util.getReference import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction import app.revanced.util.indexOfFirstInstructionOrThrow
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
@ -46,7 +45,12 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
] ]
) )
] ]
@ -67,12 +71,11 @@ object DisableResumingShortsOnStartupPatch : BytecodePatch(
) )
UserWasInShortsFingerprint.result?.mutableMethod?.apply { UserWasInShortsFingerprint.result?.mutableMethod?.apply {
val listenableInstructionIndex = indexOfFirstInstruction { val listenableInstructionIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.INVOKE_INTERFACE && opcode == Opcode.INVOKE_INTERFACE &&
getReference<MethodReference>()?.definingClass == "Lcom/google/common/util/concurrent/ListenableFuture;" && getReference<MethodReference>()?.definingClass == "Lcom/google/common/util/concurrent/ListenableFuture;" &&
getReference<MethodReference>()?.name == "isDone" getReference<MethodReference>()?.name == "isDone"
} }
if (listenableInstructionIndex < 0) throw PatchException("Could not find instruction index")
val originalInstructionRegister = getInstruction<FiveRegisterInstruction>(listenableInstructionIndex).registerC val originalInstructionRegister = getInstruction<FiveRegisterInstruction>(listenableInstructionIndex).registerC
val freeRegister = getInstruction<OneRegisterInstruction>(listenableInstructionIndex + 1).registerA val freeRegister = getInstruction<OneRegisterInstruction>(listenableInstructionIndex + 1).registerA

View file

@ -45,7 +45,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
) )
) )
] ]

View file

@ -52,7 +52,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
] ]
) )
] ]

View file

@ -63,7 +63,12 @@ import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
], ],
), ),
], ],

View file

@ -41,7 +41,12 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
] ]
) )
] ]

View file

@ -36,7 +36,12 @@ import app.revanced.util.exception
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
] ]
) )
] ]

View file

@ -24,6 +24,7 @@ import app.revanced.patches.youtube.misc.fix.playback.fingerprints.PlayerGesture
import app.revanced.patches.youtube.misc.fix.playback.fingerprints.SetPlayerRequestClientTypeFingerprint import app.revanced.patches.youtube.misc.fix.playback.fingerprints.SetPlayerRequestClientTypeFingerprint
import app.revanced.patches.youtube.misc.settings.SettingsPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch
import app.revanced.util.getReference import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
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
@ -65,6 +66,11 @@ import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43", "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
], ],
), ),
], ],
@ -195,15 +201,14 @@ object SpoofClientPatch : BytecodePatch(
val clientInfoClientModelField = CreatePlayerRequestBodyWithModelFingerprint.resultOrThrow().let { val clientInfoClientModelField = CreatePlayerRequestBodyWithModelFingerprint.resultOrThrow().let {
val getClientModelIndex = CreatePlayerRequestBodyWithModelFingerprint.indexOfBuildModelInstruction(it.method) val getClientModelIndex = CreatePlayerRequestBodyWithModelFingerprint.indexOfBuildModelInstruction(it.method)
val instructions = it.mutableMethod.getInstructions()
// The next IPUT_OBJECT instruction after getting the client model is setting the client model field. // The next IPUT_OBJECT instruction after getting the client model is setting the client model field.
instructions.subList( val index = it.mutableMethod.indexOfFirstInstructionOrThrow(getClientModelIndex) {
getClientModelIndex, opcode == Opcode.IPUT_OBJECT
instructions.size, }
).find { instruction ->
instruction.opcode == Opcode.IPUT_OBJECT it.mutableMethod.getInstruction(index).getReference<FieldReference>()
}?.getReference<FieldReference>() ?: throw PatchException("Could not find clientInfoClientModelField") ?: throw PatchException("Could not find clientInfoClientModelField")
} }
// endregion // endregion

View file

@ -52,6 +52,11 @@ object GmsCoreSupportPatch : BaseGmsCoreSupportPatch(
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43", "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
), ),
), ),
), ),

View file

@ -12,7 +12,7 @@ import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
import app.revanced.patches.youtube.misc.links.fingerprints.ABUriParserFingerprint import app.revanced.patches.youtube.misc.links.fingerprints.ABUriParserFingerprint
import app.revanced.patches.youtube.misc.links.fingerprints.HTTPUriParserFingerprint import app.revanced.patches.youtube.misc.links.fingerprints.HTTPUriParserFingerprint
import app.revanced.patches.youtube.misc.settings.SettingsPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch
import app.revanced.util.exception import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
@Patch( @Patch(
@ -38,27 +38,32 @@ import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
] "19.12.41",
) "19.13.37",
] "19.14.43",
"19.15.36",
"19.16.39",
],
),
],
) )
@Suppress("unused") @Suppress("unused")
object BypassURLRedirectsPatch : BytecodePatch( object BypassURLRedirectsPatch : BytecodePatch(
setOf(ABUriParserFingerprint, HTTPUriParserFingerprint) setOf(ABUriParserFingerprint, HTTPUriParserFingerprint),
) { ) {
override fun execute(context: BytecodeContext) { override fun execute(context: BytecodeContext) {
AddResourcesPatch(this::class) AddResourcesPatch(this::class)
SettingsPatch.PreferenceScreen.MISC.addPreferences( SettingsPatch.PreferenceScreen.MISC.addPreferences(
SwitchPreference("revanced_bypass_url_redirects") SwitchPreference("revanced_bypass_url_redirects"),
) )
mapOf( mapOf(
ABUriParserFingerprint to 7, // Offset to Uri.parse. ABUriParserFingerprint to 7, // Offset to Uri.parse.
HTTPUriParserFingerprint to 0 // Offset to Uri.parse. HTTPUriParserFingerprint to 0, // Offset to Uri.parse.
).map { (fingerprint, offset) -> ).map { (fingerprint, offset) ->
(fingerprint.result ?: throw fingerprint.exception) to offset fingerprint.resultOrThrow() to offset
}.forEach { (result, offset) -> }.forEach { (result, offset) ->
result.mutableMethod.apply { result.mutableMethod.apply {
val insertIndex = result.scanResult.patternScanResult!!.startIndex + offset val insertIndex = result.scanResult.patternScanResult!!.startIndex + offset
@ -67,11 +72,11 @@ object BypassURLRedirectsPatch : BytecodePatch(
replaceInstruction( replaceInstruction(
insertIndex, insertIndex,
"invoke-static {v$uriStringRegister}," + "invoke-static {v$uriStringRegister}," +
"Lapp/revanced/integrations/youtube/patches/BypassURLRedirectsPatch;" + "Lapp/revanced/integrations/youtube/patches/BypassURLRedirectsPatch;" +
"->" + "->" +
"parseRedirectUri(Ljava/lang/String;)Landroid/net/Uri;" "parseRedirectUri(Ljava/lang/String;)Landroid/net/Uri;",
) )
} }
} }
} }
} }

View file

@ -42,7 +42,12 @@ import com.android.tools.smali.dexlib2.iface.reference.StringReference
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
] ]
) )
] ]

View file

@ -20,10 +20,14 @@ internal object ABUriParserFingerprint : MethodFingerprint(
Opcode.INVOKE_STATIC, Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT, Opcode.MOVE_RESULT_OBJECT,
Opcode.RETURN_OBJECT, Opcode.RETURN_OBJECT,
Opcode.CHECK_CAST Opcode.CHECK_CAST,
), ),
customFingerprint = { methodDef, classDef -> customFingerprint = custom@{ methodDef, classDef ->
// This method is always called "a" because this kind of class always has a single method. // This method is always called "a" because this kind of class always has a single (non synthetic) method.
methodDef.name == "a" && classDef.methods.count() == 3
} if (methodDef.name != "a") return@custom false
)
val count = classDef.methods.count()
count == 2 || count == 3
},
)

View file

@ -10,20 +10,18 @@ import app.revanced.patcher.extensions.InstructionExtensions.removeInstructions
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patcher.util.smali.ExternalLabel import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
import app.revanced.patches.youtube.misc.litho.filter.fingerprints.* import app.revanced.patches.youtube.misc.litho.filter.fingerprints.*
import app.revanced.util.getReference import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction import app.revanced.util.indexOfFirstInstructionOrThrow
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.Instruction import com.android.tools.smali.dexlib2.iface.instruction.Instruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.reference.FieldReference import com.android.tools.smali.dexlib2.iface.reference.FieldReference
import com.android.tools.smali.dexlib2.iface.reference.TypeReference
import java.io.Closeable import java.io.Closeable
@Patch( @Patch(
@ -108,11 +106,10 @@ object LithoFilterPatch : BytecodePatch(
val emptyComponentFieldIndex = builderMethodIndex + 2 val emptyComponentFieldIndex = builderMethodIndex + 2
bytesToComponentContextMethod.mutableMethod.apply { bytesToComponentContextMethod.mutableMethod.apply {
val insertHookIndex = indexOfFirstInstruction { val insertHookIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.IPUT_OBJECT && opcode == Opcode.IPUT_OBJECT &&
getReference<FieldReference>()?.type == "Ljava/lang/StringBuilder;" getReference<FieldReference>()?.type == "Ljava/lang/StringBuilder;"
} + 1 } + 1
if (insertHookIndex <= 0) throw PatchException("Could not find insert index")
// region Get free registers that this patch uses. // region Get free registers that this patch uses.
// Registers are overwritten right after they are used in this patch, therefore free to clobber. // Registers are overwritten right after they are used in this patch, therefore free to clobber.

View file

@ -13,7 +13,6 @@ import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
import app.revanced.patches.youtube.misc.minimizedplayback.fingerprints.KidsMinimizedPlaybackPolicyControllerFingerprint import app.revanced.patches.youtube.misc.minimizedplayback.fingerprints.KidsMinimizedPlaybackPolicyControllerFingerprint
import app.revanced.patches.youtube.misc.minimizedplayback.fingerprints.MinimizedPlaybackManagerFingerprint import app.revanced.patches.youtube.misc.minimizedplayback.fingerprints.MinimizedPlaybackManagerFingerprint
import app.revanced.patches.youtube.misc.minimizedplayback.fingerprints.MinimizedPlaybackSettingsFingerprint import app.revanced.patches.youtube.misc.minimizedplayback.fingerprints.MinimizedPlaybackSettingsFingerprint
import app.revanced.patches.youtube.misc.minimizedplayback.fingerprints.MinimizedPlaybackSettingsParentFingerprint
import app.revanced.patches.youtube.misc.playertype.PlayerTypeHookPatch import app.revanced.patches.youtube.misc.playertype.PlayerTypeHookPatch
import app.revanced.patches.youtube.misc.settings.SettingsPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch
import app.revanced.patches.youtube.video.information.VideoInformationPatch import app.revanced.patches.youtube.video.information.VideoInformationPatch
@ -25,6 +24,7 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
name = "Minimized playback", name = "Minimized playback",
description = "Unlocks options for picture-in-picture and background playback.", description = "Unlocks options for picture-in-picture and background playback.",
dependencies = [ dependencies = [
MinimizedPlaybackResourcePatch::class,
IntegrationsPatch::class, IntegrationsPatch::class,
PlayerTypeHookPatch::class, PlayerTypeHookPatch::class,
VideoInformationPatch::class, VideoInformationPatch::class,
@ -47,7 +47,12 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
] ]
) )
] ]
@ -56,7 +61,7 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
object MinimizedPlaybackPatch : BytecodePatch( object MinimizedPlaybackPatch : BytecodePatch(
setOf( setOf(
MinimizedPlaybackManagerFingerprint, MinimizedPlaybackManagerFingerprint,
MinimizedPlaybackSettingsParentFingerprint, MinimizedPlaybackSettingsFingerprint,
KidsMinimizedPlaybackPolicyControllerFingerprint KidsMinimizedPlaybackPolicyControllerFingerprint
) )
) { ) {
@ -82,11 +87,6 @@ object MinimizedPlaybackPatch : BytecodePatch(
} ?: throw MinimizedPlaybackManagerFingerprint.exception } ?: throw MinimizedPlaybackManagerFingerprint.exception
// Enable minimized playback option in YouTube settings // Enable minimized playback option in YouTube settings
MinimizedPlaybackSettingsParentFingerprint.result ?: throw MinimizedPlaybackSettingsParentFingerprint.exception
MinimizedPlaybackSettingsFingerprint.resolve(
context,
MinimizedPlaybackSettingsParentFingerprint.result!!.classDef
)
MinimizedPlaybackSettingsFingerprint.result?.apply { MinimizedPlaybackSettingsFingerprint.result?.apply {
val booleanCalls = method.implementation!!.instructions.withIndex() val booleanCalls = method.implementation!!.instructions.withIndex()
.filter { ((it.value as? ReferenceInstruction)?.reference as? MethodReference)?.returnType == "Z" } .filter { ((it.value as? ReferenceInstruction)?.reference as? MethodReference)?.returnType == "Z" }

View file

@ -0,0 +1,17 @@
package app.revanced.patches.youtube.misc.minimizedplayback
import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.ResourcePatch
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch
@Patch(
dependencies = [ResourceMappingPatch::class],
)
internal object MinimizedPlaybackResourcePatch : ResourcePatch() {
internal var prefBackgroundAndOfflineCategoryId: Long = -1
override fun execute(context: ResourceContext) {
prefBackgroundAndOfflineCategoryId = ResourceMappingPatch["string", "pref_background_and_offline_category"]
}
}

View file

@ -1,11 +1,12 @@
package app.revanced.patches.youtube.misc.minimizedplayback.fingerprints package app.revanced.patches.youtube.misc.minimizedplayback.fingerprints
import app.revanced.patcher.extensions.or import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patches.youtube.misc.minimizedplayback.MinimizedPlaybackResourcePatch
import app.revanced.util.patch.LiteralValueFingerprint
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 object MinimizedPlaybackSettingsFingerprint : MethodFingerprint( internal object MinimizedPlaybackSettingsFingerprint : LiteralValueFingerprint(
returnType = "Ljava/lang/String;", returnType = "Ljava/lang/String;",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf(), parameters = listOf(),
@ -16,8 +17,7 @@ internal object MinimizedPlaybackSettingsFingerprint : MethodFingerprint(
Opcode.MOVE_RESULT, Opcode.MOVE_RESULT,
Opcode.IF_EQZ, Opcode.IF_EQZ,
Opcode.IF_NEZ, Opcode.IF_NEZ,
Opcode.GOTO, Opcode.GOTO
Opcode.IGET_OBJECT,
Opcode.CHECK_CAST
), ),
literalSupplier = { MinimizedPlaybackResourcePatch.prefBackgroundAndOfflineCategoryId }
) )

View file

@ -1,15 +0,0 @@
package app.revanced.patches.youtube.misc.minimizedplayback.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
/**
* Class fingerprint for [MinimizedPlaybackSettingsFingerprint]
*/
internal object MinimizedPlaybackSettingsParentFingerprint : MethodFingerprint(
accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL,
returnType = "I",
parameters = listOf(),
strings = listOf("BiometricManager", "Failure in canAuthenticate(). FingerprintManager was null.")
)

View file

@ -12,7 +12,7 @@ import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
import app.revanced.patches.youtube.misc.navigation.fingerprints.* import app.revanced.patches.youtube.misc.navigation.fingerprints.*
import app.revanced.patches.youtube.misc.playertype.PlayerTypeHookPatch import app.revanced.patches.youtube.misc.playertype.PlayerTypeHookPatch
import app.revanced.util.getReference import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
@ -121,7 +121,7 @@ object NavigationBarHookPatch : BytecodePatch(
// Insert before the first ViewGroup method call after inflating, // Insert before the first ViewGroup method call after inflating,
// so this works regardless which layout is used. // so this works regardless which layout is used.
ActionBarSearchResultsFingerprint.resultOrThrow().mutableMethod.apply { ActionBarSearchResultsFingerprint.resultOrThrow().mutableMethod.apply {
val instructionIndex = indexOfFirstInstruction { val instructionIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.INVOKE_VIRTUAL && getReference<MethodReference>()?.name == "setLayoutDirection" opcode == Opcode.INVOKE_VIRTUAL && getReference<MethodReference>()?.name == "setLayoutDirection"
} }

View file

@ -43,7 +43,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
] ]
) )
] ]

View file

@ -47,7 +47,12 @@ import com.android.tools.smali.dexlib2.iface.reference.FieldReference
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
] ]
) )
] ]

View file

@ -27,7 +27,12 @@ import app.revanced.patches.youtube.video.speed.remember.RememberPlaybackSpeedPa
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
], ],
), ),
], ],

View file

@ -2,12 +2,12 @@ package app.revanced.patches.youtube.video.videoqualitymenu
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
import app.revanced.patches.youtube.misc.litho.filter.LithoFilterPatch import app.revanced.patches.youtube.misc.litho.filter.LithoFilterPatch
import app.revanced.patches.youtube.misc.recyclerviewtree.hook.RecyclerViewTreeHookPatch import app.revanced.patches.youtube.misc.recyclerviewtree.hook.RecyclerViewTreeHookPatch
@ -23,7 +23,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
IntegrationsPatch::class, IntegrationsPatch::class,
RestoreOldVideoQualityMenuResourcePatch::class, RestoreOldVideoQualityMenuResourcePatch::class,
LithoFilterPatch::class, LithoFilterPatch::class,
RecyclerViewTreeHookPatch::class RecyclerViewTreeHookPatch::class,
], ],
compatiblePackages = [ compatiblePackages = [
CompatiblePackage( CompatiblePackage(
@ -47,20 +47,25 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43" "19.11.43",
] "19.12.41",
) "19.13.37",
] "19.14.43",
"19.15.36",
"19.16.39",
],
),
],
) )
@Suppress("unused") @Suppress("unused")
object RestoreOldVideoQualityMenuPatch : BytecodePatch( object RestoreOldVideoQualityMenuPatch : BytecodePatch(
setOf(VideoQualityMenuViewInflateFingerprint, VideoQualityMenuOptionsFingerprint) setOf(VideoQualityMenuViewInflateFingerprint, VideoQualityMenuOptionsFingerprint),
) { ) {
private const val FILTER_CLASS_DESCRIPTOR = private const val FILTER_CLASS_DESCRIPTOR =
"Lapp/revanced/integrations/youtube/patches/components/VideoQualityMenuFilterPatch;" "Lapp/revanced/integrations/youtube/patches/components/VideoQualityMenuFilterPatch;"
private const val INTEGRATIONS_CLASS_DESCRIPTOR = private const val INTEGRATIONS_CLASS_DESCRIPTOR =
"Lapp/revanced/integrations/youtube/patches/playback/quality/RestoreOldVideoQualityMenuPatch;" "Lapp/revanced/integrations/youtube/patches/playback/quality/RestoreOldVideoQualityMenuPatch;"
override fun execute(context: BytecodeContext) { override fun execute(context: BytecodeContext) {
// region Patch for the old type of the video quality menu. // region Patch for the old type of the video quality menu.
@ -75,31 +80,30 @@ object RestoreOldVideoQualityMenuPatch : BytecodePatch(
addInstruction( addInstruction(
checkCastIndex + 1, checkCastIndex + 1,
"invoke-static { v$listViewRegister }, " + "invoke-static { v$listViewRegister }, " +
"$INTEGRATIONS_CLASS_DESCRIPTOR->" + "$INTEGRATIONS_CLASS_DESCRIPTOR->" +
"showOldVideoQualityMenu(Landroid/widget/ListView;)V" "showOldVideoQualityMenu(Landroid/widget/ListView;)V",
) )
} }
} }
// Force YT to add the 'advanced' quality menu for Shorts. // Force YT to add the 'advanced' quality menu for Shorts.
VideoQualityMenuOptionsFingerprint.resultOrThrow().let { VideoQualityMenuOptionsFingerprint.resultOrThrow().let {
val result = it.scanResult.patternScanResult!! val scanResult = it.scanResult.patternScanResult!!
val startIndex = result.startIndex val startIndex = scanResult.startIndex
val endIndex = result.endIndex if (startIndex != 0) throw PatchException("Unexpected opcode start index: $startIndex")
val insertIndex = scanResult.endIndex
it.mutableMethod.apply { it.mutableMethod.apply {
val freeRegister = getInstruction<OneRegisterInstruction>(startIndex).registerA val register = getInstruction<OneRegisterInstruction>(insertIndex).registerA
// A condition controls whether to show the three or four items quality menu. // A condition controls whether to show the three or four items quality menu.
// Force the four items quality menu to make the "Advanced" item visible, necessary for the patch. // Force the four items quality menu to make the "Advanced" item visible, necessary for the patch.
addInstructionsWithLabels( addInstructions(
startIndex + 1, insertIndex,
""" """
invoke-static { }, $INTEGRATIONS_CLASS_DESCRIPTOR->forceAdvancedVideoQualityMenuCreation()Z invoke-static { v$register }, $INTEGRATIONS_CLASS_DESCRIPTOR->forceAdvancedVideoQualityMenuCreation(Z)Z
move-result v$freeRegister move-result v$register
if-nez v$freeRegister, :includeAdvancedMenu
""", """,
ExternalLabel("includeAdvancedMenu", getInstruction(endIndex))
) )
} }
} }
@ -115,4 +119,4 @@ object RestoreOldVideoQualityMenuPatch : BytecodePatch(
// endregion // endregion
} }
} }

View file

@ -10,13 +10,11 @@ internal object VideoQualityMenuOptionsFingerprint : LiteralValueFingerprint(
parameters = listOf("Landroid/content/Context", "L", "L"), parameters = listOf("Landroid/content/Context", "L", "L"),
returnType = "[L", returnType = "[L",
opcodes = listOf( opcodes = listOf(
Opcode.IF_EQZ, // Check if advanced menu should be shown. Opcode.CONST_4, // First instruction of method.
Opcode.NEW_ARRAY, Opcode.CONST_4,
Opcode.APUT_OBJECT, Opcode.IF_EQZ,
Opcode.APUT_OBJECT, Opcode.IGET_BOOLEAN, // Use the quality menu, that contains the advanced menu.
Opcode.APUT_OBJECT, Opcode.IF_NEZ
Opcode.RETURN_OBJECT,
Opcode.CONST_4 // Advanced menu code path.
), ),
literalSupplier = { RestoreOldVideoQualityMenuResourcePatch.videoQualityQuickMenuAdvancedMenuDescription } literalSupplier = { RestoreOldVideoQualityMenuResourcePatch.videoQualityQuickMenuAdvancedMenuDescription }
) )

View file

@ -143,8 +143,41 @@ inline fun <reified T : Reference> Instruction.getReference() = (this as? Refere
* @param predicate The predicate to match. * @param predicate The predicate to match.
* @return The index of the first [Instruction] that matches the predicate. * @return The index of the first [Instruction] that matches the predicate.
*/ */
fun Method.indexOfFirstInstruction(predicate: Instruction.() -> Boolean) = // TODO: delete this on next major release, the overloaded method with an optional start index serves the same purposes.
this.implementation!!.instructions.indexOfFirst(predicate) @Deprecated("Use the overloaded method with an optional start index.", ReplaceWith("indexOfFirstInstruction(predicate)"))
fun Method.indexOfFirstInstruction(predicate: Instruction.() -> Boolean) = indexOfFirstInstruction(0, predicate)
/**
* Get the index of the first [Instruction] that matches the predicate, starting from [startIndex].
*
* @param startIndex Optional starting index to start searching from.
* @return -1 if the instruction is not found.
* @see indexOfFirstInstructionOrThrow
*/
fun Method.indexOfFirstInstruction(startIndex: Int = 0, predicate: Instruction.() -> Boolean): Int {
val index = this.implementation!!.instructions.drop(startIndex).indexOfFirst(predicate)
return if (index >= 0) {
startIndex + index
} else {
-1
}
}
/**
* Get the index of the first [Instruction] that matches the predicate, starting from [startIndex].
*
* @return the index of the instruction
* @throws PatchException
* @see indexOfFirstInstruction
*/
fun Method.indexOfFirstInstructionOrThrow(startIndex: Int = 0, predicate: Instruction.() -> Boolean): Int {
val index = indexOfFirstInstruction(startIndex, predicate)
if (index < 0) {
throw PatchException("Could not find instruction index")
}
return index
}
/** /**
* Return the resolved methods of [MethodFingerprint]s early. * Return the resolved methods of [MethodFingerprint]s early.