refactor(BytecodeUtils): remove duplicate functions

This commit is contained in:
inotia00
2024-09-17 18:40:11 +09:00
parent 5e4b56cfbe
commit afd19dead4
135 changed files with 1349 additions and 1453 deletions

View File

@ -10,10 +10,10 @@ import app.revanced.patches.youtube.player.ambientmode.fingerprints.PowerSaveMod
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
import app.revanced.patches.youtube.utils.integrations.Constants.PLAYER_CLASS_DESCRIPTOR
import app.revanced.patches.youtube.utils.settings.SettingsPatch
import app.revanced.util.getStringInstructionIndex
import app.revanced.util.getTargetIndexOrThrow
import app.revanced.util.getTargetIndexReversedOrThrow
import app.revanced.util.literalInstructionBooleanHook
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
import app.revanced.util.indexOfFirstStringInstructionOrThrow
import app.revanced.util.injectLiteralInstructionBooleanCall
import app.revanced.util.patch.BaseBytecodePatch
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode
@ -46,12 +46,12 @@ object AmbientModeSwitchPatch : BaseBytecodePatch(
).forEach { (fingerprint, reversed) ->
fingerprint.resultOrThrow().mutableMethod.apply {
val stringIndex =
getStringInstructionIndex("android.os.action.POWER_SAVE_MODE_CHANGED")
indexOfFirstStringInstructionOrThrow("android.os.action.POWER_SAVE_MODE_CHANGED")
val targetIndex =
if (reversed)
getTargetIndexReversedOrThrow(stringIndex, Opcode.INVOKE_DIRECT)
indexOfFirstInstructionReversedOrThrow(stringIndex, Opcode.INVOKE_DIRECT)
else
getTargetIndexOrThrow(stringIndex, Opcode.INVOKE_DIRECT)
indexOfFirstInstructionOrThrow(stringIndex, Opcode.INVOKE_DIRECT)
val targetClass =
(getInstruction<ReferenceInstruction>(targetIndex).reference as MethodReference).definingClass
@ -87,7 +87,7 @@ object AmbientModeSwitchPatch : BaseBytecodePatch(
// region patch for disable ambient mode in fullscreen
AmbientModeInFullscreenFingerprint.literalInstructionBooleanHook(
AmbientModeInFullscreenFingerprint.injectLiteralInstructionBooleanCall(
45389368,
"$PLAYER_CLASS_DESCRIPTOR->disableAmbientModeInFullscreen()Z"
)

View File

@ -24,8 +24,8 @@ import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.FullS
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.PlayerCollapseButton
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.TitleAnchor
import app.revanced.patches.youtube.utils.settings.SettingsPatch
import app.revanced.util.getTargetIndexOrThrow
import app.revanced.util.getWideLiteralInstructionIndex
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow
import app.revanced.util.patch.BaseBytecodePatch
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode
@ -63,9 +63,10 @@ object PlayerButtonsPatch : BaseBytecodePatch(
LayoutConstructorFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val constIndex = getWideLiteralInstructionIndex(AutoNavToggle)
val constIndex = indexOfFirstWideLiteralInstructionValueOrThrow(AutoNavToggle)
val constRegister = getInstruction<OneRegisterInstruction>(constIndex).registerA
val jumpIndex = getTargetIndexOrThrow(constIndex + 2, Opcode.INVOKE_VIRTUAL) + 1
val jumpIndex =
indexOfFirstInstructionOrThrow(constIndex + 2, Opcode.INVOKE_VIRTUAL) + 1
addInstructionsWithLabels(
constIndex, """
@ -124,9 +125,9 @@ object PlayerButtonsPatch : BaseBytecodePatch(
// region patch for hide collapse button
TitleAnchorFingerprint.resultOrThrow().mutableMethod.apply {
val titleAnchorConstIndex = getWideLiteralInstructionIndex(TitleAnchor)
val titleAnchorConstIndex = indexOfFirstWideLiteralInstructionValueOrThrow(TitleAnchor)
val titleAnchorIndex =
getTargetIndexOrThrow(titleAnchorConstIndex, Opcode.MOVE_RESULT_OBJECT)
indexOfFirstInstructionOrThrow(titleAnchorConstIndex, Opcode.MOVE_RESULT_OBJECT)
val titleAnchorRegister =
getInstruction<OneRegisterInstruction>(titleAnchorIndex).registerA
@ -136,9 +137,9 @@ object PlayerButtonsPatch : BaseBytecodePatch(
)
val playerCollapseButtonConstIndex =
getWideLiteralInstructionIndex(PlayerCollapseButton)
indexOfFirstWideLiteralInstructionValueOrThrow(PlayerCollapseButton)
val playerCollapseButtonIndex =
getTargetIndexOrThrow(playerCollapseButtonConstIndex, Opcode.CHECK_CAST)
indexOfFirstInstructionOrThrow(playerCollapseButtonConstIndex, Opcode.CHECK_CAST)
val playerCollapseButtonRegister =
getInstruction<OneRegisterInstruction>(playerCollapseButtonIndex).registerA
@ -159,7 +160,7 @@ object PlayerButtonsPatch : BaseBytecodePatch(
(instruction.value as? WideLiteralInstruction)?.wideLiteral == FullScreenButton
}
val constIndex = buttonCalls.elementAt(buttonCalls.size - 1).index
val castIndex = getTargetIndexOrThrow(constIndex, Opcode.CHECK_CAST)
val castIndex = indexOfFirstInstructionOrThrow(constIndex, Opcode.CHECK_CAST)
val insertIndex = castIndex + 1
val insertRegister = getInstruction<OneRegisterInstruction>(castIndex).registerA
@ -180,7 +181,7 @@ object PlayerButtonsPatch : BaseBytecodePatch(
PlayerControlsVisibilityModelFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val callIndex = getTargetIndexOrThrow(Opcode.INVOKE_DIRECT_RANGE)
val callIndex = indexOfFirstInstructionOrThrow(Opcode.INVOKE_DIRECT_RANGE)
val callInstruction = getInstruction<Instruction3rc>(callIndex)
val hasNextParameterRegister = callInstruction.startRegister + HAS_NEXT

View File

@ -5,7 +5,7 @@ import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.CfFullscreenButton
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.FadeDurationFast
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.FullScreenButton
import app.revanced.util.containsWideLiteralInstructionIndex
import app.revanced.util.containsWideLiteralInstructionValue
import com.android.tools.smali.dexlib2.AccessFlags
internal object FullScreenButtonFingerprint : MethodFingerprint(
@ -13,10 +13,10 @@ internal object FullScreenButtonFingerprint : MethodFingerprint(
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("Landroid/view/View;"),
customFingerprint = handler@{ methodDef, _ ->
if (!methodDef.containsWideLiteralInstructionIndex(FullScreenButton))
if (!methodDef.containsWideLiteralInstructionValue(FullScreenButton))
return@handler false
methodDef.containsWideLiteralInstructionIndex(FadeDurationFast) // YouTube 18.29.38 ~ YouTube 19.18.41
|| methodDef.containsWideLiteralInstructionIndex(CfFullscreenButton) // YouTube 19.19.39 ~
methodDef.containsWideLiteralInstructionValue(FadeDurationFast) // YouTube 18.29.38 ~ YouTube 19.18.41
|| methodDef.containsWideLiteralInstructionValue(CfFullscreenButton) // YouTube 19.19.39 ~
},
)

View File

@ -3,12 +3,12 @@ package app.revanced.patches.youtube.player.buttons.fingerprints
import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.PlayerCollapseButton
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.TitleAnchor
import app.revanced.util.containsWideLiteralInstructionIndex
import app.revanced.util.containsWideLiteralInstructionValue
internal object TitleAnchorFingerprint : MethodFingerprint(
returnType = "V",
customFingerprint = { methodDef, _ ->
methodDef.containsWideLiteralInstructionIndex(PlayerCollapseButton)
&& methodDef.containsWideLiteralInstructionIndex(TitleAnchor)
methodDef.containsWideLiteralInstructionValue(PlayerCollapseButton)
&& methodDef.containsWideLiteralInstructionValue(TitleAnchor)
}
)

View File

@ -12,9 +12,9 @@ import app.revanced.patches.youtube.utils.integrations.Constants.COMPONENTS_PATH
import app.revanced.patches.youtube.utils.integrations.Constants.PLAYER_CLASS_DESCRIPTOR
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch
import app.revanced.patches.youtube.utils.settings.SettingsPatch
import app.revanced.util.getTargetIndexOrThrow
import app.revanced.util.getWalkerMethod
import app.revanced.util.getWideLiteralInstructionIndex
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow
import app.revanced.util.patch.BaseBytecodePatch
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode
@ -56,14 +56,15 @@ object CommentsComponentPatch : BaseBytecodePatch(
ShortsLiveStreamEmojiPickerOnClickListenerFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val emojiPickerEndpointIndex = getWideLiteralInstructionIndex(126326492)
val emojiPickerEndpointIndex =
indexOfFirstWideLiteralInstructionValueOrThrow(126326492)
val emojiPickerOnClickListenerIndex =
getTargetIndexOrThrow(emojiPickerEndpointIndex, Opcode.INVOKE_DIRECT)
indexOfFirstInstructionOrThrow(emojiPickerEndpointIndex, Opcode.INVOKE_DIRECT)
val emojiPickerOnClickListenerMethod =
getWalkerMethod(context, emojiPickerOnClickListenerIndex)
emojiPickerOnClickListenerMethod.apply {
val insertIndex = getTargetIndexOrThrow(Opcode.IF_EQZ)
val insertIndex = indexOfFirstInstructionOrThrow(Opcode.IF_EQZ)
val insertRegister =
getInstruction<OneRegisterInstruction>(insertIndex).registerA

View File

@ -48,11 +48,11 @@ import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.TapBl
import app.revanced.patches.youtube.utils.settings.SettingsPatch
import app.revanced.patches.youtube.video.information.VideoInformationPatch
import app.revanced.util.REGISTER_TEMPLATE_REPLACEMENT
import app.revanced.util.getTargetIndexOrThrow
import app.revanced.util.getTargetIndexReversedOrThrow
import app.revanced.util.getTargetIndexWithMethodReferenceNameOrThrow
import app.revanced.util.getWideLiteralInstructionIndex
import app.revanced.util.literalInstructionViewHook
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow
import app.revanced.util.injectLiteralInstructionViewCall
import app.revanced.util.patch.BaseBytecodePatch
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode
@ -61,6 +61,7 @@ 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.TwoRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.WideLiteralInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
@Suppress("unused")
object PlayerComponentsPatch : BaseBytecodePatch(
@ -107,8 +108,8 @@ object PlayerComponentsPatch : BaseBytecodePatch(
YouTubeControlsOverlayFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val constIndex = getWideLiteralInstructionIndex(ScrimOverlay)
val targetIndex = getTargetIndexOrThrow(constIndex, Opcode.CHECK_CAST)
val constIndex = indexOfFirstWideLiteralInstructionValueOrThrow(ScrimOverlay)
val targetIndex = indexOfFirstInstructionOrThrow(constIndex, Opcode.CHECK_CAST)
val targetParameter = getInstruction<ReferenceInstruction>(targetIndex).reference
val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
@ -144,7 +145,8 @@ object PlayerComponentsPatch : BaseBytecodePatch(
if (fingerprint == StartVideoInformerFingerprint) {
hookInitVideoPanel(1)
} else {
val syntheticIndex = getTargetIndexOrThrow(Opcode.NEW_INSTANCE)
val syntheticIndex =
indexOfFirstInstructionOrThrow(opcode = Opcode.NEW_INSTANCE)
val syntheticReference =
getInstruction<ReferenceInstruction>(syntheticIndex).reference.toString()
val syntheticClass =
@ -228,7 +230,7 @@ object PlayerComponentsPatch : BaseBytecodePatch(
DarkBackground,
TapBloomView
).forEach { literal ->
QuickSeekOverlayFingerprint.literalInstructionViewHook(
QuickSeekOverlayFingerprint.injectLiteralInstructionViewCall(
literal,
smaliInstruction
)
@ -273,10 +275,10 @@ object PlayerComponentsPatch : BaseBytecodePatch(
YouTubeControlsOverlayFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val constIndex = getWideLiteralInstructionIndex(FadeDurationFast)
val constIndex = indexOfFirstWideLiteralInstructionValueOrThrow(FadeDurationFast)
val constRegister = getInstruction<OneRegisterInstruction>(constIndex).registerA
val insertIndex =
getTargetIndexReversedOrThrow(constIndex, Opcode.INVOKE_VIRTUAL) + 1
indexOfFirstInstructionReversedOrThrow(constIndex, Opcode.INVOKE_VIRTUAL) + 1
val jumpIndex = implementation!!.instructions.let { instruction ->
insertIndex + instruction.subList(insertIndex, instruction.size - 1)
.indexOfFirst { instructions ->
@ -341,11 +343,14 @@ object PlayerComponentsPatch : BaseBytecodePatch(
YouTubeControlsOverlayFingerprint.resultOrThrow().let { result ->
result.mutableMethod.apply {
val insertIndex = getWideLiteralInstructionIndex(SeekUndoEduOverlayStub)
val insertIndex =
indexOfFirstWideLiteralInstructionValueOrThrow(SeekUndoEduOverlayStub)
val insertRegister = getInstruction<OneRegisterInstruction>(insertIndex).registerA
val onClickListenerIndex =
getTargetIndexWithMethodReferenceNameOrThrow(insertIndex, "setOnClickListener")
val onClickListenerIndex = indexOfFirstInstructionOrThrow(insertIndex) {
opcode == Opcode.INVOKE_VIRTUAL &&
getReference<MethodReference>()?.name == "setOnClickListener"
}
val constComponent = getConstComponent(insertIndex, onClickListenerIndex - 1)
if (constComponent.isNotEmpty()) {
@ -390,8 +395,10 @@ object PlayerComponentsPatch : BaseBytecodePatch(
it.mutableClass.methods.find { method ->
method.parameters == listOf("Landroid/view/View${'$'}OnClickListener;")
}?.apply {
val setOnClickListenerIndex =
getTargetIndexWithMethodReferenceNameOrThrow("setOnClickListener")
val setOnClickListenerIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.INVOKE_VIRTUAL &&
getReference<MethodReference>()?.name == "setOnClickListener"
}
val setOnClickListenerRegister =
getInstruction<FiveRegisterInstruction>(setOnClickListenerIndex).registerC

View File

@ -3,13 +3,13 @@ package app.revanced.patches.youtube.player.components.fingerprints
import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.DarkBackground
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.TapBloomView
import app.revanced.util.containsWideLiteralInstructionIndex
import app.revanced.util.containsWideLiteralInstructionValue
internal object QuickSeekOverlayFingerprint : MethodFingerprint(
returnType = "V",
parameters = emptyList(),
customFingerprint = { methodDef, _ ->
methodDef.containsWideLiteralInstructionIndex(DarkBackground)
&& methodDef.containsWideLiteralInstructionIndex(TapBloomView)
methodDef.containsWideLiteralInstructionValue(DarkBackground)
&& methodDef.containsWideLiteralInstructionValue(TapBloomView)
},
)

View File

@ -20,10 +20,14 @@ import app.revanced.patches.youtube.utils.playertype.PlayerTypeHookPatch
import app.revanced.patches.youtube.utils.recyclerview.BottomSheetRecyclerViewPatch
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch
import app.revanced.patches.youtube.utils.settings.SettingsPatch
import app.revanced.util.getTargetIndexWithMethodReferenceNameOrThrow
import app.revanced.util.alsoResolve
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.patch.BaseBytecodePatch
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
@Suppress("unused")
object DescriptionComponentsPatch : BaseBytecodePatch(
@ -54,23 +58,23 @@ object DescriptionComponentsPatch : BaseBytecodePatch(
// In order to maintain compatibility with YouTube v18.48.39 or previous versions,
// This patch is applied only to the version after YouTube v18.49.37.
if (SettingsPatch.upward1849) {
RollingNumberTextViewAnimationUpdateFingerprint.resolve(
context,
RollingNumberTextViewFingerprint.resultOrThrow().classDef
)
RollingNumberTextViewAnimationUpdateFingerprint.resultOrThrow().let {
RollingNumberTextViewAnimationUpdateFingerprint.alsoResolve(
context, RollingNumberTextViewFingerprint
).let {
it.mutableMethod.apply {
val freeRegister = implementation!!.registerCount - parameters.size - 2
val imageSpanIndex = it.scanResult.patternScanResult!!.startIndex
val setTextIndex = getTargetIndexWithMethodReferenceNameOrThrow("setText")
val setTextIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.INVOKE_VIRTUAL &&
getReference<MethodReference>()?.name == "setText"
}
addInstruction(setTextIndex, "nop")
addInstructionsWithLabels(
imageSpanIndex, """
invoke-static {}, $PLAYER_CLASS_DESCRIPTOR->disableRollingNumberAnimations()Z
move-result v$freeRegister
if-nez v$freeRegister, :disable_animations
""", ExternalLabel("disable_animations", getInstruction(setTextIndex))
invoke-static {}, $PLAYER_CLASS_DESCRIPTOR->disableRollingNumberAnimations()Z
move-result v$freeRegister
if-nez v$freeRegister, :disable_animations
""", ExternalLabel("disable_animations", getInstruction(setTextIndex))
)
}
}
@ -106,13 +110,11 @@ object DescriptionComponentsPatch : BaseBytecodePatch(
}
}
EngagementPanelTitleFingerprint.resolve(
context,
EngagementPanelTitleParentFingerprint.resultOrThrow().classDef
)
EngagementPanelTitleFingerprint.resultOrThrow().mutableMethod.apply {
val contentDescriptionIndex =
getTargetIndexWithMethodReferenceNameOrThrow("setContentDescription")
EngagementPanelTitleFingerprint.alsoResolve(
context, EngagementPanelTitleParentFingerprint
).mutableMethod.apply {
val contentDescriptionIndex = EngagementPanelTitleFingerprint
.indexOfContentDescriptionInstruction(this)
val contentDescriptionRegister =
getInstruction<FiveRegisterInstruction>(contentDescriptionIndex).registerD

View File

@ -1,8 +1,22 @@
package app.revanced.patches.youtube.player.descriptions.fingerprints
import app.revanced.util.fingerprint.MethodReferenceNameFingerprint
import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patches.youtube.player.descriptions.fingerprints.EngagementPanelTitleFingerprint.indexOfContentDescriptionInstruction
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionReversed
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
internal object EngagementPanelTitleFingerprint : MethodReferenceNameFingerprint(
internal object EngagementPanelTitleFingerprint : MethodFingerprint(
strings = listOf(". "),
reference = { "setContentDescription" }
)
customFingerprint = { methodDef, _ ->
indexOfContentDescriptionInstruction(methodDef) >= 0
}
) {
fun indexOfContentDescriptionInstruction(methodDef: Method) =
methodDef.indexOfFirstInstructionReversed {
opcode == Opcode.INVOKE_VIRTUAL &&
getReference<MethodReference>()?.name == "setContentDescription"
}
}

View File

@ -16,12 +16,15 @@ import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.BottomSheetFooterText
import app.revanced.patches.youtube.utils.settings.SettingsPatch
import app.revanced.util.REGISTER_TEMPLATE_REPLACEMENT
import app.revanced.util.getTargetIndexWithMethodReferenceNameOrThrow
import app.revanced.util.literalInstructionBooleanHook
import app.revanced.util.literalInstructionViewHook
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.injectLiteralInstructionBooleanCall
import app.revanced.util.injectLiteralInstructionViewCall
import app.revanced.util.patch.BaseBytecodePatch
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
@Suppress("unused")
object PlayerFlyoutMenuPatch : BaseBytecodePatch(
@ -56,7 +59,7 @@ object PlayerFlyoutMenuPatch : BaseBytecodePatch(
val smaliInstruction = """
invoke-static {v$REGISTER_TEMPLATE_REPLACEMENT}, $PLAYER_CLASS_DESCRIPTOR->$name(Landroid/view/View;)V
"""
fingerprint.literalInstructionViewHook(BottomSheetFooterText, smaliInstruction)
fingerprint.injectLiteralInstructionViewCall(BottomSheetFooterText, smaliInstruction)
}
arrayOf(
@ -64,15 +67,17 @@ object PlayerFlyoutMenuPatch : BaseBytecodePatch(
QualityMenuViewInflateFingerprint
).forEach { fingerprint ->
fingerprint.resultOrThrow().mutableMethod.apply {
val insertIndex = getTargetIndexWithMethodReferenceNameOrThrow("addHeaderView")
val insertIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.INVOKE_VIRTUAL &&
getReference<MethodReference>()?.name == "addHeaderView"
}
val insertRegister = getInstruction<FiveRegisterInstruction>(insertIndex).registerD
addInstructions(
insertIndex,
"""
invoke-static {v$insertRegister}, $PLAYER_CLASS_DESCRIPTOR->hidePlayerFlyoutMenuQualityHeader(Landroid/view/View;)Landroid/view/View;
move-result-object v$insertRegister
"""
insertIndex, """
invoke-static {v$insertRegister}, $PLAYER_CLASS_DESCRIPTOR->hidePlayerFlyoutMenuQualityHeader(Landroid/view/View;)Landroid/view/View;
move-result-object v$insertRegister
"""
)
}
}
@ -95,7 +100,7 @@ object PlayerFlyoutMenuPatch : BaseBytecodePatch(
SettingsPatch.updatePatchStatus(this)
if (SettingsPatch.upward1839) {
PiPModeConfigFingerprint.literalInstructionBooleanHook(
PiPModeConfigFingerprint.injectLiteralInstructionBooleanCall(
45427407,
"$PLAYER_CLASS_DESCRIPTOR->hidePiPModeMenu(Z)Z"
)

View File

@ -4,13 +4,13 @@ import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.BottomSheetFooterText
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.SubtitleMenuSettingsFooterInfo
import app.revanced.util.containsWideLiteralInstructionIndex
import app.revanced.util.containsWideLiteralInstructionValue
import com.android.tools.smali.dexlib2.AccessFlags
internal object CaptionsBottomSheetFingerprint : MethodFingerprint(
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
customFingerprint = { methodDef, _ ->
methodDef.containsWideLiteralInstructionIndex(BottomSheetFooterText)
&& methodDef.containsWideLiteralInstructionIndex(SubtitleMenuSettingsFooterInfo)
methodDef.containsWideLiteralInstructionValue(BottomSheetFooterText)
&& methodDef.containsWideLiteralInstructionValue(SubtitleMenuSettingsFooterInfo)
}
)

View File

@ -17,11 +17,10 @@ import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PAC
import app.revanced.patches.youtube.utils.integrations.Constants.PLAYER_CLASS_DESCRIPTOR
import app.revanced.patches.youtube.utils.settings.SettingsPatch
import app.revanced.util.getReference
import app.revanced.util.getStringInstructionIndex
import app.revanced.util.getTargetIndexOrThrow
import app.revanced.util.getTargetIndexReversedOrThrow
import app.revanced.util.indexOfFirstInstruction
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
import app.revanced.util.indexOfFirstStringInstructionOrThrow
import app.revanced.util.patch.BaseBytecodePatch
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode
@ -139,13 +138,15 @@ object ChangeTogglePatch : BaseBytecodePatch(
}
val classRegister = getInstruction<TwoRegisterInstruction>(iGetIndex).registerB
val stringIndex = getStringInstructionIndex("menu_item_cinematic_lighting")
val stringIndex =
indexOfFirstStringInstructionOrThrow("menu_item_cinematic_lighting")
val checkCastIndex = getTargetIndexReversedOrThrow(stringIndex, Opcode.CHECK_CAST)
val checkCastIndex =
indexOfFirstInstructionReversedOrThrow(stringIndex, Opcode.CHECK_CAST)
val iGetObjectPrimaryIndex =
getTargetIndexReversedOrThrow(checkCastIndex, Opcode.IGET_OBJECT)
indexOfFirstInstructionReversedOrThrow(checkCastIndex, Opcode.IGET_OBJECT)
val iGetObjectSecondaryIndex =
getTargetIndexOrThrow(checkCastIndex, Opcode.IGET_OBJECT)
indexOfFirstInstructionOrThrow(checkCastIndex, Opcode.IGET_OBJECT)
val checkCastReference =
getInstruction<ReferenceInstruction>(checkCastIndex).reference
@ -154,14 +155,15 @@ object ChangeTogglePatch : BaseBytecodePatch(
val iGetObjectSecondaryReference =
getInstruction<ReferenceInstruction>(iGetObjectSecondaryIndex).reference
val invokeVirtualIndex = getTargetIndexOrThrow(stringIndex, Opcode.INVOKE_VIRTUAL)
val invokeVirtualIndex =
indexOfFirstInstructionOrThrow(stringIndex, Opcode.INVOKE_VIRTUAL)
val invokeVirtualInstruction =
getInstruction<FiveRegisterInstruction>(invokeVirtualIndex)
val freeRegisterC = invokeVirtualInstruction.registerC
val freeRegisterD = invokeVirtualInstruction.registerD
val freeRegisterE = invokeVirtualInstruction.registerE
val insertIndex = getTargetIndexOrThrow(stringIndex, Opcode.RETURN_VOID)
val insertIndex = indexOfFirstInstructionOrThrow(stringIndex, Opcode.RETURN_VOID)
addInstructionsWithLabels(
insertIndex, """

View File

@ -30,12 +30,10 @@ import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.FullS
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.QuickActionsElementContainer
import app.revanced.patches.youtube.utils.settings.SettingsPatch
import app.revanced.util.getReference
import app.revanced.util.getStringInstructionIndex
import app.revanced.util.getTargetIndexOrThrow
import app.revanced.util.getTargetIndexWithMethodReferenceNameOrThrow
import app.revanced.util.getWalkerMethod
import app.revanced.util.getWideLiteralInstructionIndex
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstStringInstructionOrThrow
import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow
import app.revanced.util.patch.BaseBytecodePatch
import app.revanced.util.resultOrThrow
import app.revanced.util.updatePatchStatus
@ -80,8 +78,9 @@ object FullscreenComponentsPatch : BaseBytecodePatch(
EngagementPanelFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val literalIndex = getWideLiteralInstructionIndex(FullScreenEngagementPanel)
val targetIndex = getTargetIndexOrThrow(literalIndex, Opcode.CHECK_CAST)
val literalIndex =
indexOfFirstWideLiteralInstructionValueOrThrow(FullScreenEngagementPanel)
val targetIndex = indexOfFirstInstructionOrThrow(literalIndex, Opcode.CHECK_CAST)
val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
addInstruction(
@ -94,7 +93,10 @@ object FullscreenComponentsPatch : BaseBytecodePatch(
PlayerTitleViewFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val insertIndex = getTargetIndexWithMethodReferenceNameOrThrow("addView")
val insertIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.INVOKE_VIRTUAL &&
getReference<MethodReference>()?.name == "addView"
}
val insertReference =
getInstruction<ReferenceInstruction>(insertIndex).reference.toString()
if (!insertReference.startsWith("Landroid/widget/FrameLayout;"))
@ -115,9 +117,10 @@ object FullscreenComponentsPatch : BaseBytecodePatch(
LayoutConstructorFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val constIndex = getWideLiteralInstructionIndex(AutoNavPreviewStub)
val constIndex = indexOfFirstWideLiteralInstructionValueOrThrow(AutoNavPreviewStub)
val constRegister = getInstruction<OneRegisterInstruction>(constIndex).registerA
val jumpIndex = getTargetIndexOrThrow(constIndex + 2, Opcode.INVOKE_VIRTUAL) + 1
val jumpIndex =
indexOfFirstInstructionOrThrow(constIndex + 2, Opcode.INVOKE_VIRTUAL) + 1
addInstructionsWithLabels(
constIndex, """
@ -159,7 +162,7 @@ object FullscreenComponentsPatch : BaseBytecodePatch(
}
val constIndex = containerCalls.elementAt(containerCalls.size - 1).index
val checkCastIndex = getTargetIndexOrThrow(constIndex, Opcode.CHECK_CAST)
val checkCastIndex = indexOfFirstInstructionOrThrow(constIndex, Opcode.CHECK_CAST)
val insertRegister =
getInstruction<OneRegisterInstruction>(checkCastIndex).registerA
@ -183,9 +186,11 @@ object FullscreenComponentsPatch : BaseBytecodePatch(
YouTubeControlsOverlayFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val targetIndex =
getTargetIndexWithMethodReferenceNameOrThrow("setFocusableInTouchMode")
val walkerIndex = getTargetIndexOrThrow(targetIndex, Opcode.INVOKE_STATIC)
val targetIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.INVOKE_VIRTUAL &&
getReference<MethodReference>()?.name == "setFocusableInTouchMode"
}
val walkerIndex = indexOfFirstInstructionOrThrow(targetIndex, Opcode.INVOKE_STATIC)
val walkerMethod = getWalkerMethod(context, walkerIndex)
walkerMethod.apply {
@ -209,14 +214,14 @@ object FullscreenComponentsPatch : BaseBytecodePatch(
ClientSettingEndpointFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val getActivityIndex = getStringInstructionIndex("watch") + 2
val getActivityIndex = indexOfFirstStringInstructionOrThrow("watch") + 2
val getActivityReference =
getInstruction<ReferenceInstruction>(getActivityIndex).reference
val classRegister =
getInstruction<TwoRegisterInstruction>(getActivityIndex).registerB
val watchDescriptorMethodIndex =
getStringInstructionIndex("start_watch_minimized") - 1
indexOfFirstStringInstructionOrThrow("start_watch_minimized") - 1
val watchDescriptorRegister =
getInstruction<FiveRegisterInstruction>(watchDescriptorMethodIndex).registerD
@ -228,7 +233,7 @@ object FullscreenComponentsPatch : BaseBytecodePatch(
)
// hooks Activity.
val insertIndex = getStringInstructionIndex("force_fullscreen")
val insertIndex = indexOfFirstStringInstructionOrThrow("force_fullscreen")
val freeRegister = getInstruction<OneRegisterInstruction>(insertIndex).registerA
addInstructions(
@ -244,9 +249,10 @@ object FullscreenComponentsPatch : BaseBytecodePatch(
VideoPortraitParentFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val stringIndex =
getStringInstructionIndex("Acquiring NetLatencyActionLogger failed. taskId=")
val invokeIndex = getTargetIndexOrThrow(stringIndex, Opcode.INVOKE_INTERFACE)
val targetIndex = getTargetIndexOrThrow(invokeIndex, Opcode.CHECK_CAST)
indexOfFirstStringInstructionOrThrow("Acquiring NetLatencyActionLogger failed. taskId=")
val invokeIndex =
indexOfFirstInstructionOrThrow(stringIndex, Opcode.INVOKE_INTERFACE)
val targetIndex = indexOfFirstInstructionOrThrow(invokeIndex, Opcode.CHECK_CAST)
val targetClass = context
.findClass(getInstruction<ReferenceInstruction>(targetIndex).reference.toString())!!
.mutableClass
@ -328,8 +334,9 @@ object FullscreenComponentsPatch : BaseBytecodePatch(
BroadcastReceiverFingerprint.resultOrThrow().let { result ->
result.mutableMethod.apply {
val stringIndex =
getStringInstructionIndex("android.intent.action.SCREEN_ON")
val insertIndex = getTargetIndexOrThrow(stringIndex, Opcode.IF_EQZ) + 1
indexOfFirstStringInstructionOrThrow("android.intent.action.SCREEN_ON")
val insertIndex =
indexOfFirstInstructionOrThrow(stringIndex, Opcode.IF_EQZ) + 1
addInstruction(
insertIndex,

View File

@ -13,7 +13,7 @@ import app.revanced.patches.youtube.player.hapticfeedback.fingerprints.ZoomHapti
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
import app.revanced.patches.youtube.utils.integrations.Constants.PLAYER_CLASS_DESCRIPTOR
import app.revanced.patches.youtube.utils.settings.SettingsPatch
import app.revanced.util.getTargetIndexOrThrow
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.patch.BaseBytecodePatch
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode
@ -65,7 +65,7 @@ object HapticFeedBackPatch : BaseBytecodePatch(
var register = 0
if (name == "run") {
index = getTargetIndexOrThrow(Opcode.SGET)
index = indexOfFirstInstructionOrThrow(Opcode.SGET)
register = getInstruction<OneRegisterInstruction>(index).registerA
}

View File

@ -30,11 +30,11 @@ import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.ReelT
import app.revanced.patches.youtube.utils.settings.SettingsPatch
import app.revanced.patches.youtube.utils.settings.SettingsPatch.contexts
import app.revanced.patches.youtube.video.information.VideoInformationPatch
import app.revanced.util.getTargetIndexOrThrow
import app.revanced.util.getTargetIndexWithMethodReferenceNameOrThrow
import app.revanced.util.getReference
import app.revanced.util.getWalkerMethod
import app.revanced.util.getWideLiteralInstructionIndex
import app.revanced.util.literalInstructionBooleanHook
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow
import app.revanced.util.injectLiteralInstructionBooleanCall
import app.revanced.util.patch.BaseBytecodePatch
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode
@ -44,6 +44,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.NarrowLiteralInstruction
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.reference.MethodReference
import org.w3c.dom.Element
@Suppress("DEPRECATION", "unused")
@ -139,11 +140,14 @@ object SeekbarComponentsPatch : BaseBytecodePatch(
TotalTimeFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val charSequenceIndex =
getTargetIndexWithMethodReferenceNameOrThrow("getString") + 1
val charSequenceIndex = indexOfFirstInstructionOrThrow {
getReference<MethodReference>()?.name == "getString"
} + 1
val charSequenceRegister =
getInstruction<OneRegisterInstruction>(charSequenceIndex).registerA
val textViewIndex = getTargetIndexWithMethodReferenceNameOrThrow("getText")
val textViewIndex = indexOfFirstInstructionOrThrow {
getReference<MethodReference>()?.name == "getText"
}
val textViewRegister =
getInstruction<FiveRegisterInstruction>(textViewIndex).registerC
@ -162,12 +166,12 @@ object SeekbarComponentsPatch : BaseBytecodePatch(
// region patch for seekbar color
PlayerSeekbarColorFingerprint.resultOrThrow().mutableMethod.apply {
hook(getWideLiteralInstructionIndex(InlineTimeBarColorizedBarPlayedColorDark) + 2)
hook(getWideLiteralInstructionIndex(InlineTimeBarPlayedNotHighlightedColor) + 2)
hook(InlineTimeBarColorizedBarPlayedColorDark)
hook(InlineTimeBarPlayedNotHighlightedColor)
}
ShortsSeekbarColorFingerprint.resultOrThrow().mutableMethod.apply {
hook(getWideLiteralInstructionIndex(ReelTimeBarPlayedColor) + 2)
hook(ReelTimeBarPlayedColor)
}
ControlsOverlayStyleFingerprint.resultOrThrow().let {
@ -212,7 +216,7 @@ object SeekbarComponentsPatch : BaseBytecodePatch(
PlayerButtonsVisibilityFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val freeRegister = implementation!!.registerCount - parameters.size - 2
val viewIndex = getTargetIndexOrThrow(Opcode.INVOKE_INTERFACE)
val viewIndex = indexOfFirstInstructionOrThrow(Opcode.INVOKE_INTERFACE)
val viewRegister = getInstruction<FiveRegisterInstruction>(viewIndex).registerD
addInstructionsWithLabels(
@ -271,7 +275,7 @@ object SeekbarComponentsPatch : BaseBytecodePatch(
// region patch for restore old seekbar thumbnails
ThumbnailPreviewConfigFingerprint.result?.let {
ThumbnailPreviewConfigFingerprint.literalInstructionBooleanHook(
ThumbnailPreviewConfigFingerprint.injectLiteralInstructionBooleanCall(
45398577,
"$PLAYER_CLASS_DESCRIPTOR->restoreOldSeekbarThumbnails()Z"
)
@ -285,7 +289,7 @@ object SeekbarComponentsPatch : BaseBytecodePatch(
// region patch for enable cairo seekbar
if (SettingsPatch.upward1923) {
CairoSeekbarConfigFingerprint.literalInstructionBooleanHook(
CairoSeekbarConfigFingerprint.injectLiteralInstructionBooleanCall(
45617850,
"$PLAYER_CLASS_DESCRIPTOR->enableCairoSeekbar()Z"
)
@ -303,7 +307,8 @@ object SeekbarComponentsPatch : BaseBytecodePatch(
SettingsPatch.updatePatchStatus(this)
}
private fun MutableMethod.hook(insertIndex: Int) {
private fun MutableMethod.hook(literal: Long) {
val insertIndex = indexOfFirstWideLiteralInstructionValueOrThrow(literal) + 2
val insertRegister = getInstruction<OneRegisterInstruction>(insertIndex).registerA
addInstructions(

View File

@ -15,18 +15,15 @@ import app.revanced.patches.youtube.player.speedoverlay.fingerprints.NextGenWatc
import app.revanced.patches.youtube.player.speedoverlay.fingerprints.RestoreSlideToSeekBehaviorFingerprint
import app.revanced.patches.youtube.player.speedoverlay.fingerprints.SlideToSeekMotionEventFingerprint
import app.revanced.patches.youtube.player.speedoverlay.fingerprints.SpeedOverlayFingerprint
import app.revanced.patches.youtube.player.speedoverlay.fingerprints.SpeedOverlayFloatValueFingerprint
import app.revanced.patches.youtube.player.speedoverlay.fingerprints.SpeedOverlayTextValueFingerprint
import app.revanced.patches.youtube.player.speedoverlay.fingerprints.SpeedOverlayValueFingerprint
import app.revanced.patches.youtube.utils.integrations.Constants.PLAYER_CLASS_DESCRIPTOR
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch
import app.revanced.util.alsoResolve
import app.revanced.util.getReference
import app.revanced.util.getTargetIndexOrThrow
import app.revanced.util.getTargetIndexReversedOrThrow
import app.revanced.util.getTargetIndexWithMethodReferenceNameOrThrow
import app.revanced.util.getTargetIndexWithMethodReferenceNameReversedOrThrow
import app.revanced.util.getWalkerMethod
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.literalInstructionBooleanHook
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
import app.revanced.util.injectLiteralInstructionBooleanCall
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
@ -35,6 +32,8 @@ 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.TwoRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
import com.android.tools.smali.dexlib2.util.MethodUtil
@Patch(dependencies = [SharedResourceIdPatch::class])
object SpeedOverlayPatch : BytecodePatch(
@ -43,8 +42,8 @@ object SpeedOverlayPatch : BytecodePatch(
NextGenWatchLayoutFingerprint,
RestoreSlideToSeekBehaviorFingerprint,
SpeedOverlayFingerprint,
SpeedOverlayFloatValueFingerprint,
SpeedOverlayTextValueFingerprint,
SpeedOverlayValueFingerprint,
)
) {
override fun execute(context: BytecodeContext) {
@ -52,36 +51,33 @@ object SpeedOverlayPatch : BytecodePatch(
val restoreSlideToSeekBehaviorFingerprintResult =
RestoreSlideToSeekBehaviorFingerprint.result
val speedOverlayFingerprintResult = SpeedOverlayFingerprint.result
val speedOverlayValueFingerprintResult = SpeedOverlayValueFingerprint.result
val speedOverlayFloatValueFingerprintResult = SpeedOverlayFloatValueFingerprint.result
val resolvable =
restoreSlideToSeekBehaviorFingerprintResult != null
&& speedOverlayFingerprintResult != null
&& speedOverlayValueFingerprintResult != null
&& speedOverlayFloatValueFingerprintResult != null
if (resolvable) {
// Legacy method.
// Used on YouTube 18.29.38 ~ YouTube 19.17.41
// region patch for disable speed overlay
// region patch for Disable speed overlay (Enable slide to seek)
mapOf(
RestoreSlideToSeekBehaviorFingerprint to 45411329,
SpeedOverlayFingerprint to 45411330
).forEach { (fingerprint, literal) ->
fingerprint.result!!.let {
fingerprint.literalInstructionBooleanHook(
literal,
"$PLAYER_CLASS_DESCRIPTOR->disableSpeedOverlay(Z)Z"
)
}
fingerprint.injectLiteralInstructionBooleanCall(
literal,
"$PLAYER_CLASS_DESCRIPTOR->disableSpeedOverlay(Z)Z"
)
}
// endregion
// region patch for custom speed overlay value
// region patch for Custom speed overlay float value
speedOverlayValueFingerprintResult!!.let {
speedOverlayFloatValueFingerprintResult!!.let {
it.mutableMethod.apply {
val index = it.scanResult.patternScanResult!!.startIndex
val register = getInstruction<TwoRegisterInstruction>(index).registerA
@ -98,13 +94,18 @@ object SpeedOverlayPatch : BytecodePatch(
// endregion
} else {
// New method.
// Used on YouTube 19.18.41~
NextGenWatchLayoutFingerprint.resultOrThrow().mutableMethod.apply {
val booleanValueIndex = getTargetIndexWithMethodReferenceNameOrThrow("booleanValue")
// region patch for Disable speed overlay (Enable slide to seek)
val insertIndex = findIGetIndex(booleanValueIndex - 10, booleanValueIndex)
NextGenWatchLayoutFingerprint.resultOrThrow().mutableMethod.apply {
val booleanValueIndex = indexOfFirstInstructionOrThrow {
getReference<MethodReference>()?.name == "booleanValue"
}
val insertIndex = indexOfFirstInstructionOrThrow(booleanValueIndex - 10) {
opcode == Opcode.IGET_OBJECT
&& getReference<FieldReference>()?.definingClass == definingClass
}
val insertInstruction = getInstruction<TwoRegisterInstruction>(insertIndex)
val insertReference = getInstruction<ReferenceInstruction>(insertIndex).reference
@ -113,77 +114,107 @@ object SpeedOverlayPatch : BytecodePatch(
"iget-object v${insertInstruction.registerA}, v${insertInstruction.registerB}, $insertReference"
)
val jumpIndex = findIGetIndex(booleanValueIndex, booleanValueIndex + 10)
val jumpIndex = indexOfFirstInstructionOrThrow(booleanValueIndex) {
opcode == Opcode.IGET_OBJECT
&& getReference<FieldReference>()?.definingClass == definingClass
}
hook(insertIndex + 1, insertInstruction.registerA, jumpIndex)
}
SlideToSeekMotionEventFingerprint.resolve(
context,
HorizontalTouchOffsetConstructorFingerprint.resultOrThrow().classDef
)
SlideToSeekMotionEventFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val scanResult = it.scanResult.patternScanResult!!
val (slideToSeekBooleanMethod, slideToSeekSyntheticMethod) =
SlideToSeekMotionEventFingerprint.alsoResolve(
context, HorizontalTouchOffsetConstructorFingerprint
).let {
with(it.mutableMethod) {
val scanResult = it.scanResult.patternScanResult!!
val jumpIndex = scanResult.endIndex + 1
val insertIndex = scanResult.endIndex - 1
val insertRegister =
getInstruction<TwoRegisterInstruction>(insertIndex).registerA
val slideToSeekBooleanIndex = scanResult.startIndex + 1
slideToSeekBooleanMethod = getWalkerMethod(context, slideToSeekBooleanIndex)
val jumpIndex = scanResult.endIndex + 1
val insertIndex = scanResult.endIndex - 1
val insertRegister =
getInstruction<TwoRegisterInstruction>(insertIndex).registerA
hook(insertIndex, insertRegister, jumpIndex)
}
}
slideToSeekBooleanMethod.apply {
var insertIndex = getTargetIndexOrThrow(Opcode.IGET_OBJECT)
var insertRegister = getInstruction<TwoRegisterInstruction>(insertIndex).registerA
var jumpIndex = getTargetIndexReversedOrThrow(Opcode.INVOKE_VIRTUAL)
hook(insertIndex, insertRegister, jumpIndex)
val constructorMethod =
context.findClass(definingClass)?.mutableClass
?.methods?.find { method -> method.name == "<init>" }
?: throw PatchException("Could not find constructor method")
constructorMethod.apply {
val syntheticIndex = getTargetIndexReversedOrThrow(Opcode.NEW_INSTANCE)
val syntheticClass =
getInstruction<ReferenceInstruction>(syntheticIndex).reference.toString()
val syntheticMethod =
context.findClass(syntheticClass)?.mutableClass
?.methods?.find { method -> method.name == "run" }
?: throw PatchException("Could not find synthetic method")
syntheticMethod.apply {
val speedOverlayValueIndex =
indexOfFirstInstructionOrThrow { (this as? NarrowLiteralInstruction)?.narrowLiteral == 2.0f.toRawBits() }
val speedOverlayValueRegister =
getInstruction<OneRegisterInstruction>(speedOverlayValueIndex).registerA
addInstructions(
speedOverlayValueIndex + 1, """
invoke-static {v$speedOverlayValueRegister}, $PLAYER_CLASS_DESCRIPTOR->speedOverlayValue(F)F
move-result v$speedOverlayValueRegister
"""
)
insertIndex = getTargetIndexWithMethodReferenceNameReversedOrThrow(
speedOverlayValueIndex,
"removeCallbacks"
) + 1
insertRegister =
getInstruction<FiveRegisterInstruction>(insertIndex - 1).registerC
jumpIndex =
getTargetIndexOrThrow(speedOverlayValueIndex, Opcode.RETURN_VOID) + 1
hook(insertIndex, insertRegister, jumpIndex)
val slideToSeekBooleanMethod = context.toMethodWalker(it.mutableMethod)
.nextMethod(scanResult.startIndex + 1, true)
.getMethod() as MutableMethod
val slideToSeekConstructorMethod =
context.findClass { classDef -> classDef.type == slideToSeekBooleanMethod.definingClass }
?.mutableClass
?.methods
?.find { method -> MethodUtil.isConstructor(method) }
?: throw PatchException("Could not find constructor method")
val slideToSeekSyntheticIndex = slideToSeekConstructorMethod
.indexOfFirstInstructionReversedOrThrow {
opcode == Opcode.NEW_INSTANCE
}
val slideToSeekSyntheticClass = slideToSeekConstructorMethod
.getInstruction<ReferenceInstruction>(slideToSeekSyntheticIndex)
.reference
.toString()
val slideToSeekSyntheticMethod =
context.findClass { classDef -> classDef.type == slideToSeekSyntheticClass }
?.mutableClass
?.methods
?.find { method -> method.name == "run" }
?: throw PatchException("Could not find synthetic method")
Pair(slideToSeekBooleanMethod, slideToSeekSyntheticMethod)
}
}
slideToSeekBooleanMethod.apply {
val insertIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.IGET_OBJECT
}
val insertRegister = getInstruction<TwoRegisterInstruction>(insertIndex).registerA
val jumpIndex = indexOfFirstInstructionReversedOrThrow {
opcode == Opcode.INVOKE_VIRTUAL
}
hook(insertIndex, insertRegister, jumpIndex)
}
slideToSeekSyntheticMethod.apply {
val speedOverlayFloatValueIndex = indexOfFirstInstructionOrThrow {
(this as? NarrowLiteralInstruction)?.narrowLiteral == 2.0f.toRawBits()
}
val insertIndex =
indexOfFirstInstructionReversedOrThrow(speedOverlayFloatValueIndex) {
getReference<MethodReference>()?.name == "removeCallbacks"
} + 1
val insertRegister =
getInstruction<FiveRegisterInstruction>(insertIndex - 1).registerC
val jumpIndex =
indexOfFirstInstructionOrThrow(
speedOverlayFloatValueIndex,
Opcode.RETURN_VOID
) + 1
hook(insertIndex, insertRegister, jumpIndex)
}
// endregion
// region patch for Custom speed overlay float value
slideToSeekSyntheticMethod.apply {
val speedOverlayFloatValueIndex = indexOfFirstInstructionOrThrow {
(this as? NarrowLiteralInstruction)?.narrowLiteral == 2.0f.toRawBits()
}
val speedOverlayFloatValueRegister =
getInstruction<OneRegisterInstruction>(speedOverlayFloatValueIndex).registerA
addInstructions(
speedOverlayFloatValueIndex + 1, """
invoke-static {v$speedOverlayFloatValueRegister}, $PLAYER_CLASS_DESCRIPTOR->speedOverlayValue(F)F
move-result v$speedOverlayFloatValueRegister
"""
)
}
SpeedOverlayTextValueFingerprint.resultOrThrow().let {
@ -200,11 +231,12 @@ object SpeedOverlayPatch : BytecodePatch(
)
}
}
// endregion
}
}
private lateinit var slideToSeekBooleanMethod: MutableMethod
// restore slide to seek
private fun MutableMethod.hook(
insertIndex: Int,
@ -220,14 +252,4 @@ object SpeedOverlayPatch : BytecodePatch(
""", ExternalLabel("disable", getInstruction(jumpIndex))
)
}
private fun MutableMethod.findIGetIndex(
startIndex: Int,
endIndex: Int
): Int = implementation!!.instructions.let { instruction ->
startIndex + instruction.subList(startIndex, endIndex).indexOfFirst {
it.opcode == Opcode.IGET_OBJECT
&& it.getReference<FieldReference>()?.definingClass == definingClass
}
}
}

View File

@ -2,8 +2,10 @@ package app.revanced.patches.youtube.player.speedoverlay.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.util.containsMethodReferenceNameInstructionIndex
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
internal object NextGenWatchLayoutFingerprint : MethodFingerprint(
returnType = "Z",
@ -13,6 +15,8 @@ internal object NextGenWatchLayoutFingerprint : MethodFingerprint(
if (methodDef.definingClass != "Lcom/google/android/apps/youtube/app/watch/nextgenwatch/ui/NextGenWatchLayout;")
return@handler false
methodDef.containsMethodReferenceNameInstructionIndex("booleanValue")
methodDef.indexOfFirstInstruction {
getReference<MethodReference>()?.name == "booleanValue"
} >= 0
}
)

View File

@ -5,6 +5,7 @@ import com.android.tools.smali.dexlib2.Opcode
/**
* This value restores the 'Slide to seek' behavior.
* Deprecated in YouTube v19.18.41+.
*/
internal object RestoreSlideToSeekBehaviorFingerprint : LiteralValueFingerprint(
returnType = "Z",

View File

@ -5,6 +5,7 @@ import com.android.tools.smali.dexlib2.Opcode
/**
* This value disables 'Playing at 2x speed' while holding down.
* Deprecated in YouTube v19.18.41+.
*/
internal object SpeedOverlayFingerprint : LiteralValueFingerprint(
returnType = "Z",

View File

@ -7,8 +7,9 @@ import com.android.tools.smali.dexlib2.Opcode
/**
* This value is the key for the playback speed overlay value.
* Deprecated in YouTube v19.18.41+.
*/
internal object SpeedOverlayValueFingerprint : LiteralValueFingerprint(
internal object SpeedOverlayFloatValueFingerprint : LiteralValueFingerprint(
returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
opcodes = listOf(Opcode.DOUBLE_TO_FLOAT),

View File

@ -1,14 +1,21 @@
package app.revanced.patches.youtube.player.speedoverlay.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.util.fingerprint.ReferenceFingerprint
import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
internal object SpeedOverlayTextValueFingerprint : ReferenceFingerprint(
internal object SpeedOverlayTextValueFingerprint : MethodFingerprint(
returnType = "V",
accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL,
parameters = emptyList(),
opcodes = listOf(Opcode.CONST_WIDE_HIGH16),
reference = { "Ljava/math/BigDecimal;->signum()I" }
customFingerprint = { methodDef, _ ->
methodDef.indexOfFirstInstruction {
getReference<MethodReference>()?.toString() == "Ljava/math/BigDecimal;->signum()I"
} >= 0
}
)