chore: remove obsolete code

This commit is contained in:
inotia00
2024-09-25 21:44:05 +09:00
parent 42d284654e
commit 0752ff0d72
31 changed files with 492 additions and 540 deletions

View File

@ -5,7 +5,6 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.music.flyoutmenu.components.fingerprints.DialogSolidFingerprint
import app.revanced.patches.music.flyoutmenu.components.fingerprints.EndButtonsContainerFingerprint
@ -20,11 +19,13 @@ import app.revanced.patches.music.utils.integrations.Constants.COMPONENTS_PATH
import app.revanced.patches.music.utils.integrations.Constants.FLYOUT_CLASS_DESCRIPTOR
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.EndButtonsContainer
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.TrimSilenceSwitch
import app.revanced.patches.music.utils.settings.CategoryType
import app.revanced.patches.music.utils.settings.SettingsPatch
import app.revanced.patches.music.utils.videotype.VideoTypeHookPatch
import app.revanced.patches.music.video.information.VideoInformationPatch
import app.revanced.patches.shared.litho.LithoFilterPatch
import app.revanced.util.findMethodOrThrow
import app.revanced.util.getReference
import app.revanced.util.getWalkerMethod
import app.revanced.util.indexOfFirstInstructionOrThrow
@ -95,40 +96,40 @@ object FlyoutMenuComponentsPatch : BaseBytecodePatch(
TrimSilenceSwitchFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val constIndex =
indexOfFirstWideLiteralInstructionValueOrThrow(SharedResourceIdPatch.TrimSilenceSwitch)
indexOfFirstWideLiteralInstructionValueOrThrow(TrimSilenceSwitch)
val onCheckedChangedListenerIndex =
indexOfFirstInstructionOrThrow(constIndex, Opcode.INVOKE_DIRECT)
val onCheckedChangedListenerReference =
getInstruction<ReferenceInstruction>(onCheckedChangedListenerIndex).reference
val onCheckedChangedListenerDefiningClass =
(onCheckedChangedListenerReference as MethodReference).definingClass
val onCheckedChangedListenerClass =
context.findClass(onCheckedChangedListenerDefiningClass)!!.mutableClass
onCheckedChangedListenerClass.methods.find { method -> method.name == "onCheckedChanged" }
?.apply {
val walkerIndex = indexOfFirstInstructionOrThrow {
val reference =
((this as? ReferenceInstruction)?.reference as? MethodReference)
val onCheckedChangedMethod =
context.findMethodOrThrow(onCheckedChangedListenerDefiningClass) {
name == "onCheckedChanged"
}
opcode == Opcode.INVOKE_VIRTUAL
&& reference?.returnType == "V"
&& reference.parameterTypes.size == 1
&& reference.parameterTypes[0] == "Z"
}
getWalkerMethod(context, walkerIndex).apply {
val insertIndex = indexOfFirstInstructionOrThrow(Opcode.MOVE_RESULT)
val insertRegister =
getInstruction<OneRegisterInstruction>(insertIndex).registerA
val onCheckedChangedWalkerIndex =
onCheckedChangedMethod.indexOfFirstInstructionOrThrow {
val reference = getReference<MethodReference>()
opcode == Opcode.INVOKE_VIRTUAL
&& reference?.returnType == "V"
&& reference.parameterTypes.size == 1
&& reference.parameterTypes[0] == "Z"
}
addInstructions(
insertIndex + 1, """
invoke-static {v$insertRegister}, $FLYOUT_CLASS_DESCRIPTOR->enableTrimSilenceSwitch(Z)Z
move-result v$insertRegister
"""
)
}
} ?: throw PatchException("onClickClass not found!")
getWalkerMethod(context, onCheckedChangedWalkerIndex).apply {
val insertIndex = indexOfFirstInstructionOrThrow(Opcode.MOVE_RESULT)
val insertRegister =
getInstruction<OneRegisterInstruction>(insertIndex).registerA
addInstructions(
insertIndex + 1, """
invoke-static {v$insertRegister}, $FLYOUT_CLASS_DESCRIPTOR->enableTrimSilenceSwitch(Z)Z
move-result v$insertRegister
"""
)
}
}
}

View File

@ -62,6 +62,7 @@ import app.revanced.patches.music.utils.videotype.VideoTypeHookPatch
import app.revanced.patches.shared.litho.LithoFilterPatch
import app.revanced.util.REGISTER_TEMPLATE_REPLACEMENT
import app.revanced.util.alsoResolve
import app.revanced.util.findMethodOrThrow
import app.revanced.util.getReference
import app.revanced.util.getWalkerMethod
import app.revanced.util.indexOfFirstInstructionOrThrow
@ -539,7 +540,7 @@ object PlayerComponentsPatch : BaseBytecodePatch(
opcode == Opcode.INVOKE_VIRTUAL
&& reference?.definingClass == "Lcom/google/android/material/bottomsheet/BottomSheetBehavior;"
&& reference.parameterTypes.first() == "Z"
}
}
val freeRegister =
getInstruction<FiveRegisterInstruction>(bottomSheetBehaviorIndex).registerD
@ -908,7 +909,8 @@ object PlayerComponentsPatch : BaseBytecodePatch(
MppWatchWhileLayoutFingerprint.resultOrThrow().mutableMethod.apply {
val callableIndex =
MppWatchWhileLayoutFingerprint.indexOfCallableInstruction(this)
val insertIndex = indexOfFirstInstructionReversedOrThrow(callableIndex, Opcode.NEW_INSTANCE)
val insertIndex =
indexOfFirstInstructionReversedOrThrow(callableIndex, Opcode.NEW_INSTANCE)
val insertRegister = getInstruction<OneRegisterInstruction>(insertIndex).registerA
addInstructionsWithLabels(
@ -929,7 +931,8 @@ object PlayerComponentsPatch : BaseBytecodePatch(
).let {
it.mutableMethod.apply {
val targetIndex = it.scanResult.patternScanResult!!.endIndex
val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
val targetRegister =
getInstruction<OneRegisterInstruction>(targetIndex).registerA
addInstructions(
targetIndex + 1, """
@ -1095,16 +1098,13 @@ object PlayerComponentsPatch : BaseBytecodePatch(
val onClickReference = getInstruction<ReferenceInstruction>(onClickIndex).reference
val onClickReferenceDefiningClass = (onClickReference as MethodReference).definingClass
val onClickClass =
context.findClass(onClickReferenceDefiningClass)!!.mutableClass
onClickClass.methods.find { method -> method.name == "<init>" }
?.apply {
context.findMethodOrThrow(onClickReferenceDefiningClass)
.apply {
addInstruction(
implementation!!.instructions.lastIndex,
"sput-object p0, $PLAYER_CLASS_DESCRIPTOR->$fieldName:$onClickReferenceDefiningClass"
)
} ?: throw PatchException("onClickClass not found!")
}
PlayerPatchConstructorFingerprint.resultOrThrow().let {
val mutableClass = it.mutableClass

View File

@ -6,7 +6,7 @@ import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.music.utils.flyoutmenu.fingerprints.PlaybackRateBottomSheetClassFingerprint
import app.revanced.patches.music.utils.integrations.Constants.INTEGRATIONS_PATH
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch
import app.revanced.util.addFieldAndInstructions
import app.revanced.util.addStaticFieldToIntegration
import app.revanced.util.resultOrThrow
@Patch(
@ -31,15 +31,12 @@ object FlyoutMenuHookPatch : BytecodePatch(
return-void
"""
context.findClass(
INTEGRATIONS_VIDEO_UTILS_CLASS_DESCRIPTOR
)!!.mutableClass.addFieldAndInstructions(
context,
context.addStaticFieldToIntegration(
INTEGRATIONS_VIDEO_UTILS_CLASS_DESCRIPTOR,
"showPlaybackSpeedFlyoutMenu",
"playbackRateBottomSheetClass",
definingClass,
smaliInstructions,
true
smaliInstructions
)
}
}

View File

@ -7,8 +7,8 @@ import app.revanced.patches.shared.mapping.ResourceMappingPatch
import app.revanced.patches.shared.mapping.ResourceMappingPatch.getId
import app.revanced.patches.shared.mapping.ResourceType.BOOL
import app.revanced.patches.shared.mapping.ResourceType.COLOR
import app.revanced.patches.shared.mapping.ResourceType.DRAWABLE
import app.revanced.patches.shared.mapping.ResourceType.DIMEN
import app.revanced.patches.shared.mapping.ResourceType.DRAWABLE
import app.revanced.patches.shared.mapping.ResourceType.ID
import app.revanced.patches.shared.mapping.ResourceType.LAYOUT
import app.revanced.patches.shared.mapping.ResourceType.STRING

View File

@ -61,11 +61,13 @@ object SponsorBlockBytecodePatch : BytecodePatch(
RectangleFieldInvalidatorFingerprint.alsoResolve(
context, SeekBarConstructorFingerprint
).let {
with (it.mutableMethod) {
val invalidateIndex = RectangleFieldInvalidatorFingerprint.indexOfInvalidateInstruction(this)
val rectangleIndex = indexOfFirstInstructionReversedOrThrow(invalidateIndex + 1) {
getReference<FieldReference>()?.type == "Landroid/graphics/Rect;"
}
with(it.mutableMethod) {
val invalidateIndex =
RectangleFieldInvalidatorFingerprint.indexOfInvalidateInstruction(this)
val rectangleIndex =
indexOfFirstInstructionReversedOrThrow(invalidateIndex + 1) {
getReference<FieldReference>()?.type == "Landroid/graphics/Rect;"
}
val rectangleReference =
getInstruction<ReferenceInstruction>(rectangleIndex).reference
@ -116,7 +118,7 @@ object SponsorBlockBytecodePatch : BytecodePatch(
*/
rectangleFieldName =
MusicPlaybackControlsTimeBarOnMeasureFingerprint.resultOrThrow().let {
with (it.mutableMethod) {
with(it.mutableMethod) {
val rectangleIndex = it.scanResult.patternScanResult!!.startIndex
val rectangleReference =
getInstruction<ReferenceInstruction>(rectangleIndex).reference

View File

@ -9,7 +9,6 @@ import app.revanced.patcher.fingerprint.MethodFingerprintResult
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patcher.util.proxy.mutableTypes.MutableClass
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
import app.revanced.patcher.util.smali.toInstructions
@ -24,7 +23,7 @@ import app.revanced.patches.music.video.information.fingerprints.VideoQualityLis
import app.revanced.patches.music.video.information.fingerprints.VideoQualityTextFingerprint
import app.revanced.patches.shared.fingerprints.MdxPlayerDirectorSetVideoStageFingerprint
import app.revanced.patches.shared.fingerprints.VideoLengthFingerprint
import app.revanced.util.addFieldAndInstructions
import app.revanced.util.addStaticFieldToIntegration
import app.revanced.util.alsoResolve
import app.revanced.util.getReference
import app.revanced.util.getWalkerMethod
@ -82,7 +81,6 @@ object VideoInformationPatch : BytecodePatch(
private var seekSourceEnumType = ""
private var seekSourceMethodName = ""
private lateinit var videoInformationMutableClass: MutableClass
private lateinit var context: BytecodeContext
private lateinit var playerConstructorMethod: MutableMethod
@ -138,21 +136,18 @@ object VideoInformationPatch : BytecodePatch(
return v0
"""
videoInformationMutableClass.addFieldAndInstructions(
context,
context.addStaticFieldToIntegration(
INTEGRATIONS_CLASS_DESCRIPTOR,
methodName,
fieldName,
definingClass,
smaliInstructions,
true
smaliInstructions
)
}
}
override fun execute(context: BytecodeContext) {
this.context = context
videoInformationMutableClass =
context.findClass(INTEGRATIONS_CLASS_DESCRIPTOR)!!.mutableClass
VideoEndFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
@ -211,9 +206,9 @@ object VideoInformationPatch : BytecodePatch(
PLAYER_RESPONSE_MODEL_CLASS_DESCRIPTOR =
getInstruction(playerResponseModelIndex)
.getReference<MethodReference>()
?.definingClass
?: throw PatchException("Could not find Player Response Model class")
.getReference<MethodReference>()
?.definingClass
?: throw PatchException("Could not find Player Response Model class")
videoIdMethodCall =
VideoIdFingerprint.getPlayerResponseInstruction("Ljava/lang/String;")
@ -302,13 +297,12 @@ object VideoInformationPatch : BytecodePatch(
return-void
"""
videoInformationMutableClass.addFieldAndInstructions(
context,
VideoInformationPatch.context.addStaticFieldToIntegration(
INTEGRATIONS_CLASS_DESCRIPTOR,
"overrideVideoQuality",
"videoQualityClass",
videoQualityClass,
smaliInstructions,
true
smaliInstructions
)
}

View File

@ -12,12 +12,13 @@ import app.revanced.patches.music.utils.settings.SettingsPatch
import app.revanced.patches.music.video.information.VideoInformationPatch
import app.revanced.patches.music.video.playback.fingerprints.PlaybackSpeedBottomSheetFingerprint
import app.revanced.patches.music.video.playback.fingerprints.UserQualityChangeFingerprint
import app.revanced.util.findMethodOrThrow
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.builder.instruction.BuilderInstruction21c
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
@Suppress("unused")
@ -84,19 +85,14 @@ object VideoPlaybackPatch : BaseBytecodePatch(
it.mutableMethod.apply {
val endIndex = it.scanResult.patternScanResult!!.endIndex
val qualityChangedClass =
context.findClass(
(getInstruction<BuilderInstruction21c>(endIndex))
.reference.toString()
)!!
.mutableClass
getInstruction<ReferenceInstruction>(endIndex).reference.toString()
val onItemClickMethod =
qualityChangedClass.methods.find { method -> method.name == "onItemClick" }
onItemClickMethod?.addInstruction(
context.findMethodOrThrow(qualityChangedClass) {
name == "onItemClick"
}.addInstruction(
0,
"invoke-static {}, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->userSelectedVideoQuality()V"
) ?: throw PatchException("Failed to find onItemClick method")
)
}
}

View File

@ -41,8 +41,7 @@ abstract class BaseAdsPatch(
MusicAdsFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val targetIndex = indexOfFirstInstructionOrThrow {
val reference = ((this as? ReferenceInstruction)?.reference as? MethodReference)
val reference = getReference<MethodReference>()
opcode == Opcode.INVOKE_VIRTUAL
&& reference?.returnType == "V"
&& reference.parameterTypes.size == 1

View File

@ -4,9 +4,9 @@ import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchException
import app.revanced.patches.shared.integrations.BaseIntegrationsPatch.IntegrationsFingerprint.IRegisterResolver
import app.revanced.patches.shared.integrations.Constants.INTEGRATIONS_UTILS_CLASS_DESCRIPTOR
import app.revanced.util.findMethodOrThrow
import app.revanced.util.isDeprecated
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode
@ -18,11 +18,7 @@ abstract class BaseIntegrationsPatch(
) : BytecodePatch(hooks) {
override fun execute(context: BytecodeContext) {
if (context.findClass(INTEGRATIONS_UTILS_CLASS_DESCRIPTOR) == null) {
throw PatchException(
"Integrations have not been merged yet. This patch can not succeed without merging the integrations.",
)
}
context.findMethodOrThrow(INTEGRATIONS_UTILS_CLASS_DESCRIPTOR)
hooks.forEach { hook ->
hook.invoke(INTEGRATIONS_UTILS_CLASS_DESCRIPTOR)

View File

@ -7,7 +7,6 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWith
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.or
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
import app.revanced.patcher.util.smali.ExternalLabel
@ -15,6 +14,7 @@ import app.revanced.patches.shared.integrations.Constants.COMPONENTS_PATH
import app.revanced.patches.shared.litho.fingerprints.ByteBufferFingerprint
import app.revanced.patches.shared.litho.fingerprints.EmptyComponentsFingerprint
import app.revanced.patches.shared.litho.fingerprints.PathBuilderFingerprint
import app.revanced.util.findMethodsOrThrow
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
@ -156,10 +156,8 @@ object LithoFilterPatch : BytecodePatch(
// Create a new method to get the filter array to avoid register conflicts.
// This fixes an issue with Integrations compiled with Android Gradle Plugin 8.3.0+.
// https://github.com/ReVanced/revanced-patches/issues/2818
val lithoFilterMethods = context.findClass(INTEGRATIONS_LITHO_FILER_CLASS_DESCRIPTOR)
?.mutableClass
?.methods
?: throw PatchException("LithoFilterPatch class not found.")
val lithoFilterMethods =
context.findMethodsOrThrow(INTEGRATIONS_LITHO_FILER_CLASS_DESCRIPTOR)
lithoFilterMethods
.first { it.name == "<clinit>" }

View File

@ -3,12 +3,12 @@ package app.revanced.patches.shared.viewgroup
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.shared.integrations.Constants.INTEGRATIONS_UTILS_CLASS_DESCRIPTOR
import app.revanced.patches.shared.viewgroup.fingerprints.ViewGroupMarginFingerprint
import app.revanced.patches.shared.viewgroup.fingerprints.ViewGroupMarginParentFingerprint
import app.revanced.util.resultOrThrow
import app.revanced.util.alsoResolve
import app.revanced.util.findMethodOrThrow
@Patch(
description = "Hook YouTube or YouTube Music to use ViewGroup.MarginLayoutParams in the integration.",
@ -18,26 +18,21 @@ object ViewGroupMarginLayoutParamsHookPatch : BytecodePatch(
) {
override fun execute(context: BytecodeContext) {
val method =
context.findClass(INTEGRATIONS_UTILS_CLASS_DESCRIPTOR)?.mutableClass?.methods?.first { method ->
method.name == "hideViewGroupByMarginLayoutParams"
} ?: throw PatchException("Could not find hideViewGroupByMarginLayoutParams method")
ViewGroupMarginFingerprint.resolve(
context,
ViewGroupMarginParentFingerprint.resultOrThrow().classDef
)
ViewGroupMarginFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val setViewGroupMarginCall = "$definingClass->$name(Landroid/view/View;II)V"
method.addInstructions(
0, """
const/4 v0, 0x0
invoke-static {p0, v0, v0}, $setViewGroupMarginCall
"""
)
}
val setViewGroupMarginCall = with(
ViewGroupMarginFingerprint.alsoResolve(
context, ViewGroupMarginParentFingerprint
).mutableMethod
) {
"$definingClass->$name(Landroid/view/View;II)V"
}
context.findMethodOrThrow(INTEGRATIONS_UTILS_CLASS_DESCRIPTOR) {
name == "hideViewGroupByMarginLayoutParams"
}.addInstructions(
0, """
const/4 v0, 0x0
invoke-static {p0, v0, v0}, $setViewGroupMarginCall
"""
)
}
}

View File

@ -19,6 +19,7 @@ import app.revanced.patches.youtube.utils.pip.PiPStateHookPatch
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch
import app.revanced.patches.youtube.utils.settings.SettingsPatch
import app.revanced.util.alsoResolve
import app.revanced.util.findMethodOrThrow
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.patch.BaseBytecodePatch
@ -87,23 +88,22 @@ object DownloadActionsPatch : BaseBytecodePatch(
?: throw PatchException("Could not find onClickListenerClass")
}
context.findClass(onClickListenerClass)
?.mutableClass
?.methods
?.first { method -> method.name == "onClick" }?.apply {
val insertIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.INVOKE_STATIC
&& getReference<MethodReference>()?.name == "isEmpty"
}
val insertRegister = getInstruction<FiveRegisterInstruction>(insertIndex).registerC
context.findMethodOrThrow(onClickListenerClass) {
name == "onClick"
}.apply {
val insertIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.INVOKE_STATIC
&& getReference<MethodReference>()?.name == "isEmpty"
}
val insertRegister = getInstruction<FiveRegisterInstruction>(insertIndex).registerC
addInstructions(
insertIndex, """
invoke-static {v$insertRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->inAppPlaylistDownloadButtonOnClick(Ljava/lang/String;)Ljava/lang/String;
move-result-object v$insertRegister
"""
)
} ?: throw PatchException("Could not find class $onClickListenerClass")
addInstructions(
insertIndex, """
invoke-static {v$insertRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->inAppPlaylistDownloadButtonOnClick(Ljava/lang/String;)Ljava/lang/String;
move-result-object v$insertRegister
"""
)
}
OfflinePlaylistEndpointFingerprint.resultOrThrow().mutableMethod.apply {
val playlistIdParameter = parameterTypes.indexOf("Ljava/lang/String;") + 1

View File

@ -11,6 +11,7 @@ import app.revanced.patches.youtube.utils.integrations.Constants.GENERAL_PATH
import app.revanced.patches.youtube.utils.settings.ResourceUtils.addEntryValues
import app.revanced.patches.youtube.utils.settings.SettingsBytecodePatch
import app.revanced.patches.youtube.utils.settings.SettingsPatch
import app.revanced.util.findMethodOrThrow
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.patch.BaseBytecodePatch
@ -39,13 +40,15 @@ object YouTubeMusicActionsPatch : BaseBytecodePatch(
AppDeepLinkFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val packageNameIndex = it.scanResult.patternScanResult!!.startIndex
val packageNameField = getInstruction<ReferenceInstruction>(packageNameIndex).reference.toString()
val packageNameField =
getInstruction<ReferenceInstruction>(packageNameIndex).reference.toString()
implementation!!.instructions
.withIndex()
.filter { (_, instruction) ->
instruction.opcode == Opcode.IGET_OBJECT &&
instruction.getReference<FieldReference>()?.toString() == packageNameField
instruction.getReference<FieldReference>()
?.toString() == packageNameField
}
.map { (index, _) -> index }
.reversed()
@ -78,30 +81,28 @@ object YouTubeMusicActionsPatch : BaseBytecodePatch(
override fun close() {
if (SettingsPatch.containsPatch("GmsCore support")) {
val musicPackageName = PackageNameYouTubeMusic.valueOrThrow()
SettingsPatch.contexts.addEntryValues(
"revanced_third_party_youtube_music_label",
"RVX Music"
)
SettingsPatch.contexts.addEntryValues(
"revanced_third_party_youtube_music_package_name",
PackageNameYouTubeMusic.valueOrThrow()
musicPackageName
)
SettingsBytecodePatch.contexts
.findClass { classDef -> classDef.type == INTEGRATIONS_CLASS_DESCRIPTOR }
?.mutableClass
?.methods
?.first { method -> method.name == "getRVXMusicPackageName" }
?.apply {
val replaceIndex = indexOfFirstInstructionOrThrow(Opcode.CONST_STRING)
val replaceRegister =
getInstruction<OneRegisterInstruction>(replaceIndex).registerA
SettingsBytecodePatch.contexts.findMethodOrThrow(INTEGRATIONS_CLASS_DESCRIPTOR) {
name == "getRVXMusicPackageName"
}.apply {
val replaceIndex = indexOfFirstInstructionOrThrow(Opcode.CONST_STRING)
val replaceRegister =
getInstruction<OneRegisterInstruction>(replaceIndex).registerA
replaceInstruction(
replaceIndex,
"const-string v$replaceRegister, \"${PackageNameYouTubeMusic.valueOrThrow()}\""
)
}
replaceInstruction(
replaceIndex,
"const-string v$replaceRegister, \"$musicPackageName\""
)
}
}
}

View File

@ -89,12 +89,12 @@ object NavigationBarComponentsPatch : BaseBytecodePatch(
AutoMotiveFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val insertIndex = indexOfFirstStringInstructionOrThrow("Android Automotive") - 1
val register = getInstruction<OneRegisterInstruction>(insertIndex).registerA
val insertRegister = getInstruction<OneRegisterInstruction>(insertIndex).registerA
addInstructions(
insertIndex, """
invoke-static {v$register}, $GENERAL_CLASS_DESCRIPTOR->switchCreateWithNotificationButton(Z)Z
move-result v$register
invoke-static {v$insertRegister}, $GENERAL_CLASS_DESCRIPTOR->switchCreateWithNotificationButton(Z)Z
move-result v$insertRegister
"""
)
}

View File

@ -41,6 +41,7 @@ import app.revanced.patches.youtube.utils.toolbar.ToolBarHookPatch
import app.revanced.util.REGISTER_TEMPLATE_REPLACEMENT
import app.revanced.util.alsoResolve
import app.revanced.util.doRecursively
import app.revanced.util.findMethodOrThrow
import app.revanced.util.getReference
import app.revanced.util.getWalkerMethod
import app.revanced.util.indexOfFirstInstructionOrThrow
@ -114,8 +115,8 @@ object ToolBarComponentsPatch : BaseBytecodePatch(
val attributeResolverMethodCall =
attributeResolverMethod.definingClass + "->" + attributeResolverMethod.name + "(Landroid/content/Context;I)Landroid/graphics/drawable/Drawable;"
context.findClass(GENERAL_CLASS_DESCRIPTOR)!!.mutableClass.methods.single { method ->
method.name == "getHeaderDrawable"
context.findMethodOrThrow(GENERAL_CLASS_DESCRIPTOR) {
name == "getHeaderDrawable"
}.addInstructions(
0, """
invoke-static {p0, p1}, $attributeResolverMethodCall
@ -381,15 +382,14 @@ object ToolBarComponentsPatch : BaseBytecodePatch(
ToolBarHookPatch.hook("$GENERAL_CLASS_DESCRIPTOR->replaceCreateButton")
val settingsClass = context.findClass("Shell_SettingsActivity")
?: throw PatchException("Shell_SettingsActivity class not found.")
settingsClass.mutableClass.methods.find { it.name == "onCreate" }?.apply {
addInstruction(
0,
"invoke-static {p0}, $GENERAL_CLASS_DESCRIPTOR->setShellActivityTheme(Landroid/app/Activity;)V"
)
} ?: throw PatchException("onCreate method not found.")
context.findMethodOrThrow(
"Lcom/google/android/apps/youtube/app/application/Shell_SettingsActivity;"
) {
name == "onCreate"
}.addInstruction(
0,
"invoke-static {p0}, $GENERAL_CLASS_DESCRIPTOR->setShellActivityTheme(Landroid/app/Activity;)V"
)
// endregion

View File

@ -141,7 +141,10 @@ object ChangeHeaderPatch : BaseResourcePatch(
}
if (customBrandingIconType == "youtube_minimal_header") {
SettingsBytecodePatch.contexts.updatePatchStatus(PATCH_STATUS_CLASS_DESCRIPTOR, "MinimalHeader")
SettingsBytecodePatch.contexts.updatePatchStatus(
PATCH_STATUS_CLASS_DESCRIPTOR,
"MinimalHeader"
)
}
} else {
println(warnings)

View File

@ -3,13 +3,13 @@ package app.revanced.patches.youtube.player.ambientmode
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.PatchException
import app.revanced.patches.youtube.player.ambientmode.fingerprints.AmbientModeInFullscreenFingerprint
import app.revanced.patches.youtube.player.ambientmode.fingerprints.PowerSaveModeBroadcastReceiverFingerprint
import app.revanced.patches.youtube.player.ambientmode.fingerprints.PowerSaveModeSyntheticFingerprint
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.findMethodOrThrow
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
import app.revanced.util.indexOfFirstStringInstructionOrThrow
@ -19,7 +19,6 @@ 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.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
@Suppress("unused")
@ -60,27 +59,30 @@ object AmbientModeSwitchPatch : BaseBytecodePatch(
}
syntheticClassList.distinct().forEach { className ->
context.findClass(className)?.mutableClass?.methods?.first { method ->
method.name == "accept"
}?.apply {
for (index in implementation!!.instructions.size - 1 downTo 0) {
val instruction = getInstruction(index)
if (instruction.opcode != Opcode.INVOKE_VIRTUAL)
continue
context.findMethodOrThrow(className) {
name == "accept"
}.apply {
implementation!!.instructions
.withIndex()
.filter { (_, instruction) ->
val reference = (instruction as? ReferenceInstruction)?.reference
instruction.opcode == Opcode.INVOKE_VIRTUAL &&
reference is MethodReference &&
reference.name == "isPowerSaveMode"
}
.map { (index, _) -> index }
.reversed()
.forEach { index ->
val register = getInstruction<OneRegisterInstruction>(index + 1).registerA
if (((instruction as Instruction35c).reference as MethodReference).name != "isPowerSaveMode")
continue
val register = getInstruction<OneRegisterInstruction>(index + 1).registerA
addInstructions(
index + 2, """
invoke-static {v$register}, $PLAYER_CLASS_DESCRIPTOR->bypassAmbientModeRestrictions(Z)Z
move-result v$register
"""
)
}
} ?: throw PatchException("Could not find $className")
addInstructions(
index + 2, """
invoke-static {v$register}, $PLAYER_CLASS_DESCRIPTOR->bypassAmbientModeRestrictions(Z)Z
move-result v$register
"""
)
}
}
}
// endregion

View File

@ -48,6 +48,7 @@ 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.findMethodOrThrow
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
@ -146,15 +147,13 @@ object PlayerComponentsPatch : BaseBytecodePatch(
hookInitVideoPanel(1)
} else {
val syntheticIndex =
indexOfFirstInstructionOrThrow(opcode = Opcode.NEW_INSTANCE)
indexOfFirstInstructionOrThrow(Opcode.NEW_INSTANCE)
val syntheticReference =
getInstruction<ReferenceInstruction>(syntheticIndex).reference.toString()
val syntheticClass =
context.findClass(syntheticReference)!!.mutableClass
syntheticClass.methods.find { method -> method.name == "onClick" }
?.hookInitVideoPanel(0)
?: throw PatchException("Could not find onClick method in $syntheticReference")
context.findMethodOrThrow(syntheticReference) {
name == "onClick"
}.hookInitVideoPanel(0)
}
}
}

View File

@ -29,6 +29,7 @@ import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.AutoN
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.FullScreenEngagementPanel
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.QuickActionsElementContainer
import app.revanced.patches.youtube.utils.settings.SettingsPatch
import app.revanced.util.findMethodOrThrow
import app.revanced.util.getReference
import app.revanced.util.getWalkerMethod
import app.revanced.util.indexOfFirstInstructionOrThrow
@ -253,18 +254,16 @@ object FullscreenComponentsPatch : BaseBytecodePatch(
val invokeIndex =
indexOfFirstInstructionOrThrow(stringIndex, Opcode.INVOKE_INTERFACE)
val targetIndex = indexOfFirstInstructionOrThrow(invokeIndex, Opcode.CHECK_CAST)
val targetClass = context
.findClass(getInstruction<ReferenceInstruction>(targetIndex).reference.toString())!!
.mutableClass
val targetClass =
getInstruction<ReferenceInstruction>(targetIndex).reference.toString()
// add an instruction to check the vertical video
targetClass.methods.find { method -> method.parameters == listOf("I", "I", "Z") }
?.apply {
addInstruction(
1,
"invoke-static {p1, p2}, $PLAYER_CLASS_DESCRIPTOR->setVideoPortrait(II)V"
)
} ?: throw PatchException("Could not find targetMethod")
context.findMethodOrThrow(targetClass) {
parameters == listOf("I", "I", "Z")
}.addInstruction(
1,
"invoke-static {p1, p2}, $PLAYER_CLASS_DESCRIPTOR->setVideoPortrait(II)V"
)
}
}
@ -281,14 +280,11 @@ object FullscreenComponentsPatch : BaseBytecodePatch(
}
val walkerMethod = getWalkerMethod(context, walkerIndex)
val targetClass =
context.findClass(walkerMethod.definingClass)!!.mutableClass
val constructorMethod = targetClass
.methods
.find { method ->
method.name == "<init>"
&& method.parameterTypes == listOf("Landroid/app/Activity;")
} ?: throw PatchException("Constructor method not found!")
val constructorMethod =
context.findMethodOrThrow(walkerMethod.definingClass) {
name == "<init>" &&
parameterTypes == listOf("Landroid/app/Activity;")
}
arrayOf(
walkerMethod,

View File

@ -30,6 +30,7 @@ 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.findMethodsOrThrow
import app.revanced.util.getReference
import app.revanced.util.getWalkerMethod
import app.revanced.util.indexOfFirstInstructionOrThrow
@ -38,8 +39,6 @@ import app.revanced.util.injectLiteralInstructionBooleanCall
import app.revanced.util.patch.BaseBytecodePatch
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction35c
import com.android.tools.smali.dexlib2.dexbacked.reference.DexBackedMethodReference
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
@ -84,14 +83,15 @@ object SeekbarComponentsPatch : BaseBytecodePatch(
SeekbarTappingFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val tapSeekIndex = it.scanResult.patternScanResult!!.startIndex + 1
val tapSeekReference = getInstruction<BuilderInstruction35c>(tapSeekIndex).reference
val tapSeekClass =
context
.findClass((tapSeekReference as DexBackedMethodReference).definingClass)!!
.mutableClass
val tapSeekMethods = mutableMapOf<String, MutableMethod>()
val tapSeekClass = getInstruction(tapSeekIndex)
.getReference<MethodReference>()!!
.definingClass
for (method in tapSeekClass.methods) {
val tapSeekMethods = context.findMethodsOrThrow(tapSeekClass)
var pMethodCall = ""
var oMethodCall = ""
for (method in tapSeekMethods) {
if (method.implementation == null)
continue
@ -110,15 +110,17 @@ object SeekbarComponentsPatch : BaseBytecodePatch(
// method founds
if (literal == 1)
tapSeekMethods["P"] = method
pMethodCall = "${method.definingClass}->${method.name}(I)V"
else if (literal == 2)
tapSeekMethods["O"] = method
oMethodCall = "${method.definingClass}->${method.name}(I)V"
}
val pMethod = tapSeekMethods["P"]
?: throw PatchException("pMethod not found")
val oMethod = tapSeekMethods["O"]
?: throw PatchException("oMethod not found")
if (pMethodCall.isEmpty()) {
throw PatchException("pMethod not found")
}
if (oMethodCall.isEmpty()) {
throw PatchException("oMethod not found")
}
val insertIndex = it.scanResult.patternScanResult!!.startIndex + 2
@ -127,8 +129,8 @@ object SeekbarComponentsPatch : BaseBytecodePatch(
invoke-static {}, $PLAYER_CLASS_DESCRIPTOR->enableSeekbarTapping()Z
move-result v0
if-eqz v0, :disabled
invoke-virtual { p0, v2 }, ${oMethod.definingClass}->${oMethod.name}(I)V
invoke-virtual { p0, v2 }, ${pMethod.definingClass}->${pMethod.name}(I)V
invoke-virtual { p0, v2 }, $pMethodCall
invoke-virtual { p0, v2 }, $oMethodCall
""", ExternalLabel("disabled", getInstruction(insertIndex))
)
}

View File

@ -6,7 +6,6 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patcher.util.smali.ExternalLabel
@ -20,7 +19,9 @@ import app.revanced.patches.youtube.player.speedoverlay.fingerprints.SpeedOverla
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.findMethodOrThrow
import app.revanced.util.getReference
import app.revanced.util.getWalkerMethod
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
import app.revanced.util.injectLiteralInstructionBooleanCall
@ -33,7 +34,6 @@ 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(
@ -135,16 +135,11 @@ object SpeedOverlayPatch : BytecodePatch(
hook(insertIndex, insertRegister, jumpIndex)
val slideToSeekBooleanMethod = context.toMethodWalker(it.mutableMethod)
.nextMethod(scanResult.startIndex + 1, true)
.getMethod() as MutableMethod
val slideToSeekBooleanMethod =
getWalkerMethod(context, scanResult.startIndex + 1)
val slideToSeekConstructorMethod =
context.findClass { classDef -> classDef.type == slideToSeekBooleanMethod.definingClass }
?.mutableClass
?.methods
?.find { method -> MethodUtil.isConstructor(method) }
?: throw PatchException("Could not find constructor method")
context.findMethodOrThrow(slideToSeekBooleanMethod.definingClass)
val slideToSeekSyntheticIndex = slideToSeekConstructorMethod
.indexOfFirstInstructionReversedOrThrow {
@ -157,11 +152,9 @@ object SpeedOverlayPatch : BytecodePatch(
.toString()
val slideToSeekSyntheticMethod =
context.findClass { classDef -> classDef.type == slideToSeekSyntheticClass }
?.mutableClass
?.methods
?.find { method -> method.name == "run" }
?: throw PatchException("Could not find synthetic method")
context.findMethodOrThrow(slideToSeekSyntheticClass) {
name == "run"
}
Pair(slideToSeekBooleanMethod, slideToSeekSyntheticMethod)
}

View File

@ -6,7 +6,6 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.removeInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patches.youtube.utils.castbutton.fingerprints.MenuItemInitializeFingerprint
@ -18,6 +17,7 @@ import app.revanced.patches.youtube.utils.integrations.Constants.PLAYER_CLASS_DE
import app.revanced.patches.youtube.utils.integrations.Constants.UTILS_PATH
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch
import app.revanced.util.alsoResolve
import app.revanced.util.findMethodOrThrow
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.resultOrThrow
@ -50,17 +50,14 @@ object CastButtonPatch : BytecodePatch(
playerButtonMethod = PlayerButtonFingerprint.resultOrThrow().mutableMethod
val buttonClass = context.findClass("MediaRouteButton")
?: throw PatchException("MediaRouteButton class not found.")
buttonClass.mutableClass.methods.find { it.name == "setVisibility" }?.apply {
addInstructions(
0, """
invoke-static {p1}, $INTEGRATIONS_CLASS_DESCRIPTOR->hideCastButton(I)I
move-result p1
"""
)
} ?: throw PatchException("setVisibility method not found.")
context.findMethodOrThrow("Landroidx/mediarouter/app/MediaRouteButton;") {
name == "setVisibility"
}.addInstructions(
0, """
invoke-static {p1}, $INTEGRATIONS_CLASS_DESCRIPTOR->hideCastButton(I)I
move-result p1
"""
)
}

View File

@ -7,7 +7,7 @@ import app.revanced.patches.youtube.utils.fingerprints.PlaybackRateBottomSheetBu
import app.revanced.patches.youtube.utils.flyoutmenu.fingerprints.VideoQualityBottomSheetClassFingerprint
import app.revanced.patches.youtube.utils.integrations.Constants.INTEGRATIONS_PATH
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch
import app.revanced.util.addFieldAndInstructions
import app.revanced.util.addStaticFieldToIntegration
import app.revanced.util.resultOrThrow
@Patch(
@ -25,10 +25,6 @@ object FlyoutMenuHookPatch : BytecodePatch(
override fun execute(context: BytecodeContext) {
val videoUtilsMutableClass = context.findClass(
INTEGRATIONS_VIDEO_UTILS_CLASS_DESCRIPTOR
)!!.mutableClass
PlaybackRateBottomSheetBuilderFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val smaliInstructions =
@ -39,13 +35,12 @@ object FlyoutMenuHookPatch : BytecodePatch(
return-void
"""
videoUtilsMutableClass.addFieldAndInstructions(
context,
context.addStaticFieldToIntegration(
INTEGRATIONS_VIDEO_UTILS_CLASS_DESCRIPTOR,
"showPlaybackSpeedFlyoutMenu",
"playbackRateBottomSheetClass",
definingClass,
smaliInstructions,
true
smaliInstructions
)
}
}
@ -61,13 +56,12 @@ object FlyoutMenuHookPatch : BytecodePatch(
return-void
"""
videoUtilsMutableClass.addFieldAndInstructions(
context,
context.addStaticFieldToIntegration(
INTEGRATIONS_VIDEO_UTILS_CLASS_DESCRIPTOR,
"showVideoQualityFlyoutMenu",
"videoQualityBottomSheetClass",
definingClass,
smaliInstructions,
true
smaliInstructions
)
}
}

View File

@ -3,11 +3,11 @@ package app.revanced.patches.youtube.utils.lottie
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.youtube.utils.integrations.Constants.UTILS_PATH
import app.revanced.patches.youtube.utils.lottie.fingerprints.SetAnimationFingerprint
import app.revanced.patches.youtube.utils.lottie.fingerprints.SetAnimationFingerprint.LOTTIE_ANIMATION_VIEW_CLASS_DESCRIPTOR
import app.revanced.util.findMethodOrThrow
import app.revanced.util.resultOrThrow
@Patch(
@ -20,21 +20,15 @@ object LottieAnimationViewHookPatch : BytecodePatch(
"$UTILS_PATH/LottieAnimationViewPatch;"
override fun execute(context: BytecodeContext) {
val setAnimationMethodName = SetAnimationFingerprint.resultOrThrow().mutableMethod.name
val setAnimationCall = "invoke-virtual {p0, p1}, " +
LOTTIE_ANIMATION_VIEW_CLASS_DESCRIPTOR +
"->" +
setAnimationMethodName +
"(I)V"
context.findClass(INTEGRATIONS_CLASS_DESCRIPTOR)
?.mutableClass
?.methods
?.first { method -> method.name == "setAnimation" }
?.addInstruction(
0,
setAnimationCall
) ?: throw PatchException("Could not find setAnimation method")
context.findMethodOrThrow(INTEGRATIONS_CLASS_DESCRIPTOR) {
name == "setAnimation"
}.addInstruction(
0,
"invoke-virtual {p0, p1}, " +
LOTTIE_ANIMATION_VIEW_CLASS_DESCRIPTOR +
"->" +
SetAnimationFingerprint.resultOrThrow().mutableMethod.name +
"(I)V"
)
}
}

View File

@ -18,6 +18,7 @@ import app.revanced.patches.youtube.utils.navigation.fingerprints.PivotBarButton
import app.revanced.patches.youtube.utils.navigation.fingerprints.PivotBarConstructorFingerprint
import app.revanced.patches.youtube.utils.playertype.PlayerTypeHookPatch
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch
import app.revanced.util.findMethodOrThrow
import app.revanced.util.getReference
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode
@ -115,9 +116,9 @@ object NavigationBarHookPatch : BytecodePatch(
}
navigationTabCreatedCallback =
context.findClass(INTEGRATIONS_CLASS_DESCRIPTOR)?.mutableClass?.methods?.first { method ->
method.name == "navigationTabCreatedCallback"
} ?: throw PatchException("Could not find navigationTabCreatedCallback method")
context.findMethodOrThrow(INTEGRATIONS_CLASS_DESCRIPTOR) {
name == "navigationTabCreatedCallback"
}
MainActivityResolvePatch.injectOnBackPressedMethodCall(
INTEGRATIONS_CLASS_DESCRIPTOR,

View File

@ -17,6 +17,7 @@ import app.revanced.patches.youtube.utils.playercontrols.fingerprints.PlayerCont
import app.revanced.patches.youtube.utils.playercontrols.fingerprints.PlayerControlsVisibilityFingerprint
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch
import app.revanced.util.alsoResolve
import app.revanced.util.findMethodOrThrow
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode
@ -115,28 +116,25 @@ object PlayerControlsPatch : BytecodePatch(
// region set methods to inject into integration
val playerControlsMutableClass =
context.findClass(INTEGRATIONS_CLASS_DESCRIPTOR)!!.mutableClass
changeVisibilityMethod =
playerControlsMutableClass.methods.single { method ->
method.name == "changeVisibility"
&& method.parameters == listOf("Z", "Z")
context.findMethodOrThrow(INTEGRATIONS_CLASS_DESCRIPTOR) {
name == "changeVisibility"
&& parameters == listOf("Z", "Z")
}
changeVisibilityNegatedImmediatelyMethod =
playerControlsMutableClass.methods.single { method ->
method.name == "changeVisibilityNegatedImmediately"
context.findMethodOrThrow(INTEGRATIONS_CLASS_DESCRIPTOR) {
name == "changeVisibilityNegatedImmediately"
}
initializeBottomControlButtonMethod =
playerControlsMutableClass.methods.single { method ->
method.name == "initializeBottomControlButton"
context.findMethodOrThrow(INTEGRATIONS_CLASS_DESCRIPTOR) {
name == "initializeBottomControlButton"
}
initializeTopControlButtonMethod =
playerControlsMutableClass.methods.single { method ->
method.name == "initializeTopControlButton"
context.findMethodOrThrow(INTEGRATIONS_CLASS_DESCRIPTOR) {
name == "initializeTopControlButton"
}
// endregion

View File

@ -15,7 +15,10 @@ import app.revanced.patches.youtube.utils.playertype.fingerprint.BrowseIdClassFi
import app.revanced.patches.youtube.utils.playertype.fingerprint.PlayerTypeFingerprint
import app.revanced.patches.youtube.utils.playertype.fingerprint.VideoStateFingerprint
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch
import app.revanced.util.addFieldAndInstructions
import app.revanced.util.addStaticFieldToIntegration
import app.revanced.util.alsoResolve
import app.revanced.util.findMethodOrThrow
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstStringInstructionOrThrow
import app.revanced.util.resultOrThrow
@ -57,22 +60,20 @@ object PlayerTypeHookPatch : BytecodePatch(
// region patch for set video state
YouTubeControlsOverlayFingerprint.resultOrThrow().let { parentResult ->
VideoStateFingerprint.also {
it.resolve(context, parentResult.classDef)
}.resultOrThrow().let {
it.mutableMethod.apply {
val endIndex = it.scanResult.patternScanResult!!.endIndex
val videoStateFieldName =
getInstruction<ReferenceInstruction>(endIndex).reference
VideoStateFingerprint.alsoResolve(
context, YouTubeControlsOverlayFingerprint
).let {
it.mutableMethod.apply {
val endIndex = it.scanResult.patternScanResult!!.endIndex
val videoStateFieldName =
getInstruction<ReferenceInstruction>(endIndex).reference
addInstructions(
0, """
iget-object v0, p1, $videoStateFieldName # copy VideoState parameter field
invoke-static {v0}, $INTEGRATIONS_PLAYER_TYPE_HOOK_CLASS_DESCRIPTOR->setVideoState(Ljava/lang/Enum;)V
"""
)
}
addInstructions(
0, """
iget-object v0, p1, $videoStateFieldName # copy VideoState parameter field
invoke-static {v0}, $INTEGRATIONS_PLAYER_TYPE_HOOK_CLASS_DESCRIPTOR->setVideoState(Ljava/lang/Enum;)V
"""
)
}
}
@ -83,39 +84,36 @@ object PlayerTypeHookPatch : BytecodePatch(
BrowseIdClassFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val targetIndex = indexOfFirstStringInstructionOrThrow("VL") - 1
val targetReference = getInstruction<ReferenceInstruction>(targetIndex).reference
val targetClass =
context.findClass((targetReference as FieldReference).definingClass)!!.mutableClass
val targetClass = getInstruction(targetIndex)
.getReference<FieldReference>()
?.definingClass
?: throw PatchException("Could not find browseId class")
targetClass.methods.find { method -> method.name == "<init>" }
?.apply {
val browseIdFieldIndex = indexOfFirstInstructionOrThrow(Opcode.IPUT_OBJECT)
val browseIdFieldName =
(getInstruction<ReferenceInstruction>(browseIdFieldIndex).reference as FieldReference).name
context.findMethodOrThrow(targetClass).apply {
val browseIdFieldReference = getInstruction<ReferenceInstruction>(
indexOfFirstInstructionOrThrow(Opcode.IPUT_OBJECT)
).reference
val browseIdFieldName = (browseIdFieldReference as FieldReference).name
val smaliInstructions =
val smaliInstructions =
"""
if-eqz v0, :ignore
iget-object v0, v0, $definingClass->$browseIdFieldName:Ljava/lang/String;
if-eqz v0, :ignore
return-object v0
:ignore
const-string v0, ""
return-object v0
"""
if-eqz v0, :ignore
iget-object v0, v0, $definingClass->$browseIdFieldName:Ljava/lang/String;
if-eqz v0, :ignore
return-object v0
:ignore
const-string v0, ""
return-object v0
"""
val rootViewMutableClass =
context.findClass(INTEGRATIONS_ROOT_VIEW_HOOK_CLASS_DESCRIPTOR)!!.mutableClass
rootViewMutableClass.addFieldAndInstructions(
context,
"getBrowseId",
"browseIdClass",
definingClass,
smaliInstructions,
true
)
} ?: throw PatchException("BrowseIdClass not found!")
context.addStaticFieldToIntegration(
INTEGRATIONS_ROOT_VIEW_HOOK_CLASS_DESCRIPTOR,
"getBrowseId",
"browseIdClass",
definingClass,
smaliInstructions
)
}
}
}

View File

@ -6,7 +6,6 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWith
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.removeInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.youtube.utils.fingerprints.RollingNumberTextViewAnimationUpdateFingerprint
@ -17,6 +16,8 @@ import app.revanced.patches.youtube.utils.returnyoutubedislike.rollingnumber.fin
import app.revanced.patches.youtube.utils.returnyoutubedislike.rollingnumber.fingerprints.RollingNumberMeasureTextParentFingerprint
import app.revanced.patches.youtube.utils.returnyoutubedislike.rollingnumber.fingerprints.RollingNumberSetterFingerprint
import app.revanced.patches.youtube.utils.settings.SettingsPatch
import app.revanced.util.alsoResolve
import app.revanced.util.findMethodOrThrow
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.resultOrThrow
@ -26,7 +27,6 @@ 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.MethodReference
import com.android.tools.smali.dexlib2.iface.reference.Reference
@Patch(dependencies = [SettingsPatch::class])
object ReturnYouTubeDislikeRollingNumberPatch : BytecodePatch(
@ -47,130 +47,115 @@ object ReturnYouTubeDislikeRollingNumberPatch : BytecodePatch(
* 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) {
if (!SettingsPatch.upward1849) {
return
}
RollingNumberSetterFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val rollingNumberClassIndex = it.scanResult.patternScanResult!!.startIndex
val rollingNumberClassReference =
getInstruction<ReferenceInstruction>(rollingNumberClassIndex).reference
val rollingNumberClass =
context.findClass(rollingNumberClassReference.toString())!!.mutableClass
RollingNumberSetterFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val rollingNumberClassIndex = it.scanResult.patternScanResult!!.startIndex
val rollingNumberClassReference =
getInstruction<ReferenceInstruction>(rollingNumberClassIndex).reference.toString()
val rollingNumberConstructorMethod =
context.findMethodOrThrow(rollingNumberClassReference)
val charSequenceFieldReference = with(rollingNumberConstructorMethod) {
getInstruction<ReferenceInstruction>(
indexOfFirstInstructionOrThrow(Opcode.IPUT_OBJECT)
).reference
}
lateinit var charSequenceFieldReference: Reference
val insertIndex = rollingNumberClassIndex + 1
val charSequenceInstanceRegister =
getInstruction<OneRegisterInstruction>(rollingNumberClassIndex).registerA
val registerCount = implementation!!.registerCount
rollingNumberClass.methods.find { method -> method.name == "<init>" }
?.apply {
val rollingNumberFieldIndex =
indexOfFirstInstructionOrThrow(opcode = Opcode.IPUT_OBJECT)
charSequenceFieldReference =
getInstruction<ReferenceInstruction>(rollingNumberFieldIndex).reference
} ?: throw PatchException("RollingNumberClass not found!")
// This register is being overwritten, so it is free to use.
val freeRegister = registerCount - 1
val conversionContextRegister = registerCount - parameters.size + 1
val insertIndex = rollingNumberClassIndex + 1
val charSequenceInstanceRegister =
getInstruction<OneRegisterInstruction>(rollingNumberClassIndex).registerA
val registerCount = implementation!!.registerCount
// This register is being overwritten, so it is free to use.
val freeRegister = registerCount - 1
val conversionContextRegister = registerCount - parameters.size + 1
addInstructions(
insertIndex, """
addInstructions(
insertIndex, """
iget-object v$freeRegister, v$charSequenceInstanceRegister, $charSequenceFieldReference
invoke-static {v$conversionContextRegister, v$freeRegister}, $INTEGRATIONS_RYD_CLASS_DESCRIPTOR->onRollingNumberLoaded(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/String;
move-result-object v$freeRegister
iput-object v$freeRegister, v$charSequenceInstanceRegister, $charSequenceFieldReference
"""
)
}
)
}
}
// Rolling Number text views use the measured width of the raw string for layout.
// Modify the measure text calculation to include the left drawable separator if needed.
RollingNumberMeasureAnimatedTextFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val endIndex = it.scanResult.patternScanResult!!.endIndex
val measuredTextWidthIndex = endIndex - 2
val measuredTextWidthRegister =
getInstruction<TwoRegisterInstruction>(measuredTextWidthIndex).registerA
// Rolling Number text views use the measured width of the raw string for layout.
// Modify the measure text calculation to include the left drawable separator if needed.
RollingNumberMeasureAnimatedTextFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val endIndex = it.scanResult.patternScanResult!!.endIndex
val measuredTextWidthIndex = endIndex - 2
val measuredTextWidthRegister =
getInstruction<TwoRegisterInstruction>(measuredTextWidthIndex).registerA
addInstructions(
endIndex + 1, """
invoke-static {p1, v$measuredTextWidthRegister}, $INTEGRATIONS_RYD_CLASS_DESCRIPTOR->onRollingNumberMeasured(Ljava/lang/String;F)F
move-result v$measuredTextWidthRegister
"""
)
addInstructions(
endIndex + 1, """
invoke-static {p1, v$measuredTextWidthRegister}, $INTEGRATIONS_RYD_CLASS_DESCRIPTOR->onRollingNumberMeasured(Ljava/lang/String;F)F
move-result v$measuredTextWidthRegister
"""
)
val ifGeIndex = indexOfFirstInstructionOrThrow(opcode = Opcode.IF_GE)
val ifGeInstruction = getInstruction<TwoRegisterInstruction>(ifGeIndex)
val ifGeIndex = indexOfFirstInstructionOrThrow(opcode = Opcode.IF_GE)
val ifGeInstruction = getInstruction<TwoRegisterInstruction>(ifGeIndex)
removeInstruction(ifGeIndex)
addInstructionsWithLabels(
ifGeIndex, """
if-ge v${ifGeInstruction.registerA}, v${ifGeInstruction.registerB}, :jump
""", ExternalLabel("jump", getInstruction(endIndex))
)
}
removeInstruction(ifGeIndex)
addInstructionsWithLabels(
ifGeIndex, """
if-ge v${ifGeInstruction.registerA}, v${ifGeInstruction.registerB}, :jump
""", ExternalLabel("jump", getInstruction(endIndex))
)
}
}
RollingNumberMeasureTextParentFingerprint.resultOrThrow().classDef.let { parentClassDef ->
RollingNumberMeasureStaticLabelFingerprint.resolve(context, parentClassDef)
RollingNumberMeasureStaticLabelFingerprint.alsoResolve(
context,
RollingNumberMeasureTextParentFingerprint
).let {
it.mutableMethod.apply {
val measureTextIndex = it.scanResult.patternScanResult!!.startIndex + 1
val freeRegister = getInstruction<TwoRegisterInstruction>(0).registerA
// Additional text measurement method. Used if YouTube decides not to animate the likes count
// and sometimes used for initial video load.
RollingNumberMeasureStaticLabelFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val measureTextIndex = it.scanResult.patternScanResult!!.startIndex + 1
val freeRegister = getInstruction<TwoRegisterInstruction>(0).registerA
addInstructions(
measureTextIndex + 1, """
move-result v$freeRegister
invoke-static {p1, v$freeRegister}, $INTEGRATIONS_RYD_CLASS_DESCRIPTOR->onRollingNumberMeasured(Ljava/lang/String;F)F
"""
)
}
}
addInstructions(
measureTextIndex + 1, """
move-result v$freeRegister
invoke-static {p1, v$freeRegister}, $INTEGRATIONS_RYD_CLASS_DESCRIPTOR->onRollingNumberMeasured(Ljava/lang/String;F)F
"""
)
}
}
// The rolling number Span is missing styling since it's initially set as a String.
// Modify the UI text view and use the styled like/dislike Span.
RollingNumberTextViewFingerprint.resultOrThrow().let { parentResult ->
// Initial TextView is set in this method.
val initiallyCreatedTextViewMethod = parentResult.mutableMethod
// The rolling number Span is missing styling since it's initially set as a String.
// Modify the UI text view and use the styled like/dislike Span.
arrayOf(
// Initial TextView is set in this method.
RollingNumberTextViewFingerprint
.resultOrThrow(),
// Video less than 24 hours after uploaded, like counts will be updated in real time.
// Whenever like counts are updated, TextView is set in this method.
val realTimeUpdateTextViewMethod =
RollingNumberTextViewAnimationUpdateFingerprint.also {
it.resolve(context, parentResult.classDef)
}.resultOrThrow().mutableMethod
arrayOf(
initiallyCreatedTextViewMethod,
realTimeUpdateTextViewMethod
).forEach { insertMethod ->
insertMethod.apply {
val setTextIndex = indexOfFirstInstructionOrThrow {
getReference<MethodReference>()?.name == "setText"
}
val textViewRegister =
getInstruction<FiveRegisterInstruction>(setTextIndex).registerC
val textSpanRegister =
getInstruction<FiveRegisterInstruction>(setTextIndex).registerD
addInstructions(
setTextIndex, """
invoke-static {v$textViewRegister, v$textSpanRegister}, $INTEGRATIONS_RYD_CLASS_DESCRIPTOR->updateRollingNumber(Landroid/widget/TextView;Ljava/lang/CharSequence;)Ljava/lang/CharSequence;
move-result-object v$textSpanRegister
"""
)
}
// Video less than 24 hours after uploaded, like counts will be updated in real time.
// Whenever like counts are updated, TextView is set in this method.
RollingNumberTextViewAnimationUpdateFingerprint
.alsoResolve(context, RollingNumberTextViewFingerprint)
).forEach { fingerprintResult ->
fingerprintResult.mutableMethod.apply {
val setTextIndex = indexOfFirstInstructionOrThrow {
getReference<MethodReference>()?.name == "setText"
}
val textViewRegister =
getInstruction<FiveRegisterInstruction>(setTextIndex).registerC
val textSpanRegister =
getInstruction<FiveRegisterInstruction>(setTextIndex).registerD
addInstructions(
setTextIndex, """
invoke-static {v$textViewRegister, v$textSpanRegister}, $INTEGRATIONS_RYD_CLASS_DESCRIPTOR->updateRollingNumber(Landroid/widget/TextView;Ljava/lang/CharSequence;)Ljava/lang/CharSequence;
move-result-object v$textSpanRegister
"""
)
}
}
}

View File

@ -71,28 +71,30 @@ object ReturnYouTubeDislikeShortsPatch : BytecodePatch(
}
}
if (SettingsPatch.upward1834) {
TextComponentSpecFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val insertIndex = indexOfFirstInstructionOrThrow {
getReference<MethodReference>()?.toString() == "Landroid/text/SpannableString;->valueOf(Ljava/lang/CharSequence;)Landroid/text/SpannableString;"
}
val charSequenceRegister =
getInstruction<FiveRegisterInstruction>(insertIndex).registerC
val conversionContextRegister =
getInstruction<TwoRegisterInstruction>(0).registerA
val replaceReference =
getInstruction<ReferenceInstruction>(insertIndex).reference
if (!SettingsPatch.upward1834) {
return
}
addInstructions(
insertIndex + 1, """
invoke-static {v$conversionContextRegister, v$charSequenceRegister}, $INTEGRATIONS_RYD_CLASS_DESCRIPTOR->onCharSequenceLoaded(Ljava/lang/Object;Ljava/lang/CharSequence;)Ljava/lang/CharSequence;
move-result-object v$charSequenceRegister
invoke-static {v$charSequenceRegister}, $replaceReference
"""
)
removeInstruction(insertIndex)
TextComponentSpecFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val insertIndex = indexOfFirstInstructionOrThrow {
getReference<MethodReference>()?.toString() == "Landroid/text/SpannableString;->valueOf(Ljava/lang/CharSequence;)Landroid/text/SpannableString;"
}
val charSequenceRegister =
getInstruction<FiveRegisterInstruction>(insertIndex).registerC
val conversionContextRegister =
getInstruction<TwoRegisterInstruction>(0).registerA
val replaceReference =
getInstruction<ReferenceInstruction>(insertIndex).reference
addInstructions(
insertIndex + 1, """
invoke-static {v$conversionContextRegister, v$charSequenceRegister}, $INTEGRATIONS_RYD_CLASS_DESCRIPTOR->onCharSequenceLoaded(Ljava/lang/Object;Ljava/lang/CharSequence;)Ljava/lang/CharSequence;
move-result-object v$charSequenceRegister
invoke-static {v$charSequenceRegister}, $replaceReference
"""
)
removeInstruction(insertIndex)
}
}
}

View File

@ -10,11 +10,11 @@ import app.revanced.patcher.fingerprint.MethodFingerprintResult
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patcher.util.proxy.mutableTypes.MutableClass
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
import app.revanced.patcher.util.smali.toInstructions
import app.revanced.patches.shared.fingerprints.MdxPlayerDirectorSetVideoStageFingerprint
import app.revanced.patches.shared.fingerprints.VideoLengthFingerprint
import app.revanced.patches.youtube.utils.PlayerResponseModelUtils.PLAYER_RESPONSE_MODEL_CLASS_DESCRIPTOR
import app.revanced.patches.youtube.utils.PlayerResponseModelUtils.indexOfPlayerResponseModelInstruction
import app.revanced.patches.youtube.utils.fingerprints.VideoEndFingerprint
@ -31,13 +31,12 @@ import app.revanced.patches.youtube.video.information.fingerprints.SeekRelativeF
import app.revanced.patches.youtube.video.information.fingerprints.VideoIdFingerprint
import app.revanced.patches.youtube.video.information.fingerprints.VideoIdFingerprintBackgroundPlay
import app.revanced.patches.youtube.video.information.fingerprints.VideoIdFingerprintShorts
import app.revanced.patches.shared.fingerprints.VideoLengthFingerprint
import app.revanced.patches.youtube.video.information.fingerprints.VideoQualityListFingerprint
import app.revanced.patches.youtube.video.information.fingerprints.VideoQualityTextFingerprint
import app.revanced.patches.youtube.video.information.fingerprints.VideoTitleFingerprint
import app.revanced.patches.youtube.video.playerresponse.PlayerResponseMethodHookPatch
import app.revanced.patches.youtube.video.videoid.VideoIdPatch
import app.revanced.util.addFieldAndInstructions
import app.revanced.util.addStaticFieldToIntegration
import app.revanced.util.alsoResolve
import app.revanced.util.getReference
import app.revanced.util.getWalkerMethod
@ -121,7 +120,6 @@ object VideoInformationPatch : BytecodePatch(
private var seekSourceMethodName = ""
private var seekRelativeSourceMethodName = ""
private lateinit var videoInformationMutableClass: MutableClass
private lateinit var context: BytecodeContext
private lateinit var playerConstructorMethod: MutableMethod
@ -179,21 +177,18 @@ object VideoInformationPatch : BytecodePatch(
return v0
"""
videoInformationMutableClass.addFieldAndInstructions(
context,
context.addStaticFieldToIntegration(
INTEGRATIONS_CLASS_DESCRIPTOR,
methodName,
fieldName,
definingClass,
smaliInstructions,
true
smaliInstructions
)
}
}
override fun execute(context: BytecodeContext) {
this.context = context
videoInformationMutableClass =
context.findClass(INTEGRATIONS_CLASS_DESCRIPTOR)!!.mutableClass
VideoEndFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
@ -449,8 +444,8 @@ object VideoInformationPatch : BytecodePatch(
return-void
"""
videoInformationMutableClass.addFieldAndInstructions(
context,
context.addStaticFieldToIntegration(
INTEGRATIONS_CLASS_DESCRIPTOR,
"overridePlaybackSpeed",
"playbackSpeedClass",
playbackSpeedClass,
@ -490,13 +485,12 @@ object VideoInformationPatch : BytecodePatch(
return-void
"""
videoInformationMutableClass.addFieldAndInstructions(
context,
context.addStaticFieldToIntegration(
INTEGRATIONS_CLASS_DESCRIPTOR,
"overrideVideoQuality",
"videoQualityClass",
videoQualityClass,
smaliInstructions,
true
smaliInstructions
)
}

View File

@ -470,87 +470,102 @@ fun MethodFingerprintResult.getWalkerMethod(context: BytecodeContext, offset: In
*/
fun MutableMethod.getWalkerMethod(context: BytecodeContext, offset: Int): MutableMethod {
val newMethod = getInstruction<ReferenceInstruction>(offset).reference as MethodReference
return context.findClass { classDef -> classDef.type == newMethod.definingClass }
?.mutableClass
?.methods
?.first { method -> MethodUtil.methodSignaturesMatch(method, newMethod) }
?: throw PatchException("This method can not be walked at offset $offset inside the method $name")
return context.findMethodOrThrow(newMethod.definingClass) {
MethodUtil.methodSignaturesMatch(this, newMethod)
}
}
fun MutableClass.addFieldAndInstructions(
context: BytecodeContext,
fun BytecodeContext.addStaticFieldToIntegration(
className: String,
methodName: String,
fieldName: String,
objectClass: String,
smaliInstructions: String,
shouldAddConstructor: Boolean
shouldAddConstructor: Boolean = true
) {
val objectCall = "$this->$fieldName:$objectClass"
val mutableClass = findClass { classDef -> classDef.type == className }
?.mutableClass
?: throw PatchException("No matching classes found: $className")
methods.single { method -> method.name == methodName }.apply {
staticFields.add(
ImmutableField(
definingClass,
fieldName,
objectClass,
AccessFlags.PUBLIC or AccessFlags.STATIC,
null,
annotations,
null
).toMutable()
)
val objectCall = "$mutableClass->$fieldName:$objectClass"
addInstructionsWithLabels(
0,
"""
mutableClass.apply {
methods.first { method -> method.name == methodName }.apply {
staticFields.add(
ImmutableField(
definingClass,
fieldName,
objectClass,
AccessFlags.PUBLIC or AccessFlags.STATIC,
null,
annotations,
null
).toMutable()
)
addInstructionsWithLabels(
0,
"""
sget-object v0, $objectCall
""" + smaliInstructions
)
)
}
}
if (shouldAddConstructor) {
context.findClass(objectClass)!!.mutableClass.methods
.filter { method -> method.name == "<init>" }
.forEach { mutableMethod ->
mutableMethod.apply {
val initializeIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.INVOKE_DIRECT && getReference<MethodReference>()?.name == "<init>"
}
val insertIndex = if (initializeIndex == -1)
1
else
initializeIndex + 1
if (!shouldAddConstructor) return
val initializeRegister = if (initializeIndex == -1)
"p0"
else
"v${getInstruction<FiveRegisterInstruction>(initializeIndex).registerC}"
addInstruction(
insertIndex,
"sput-object $initializeRegister, $objectCall"
)
findMethodsOrThrow(objectClass)
.filter { method -> MethodUtil.isConstructor(method) }
.forEach { mutableMethod ->
mutableMethod.apply {
val initializeIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.INVOKE_DIRECT &&
getReference<MethodReference>()?.name == "<init>"
}
val insertIndex = if (initializeIndex == -1)
1
else
initializeIndex + 1
val initializeRegister = if (initializeIndex == -1)
"p0"
else
"v${getInstruction<FiveRegisterInstruction>(initializeIndex).registerC}"
addInstruction(
insertIndex,
"sput-object $initializeRegister, $objectCall"
)
}
}
}
fun BytecodeContext.findMethodOrThrow(
reference: String,
methodPredicate: Method.() -> Boolean = { MethodUtil.isConstructor(this) }
) = findMethodsOrThrow(reference).first(methodPredicate)
fun BytecodeContext.findMethodsOrThrow(reference: String): MutableSet<MutableMethod> {
val methods =
findClass { classDef -> classDef.type == reference }
?.mutableClass
?.methods
if (methods != null) {
return methods
} else {
throw PatchException("No matching methods found in: $reference")
}
}
fun BytecodeContext.updatePatchStatus(
className: String,
methodName: String
) {
this.classes.forEach { classDef ->
if (classDef.type.endsWith(className)) {
val patchStatusMethod =
this.proxy(classDef).mutableClass.methods.first { it.name == methodName }
patchStatusMethod.replaceInstruction(
0,
"const/4 v0, 0x1"
)
}
}
}
) = findMethodOrThrow(className) { name == methodName }
.replaceInstruction(
0,
"const/4 v0, 0x1"
)
/**
* Return the resolved methods of [MethodFingerprint]s early.
@ -571,7 +586,7 @@ fun List<MethodFingerprint>.returnEarly(bool: Boolean = false) {
return v0
"""
else -> throw Exception("This case should never happen.")
else -> throw PatchException("This case should never happen: ${fingerprint.javaClass.simpleName}")
}
result.mutableMethod.addInstructions(0, stringInstructions)