From 8c603802f795716542f58eaa469e607ec2695ac8 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Wed, 26 Nov 2025 23:12:48 +0100 Subject: [PATCH] fix: Adjusting to new API --- .../TransformInstructionsPatch.kt | 38 ++--------- .../patches/crunchyroll/ads/HideAdsPatch.kt | 2 +- .../duolingo/debug/EnableDebugMenuPatch.kt | 2 +- .../energy/SkipEnergyRechargeAdsPatch.kt | 2 +- .../instagram/hide/explore/HideExploreFeed.kt | 2 +- .../instagram/hide/stories/HideStories.kt | 2 +- .../misc/devmenu/EnableDeveloperMenuPatch.kt | 2 +- .../misc/share/EditShareLinksPatch.kt | 2 +- .../messenger/metaai/RemoveMetaAIPatch.kt | 4 +- .../music/layout/buttons/HideButtons.kt | 2 +- .../layout/compactheader/HideCategoryBar.kt | 2 +- .../navigationbar/NavigationBarPatch.kt | 2 +- .../revanced/patches/nunl/ads/HideAdsPatch.kt | 2 +- .../patches/primevideo/ads/SkipAdsPatch.kt | 2 +- .../baconreader/api/SpoofClientPatch.kt | 2 +- .../boostforreddit/api/SpoofClientPatch.kt | 2 +- .../redditisfun/api/SpoofClientPatch.kt | 2 +- .../layout/theme/LithoColorHookPatch.kt | 2 +- .../shared/misc/gms/GmsCoreSupportPatch.kt | 48 +++++++------ .../misc/mapping/ResourceMappingPatch.kt | 10 ++- .../misc/spoof/SpoofVideoStreamsPatch.kt | 2 +- .../patches/viber/ads/HideAdsPatch.kt | 2 +- .../youtube/ad/general/HideAdsPatch.kt | 49 ++++---------- .../branding/header/ChangeHeaderPatch.kt | 43 +++++++----- .../hide/general/HideLayoutComponentsPatch.kt | 19 ++---- .../hide/shorts/HideShortsComponentsPatch.kt | 31 ++++----- .../BackgroundPlaybackPatch.kt | 3 +- .../FixBackToExitGesturePatch.kt | 2 +- ...t => FixPlaybackSpeedWhilePlayingPatch.kt} | 4 +- .../youtube/misc/navigation/Fingerprints.kt | 7 +- .../misc/navigation/NavigationBarHookPatch.kt | 42 +++++------- .../kotlin/app/revanced/util/BytecodeUtils.kt | 67 ++++++++++--------- 32 files changed, 175 insertions(+), 228 deletions(-) rename patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playbackspeed/{FIxPlaybackSpeedWhilePlayingPatch.kt => FixPlaybackSpeedWhilePlayingPatch.kt} (97%) diff --git a/patches/src/main/kotlin/app/revanced/patches/all/misc/transformation/TransformInstructionsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/all/misc/transformation/TransformInstructionsPatch.kt index 520e49699..67b65dffd 100644 --- a/patches/src/main/kotlin/app/revanced/patches/all/misc/transformation/TransformInstructionsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/all/misc/transformation/TransformInstructionsPatch.kt @@ -1,8 +1,8 @@ package app.revanced.patches.all.misc.transformation -import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.dex.mutable.MutableMethod -import app.revanced.util.findMutableMethodOf +import app.revanced.patcher.patch.bytecodePatch +import app.revanced.util.forEachInstructionAsSequence import com.android.tools.smali.dexlib2.iface.ClassDef import com.android.tools.smali.dexlib2.iface.Method import com.android.tools.smali.dexlib2.iface.instruction.Instruction @@ -11,39 +11,9 @@ fun transformInstructionsPatch( filterMap: (ClassDef, Method, Instruction, Int) -> T?, transform: (MutableMethod, T) -> Unit, ) = bytecodePatch { - // Returns the patch indices as a Sequence, which will execute lazily. - fun findPatchIndices(classDef: ClassDef, method: Method): Sequence? = - method.implementation?.instructions?.asSequence()?.withIndex()?.mapNotNull { (index, instruction) -> - filterMap(classDef, method, instruction, index) - } - execute { - // Find all methods to patch - buildMap { - classDefs.forEach { classDef -> - val methods = buildList { - classDef.methods.forEach { method -> - // Since the Sequence executes lazily, - // using any() results in only calling - // filterMap until the first index has been found. - if (findPatchIndices(classDef, method)?.any() == true) add(method) - } - } - - if (methods.isNotEmpty()) { - put(classDef, methods) - } - } - }.forEach { (classDef, methods) -> - // And finally transform the methods... - val mutableClass = classDef.mutable() - - methods.map(mutableClass::findMutableMethodOf).forEach methods@{ mutableMethod -> - val patchIndices = findPatchIndices(mutableClass, mutableMethod)?.toCollection(ArrayDeque()) - ?: return@methods - - while (!patchIndices.isEmpty()) transform(mutableMethod, patchIndices.removeLast()) - } + forEachInstructionAsSequence { classDef, method, i, instruction -> + transform(method, filterMap(classDef, method, instruction, i) ?: return@forEachInstructionAsSequence) } } } diff --git a/patches/src/main/kotlin/app/revanced/patches/crunchyroll/ads/HideAdsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/crunchyroll/ads/HideAdsPatch.kt index 5ce3bc7d2..50773f29f 100644 --- a/patches/src/main/kotlin/app/revanced/patches/crunchyroll/ads/HideAdsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/crunchyroll/ads/HideAdsPatch.kt @@ -21,7 +21,7 @@ val hideAdsPatch = bytecodePatch( execute { // Get obfuscated "enableAds" field from toString method. val enableAdsField = videoUrlReadyToStringFingerprint.let { - val strIndex = videoUrlReadyToStringFingerprint.stringMatches!!.last().index + val strIndex = videoUrlReadyToStringFingerprint.stringMatches.last().index val fieldIndex = it.method.indexOfFirstInstruction(strIndex, Opcode.IGET_BOOLEAN) it.method.getInstruction(fieldIndex).getReference()!! } diff --git a/patches/src/main/kotlin/app/revanced/patches/duolingo/debug/EnableDebugMenuPatch.kt b/patches/src/main/kotlin/app/revanced/patches/duolingo/debug/EnableDebugMenuPatch.kt index 7b58e8a48..4c9edc744 100644 --- a/patches/src/main/kotlin/app/revanced/patches/duolingo/debug/EnableDebugMenuPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/duolingo/debug/EnableDebugMenuPatch.kt @@ -21,7 +21,7 @@ val enableDebugMenuPatch = bytecodePatch( buildConfigProviderConstructorFingerprint.match( buildConfigProviderToStringFingerprint.classDef ).let { - val index = it.patternMatch!!.startIndex + val index = it.patternMatch.startIndex it.method.apply { val register = getInstruction(index).registerA diff --git a/patches/src/main/kotlin/app/revanced/patches/duolingo/energy/SkipEnergyRechargeAdsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/duolingo/energy/SkipEnergyRechargeAdsPatch.kt index 64e872baf..397350454 100644 --- a/patches/src/main/kotlin/app/revanced/patches/duolingo/energy/SkipEnergyRechargeAdsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/duolingo/energy/SkipEnergyRechargeAdsPatch.kt @@ -17,7 +17,7 @@ val skipEnergyRechargeAdsPatch = bytecodePatch( .method.apply { val energyField = energyConfigToStringFingerprint.method .findFieldFromToString("energy=") - val insertIndex = initializeEnergyConfigFingerprint.patternMatch!!.startIndex + val insertIndex = initializeEnergyConfigFingerprint.patternMatch.startIndex addInstructions( insertIndex, diff --git a/patches/src/main/kotlin/app/revanced/patches/instagram/hide/explore/HideExploreFeed.kt b/patches/src/main/kotlin/app/revanced/patches/instagram/hide/explore/HideExploreFeed.kt index 0ddf803cb..c0a35c694 100644 --- a/patches/src/main/kotlin/app/revanced/patches/instagram/hide/explore/HideExploreFeed.kt +++ b/patches/src/main/kotlin/app/revanced/patches/instagram/hide/explore/HideExploreFeed.kt @@ -11,7 +11,7 @@ context(BytecodePatchContext) internal fun Fingerprint.replaceJsonFieldWithBogus( key: String, ) { - val targetStringIndex = stringMatches!!.first { match -> match.string == key }.index + val targetStringIndex = stringMatches.first { match -> match.string == key }.index val targetStringRegister = method.getInstruction(targetStringIndex).registerA /** diff --git a/patches/src/main/kotlin/app/revanced/patches/instagram/hide/stories/HideStories.kt b/patches/src/main/kotlin/app/revanced/patches/instagram/hide/stories/HideStories.kt index b699b2c59..2647ee4f7 100644 --- a/patches/src/main/kotlin/app/revanced/patches/instagram/hide/stories/HideStories.kt +++ b/patches/src/main/kotlin/app/revanced/patches/instagram/hide/stories/HideStories.kt @@ -12,7 +12,7 @@ val hideStoriesPatch = bytecodePatch( execute { val addStoryMethod = getOrCreateAvatarViewFingerprint.method // Creates Story - val addStoryEndIndex = getOrCreateAvatarViewFingerprint.patternMatch!!.endIndex + val addStoryEndIndex = getOrCreateAvatarViewFingerprint.patternMatch.endIndex // Remove addView of Story. addStoryMethod.removeInstruction(addStoryEndIndex) diff --git a/patches/src/main/kotlin/app/revanced/patches/instagram/misc/devmenu/EnableDeveloperMenuPatch.kt b/patches/src/main/kotlin/app/revanced/patches/instagram/misc/devmenu/EnableDeveloperMenuPatch.kt index e9577477a..a43b3e9f7 100644 --- a/patches/src/main/kotlin/app/revanced/patches/instagram/misc/devmenu/EnableDeveloperMenuPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/instagram/misc/devmenu/EnableDeveloperMenuPatch.kt @@ -22,7 +22,7 @@ val enableDeveloperMenuPatch = bytecodePatch( execute { with(clearNotificationReceiverFingerprint.method) { - indexOfFirstInstructionReversedOrThrow(clearNotificationReceiverFingerprint.stringMatches!!.first().index) { + indexOfFirstInstructionReversedOrThrow(clearNotificationReceiverFingerprint.stringMatches.first().index) { val reference = getReference() opcode in listOf(Opcode.INVOKE_STATIC, Opcode.INVOKE_STATIC_RANGE) && reference?.parameterTypes?.size == 1 && diff --git a/patches/src/main/kotlin/app/revanced/patches/instagram/misc/share/EditShareLinksPatch.kt b/patches/src/main/kotlin/app/revanced/patches/instagram/misc/share/EditShareLinksPatch.kt index e8df4c7aa..3817c2c31 100644 --- a/patches/src/main/kotlin/app/revanced/patches/instagram/misc/share/EditShareLinksPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/instagram/misc/share/EditShareLinksPatch.kt @@ -19,7 +19,7 @@ internal fun editShareLinksPatch(block: MutableMethod.(index: Int, register: Int for (fingerprint in fingerprintsToPatch) { fingerprint.method.apply { val putSharingUrlIndex = indexOfFirstInstruction( - permalinkResponseJsonParserFingerprint.stringMatches!!.first().index, + permalinkResponseJsonParserFingerprint.stringMatches.first().index, Opcode.IPUT_OBJECT ) diff --git a/patches/src/main/kotlin/app/revanced/patches/messenger/metaai/RemoveMetaAIPatch.kt b/patches/src/main/kotlin/app/revanced/patches/messenger/metaai/RemoveMetaAIPatch.kt index 155c8c4cb..ed4bf770c 100644 --- a/patches/src/main/kotlin/app/revanced/patches/messenger/metaai/RemoveMetaAIPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/messenger/metaai/RemoveMetaAIPatch.kt @@ -22,7 +22,7 @@ val removeMetaAIPatch = bytecodePatch( execute { getMobileConfigBoolFingerprint.method.apply { - val returnIndex = getMobileConfigBoolFingerprint.patternMatch!!.startIndex + val returnIndex = getMobileConfigBoolFingerprint.patternMatch.startIndex val returnRegister = getInstruction(returnIndex).registerA addInstructions( @@ -42,7 +42,7 @@ val removeMetaAIPatch = bytecodePatch( // Replace placeholder in the extension method. with(extensionMethodFingerprint) { method.replaceInstruction( - stringMatches!!.first().index, + stringMatches.first().index, """ const-string v1, "$relevantDigits" """ diff --git a/patches/src/main/kotlin/app/revanced/patches/music/layout/buttons/HideButtons.kt b/patches/src/main/kotlin/app/revanced/patches/music/layout/buttons/HideButtons.kt index 92b9378ba..2a71bd912 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/layout/buttons/HideButtons.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/layout/buttons/HideButtons.kt @@ -73,7 +73,7 @@ val hideButtons = bytecodePatch( historyMenuItemOfflineTabFingerprint ).forEach { fingerprint -> fingerprint.method.apply { - val targetIndex = fingerprint.patternMatch!!.startIndex + val targetIndex = fingerprint.patternMatch.startIndex val targetRegister = getInstruction(targetIndex).registerD addInstructions( diff --git a/patches/src/main/kotlin/app/revanced/patches/music/layout/compactheader/HideCategoryBar.kt b/patches/src/main/kotlin/app/revanced/patches/music/layout/compactheader/HideCategoryBar.kt index 4874e80db..345a17f4d 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/layout/compactheader/HideCategoryBar.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/layout/compactheader/HideCategoryBar.kt @@ -46,7 +46,7 @@ val hideCategoryBar = bytecodePatch( chipCloud = getResourceId(ResourceType.LAYOUT, "chip_cloud") chipCloudFingerprint.method.apply { - val targetIndex = chipCloudFingerprint.patternMatch!!.endIndex + val targetIndex = chipCloudFingerprint.patternMatch.endIndex val targetRegister = getInstruction(targetIndex).registerA addInstruction( diff --git a/patches/src/main/kotlin/app/revanced/patches/music/layout/navigationbar/NavigationBarPatch.kt b/patches/src/main/kotlin/app/revanced/patches/music/layout/navigationbar/NavigationBarPatch.kt index c690183e8..e2fc4ec1e 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/layout/navigationbar/NavigationBarPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/layout/navigationbar/NavigationBarPatch.kt @@ -100,7 +100,7 @@ val navigationBarPatch = bytecodePatch( ) // Set navigation enum and hide navigation buttons. - val enumIndex = tabLayoutTextFingerprint.patternMatch!!.startIndex + 3 + val enumIndex = tabLayoutTextFingerprint.patternMatch.startIndex + 3 val enumRegister = getInstruction(enumIndex).registerA val insertEnumIndex = indexOfFirstInstructionOrThrow(Opcode.AND_INT_LIT8) - 2 diff --git a/patches/src/main/kotlin/app/revanced/patches/nunl/ads/HideAdsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/nunl/ads/HideAdsPatch.kt index a58845cea..1908b3a28 100644 --- a/patches/src/main/kotlin/app/revanced/patches/nunl/ads/HideAdsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/nunl/ads/HideAdsPatch.kt @@ -27,7 +27,7 @@ val hideAdsPatch = bytecodePatch( // Filter injected content from API calls out of lists. arrayOf(screenMapperFingerprint, nextPageRepositoryImplFingerprint).forEach { // Index of instruction moving result of BlockPage;->getBlocks(...). - val moveGetBlocksResultObjectIndex = it.patternMatch!!.startIndex + val moveGetBlocksResultObjectIndex = it.patternMatch.startIndex it.method.apply { val moveInstruction = getInstruction(moveGetBlocksResultObjectIndex) diff --git a/patches/src/main/kotlin/app/revanced/patches/primevideo/ads/SkipAdsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/primevideo/ads/SkipAdsPatch.kt index e295e7a54..6c364c79e 100644 --- a/patches/src/main/kotlin/app/revanced/patches/primevideo/ads/SkipAdsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/primevideo/ads/SkipAdsPatch.kt @@ -22,7 +22,7 @@ val skipAdsPatch = bytecodePatch( // Force doTrigger() access to public so we can call it from our extension. doTriggerFingerprint.method.accessFlags = AccessFlags.PUBLIC.value; - val getPlayerIndex = enterServerInsertedAdBreakStateFingerprint.patternMatch!!.startIndex + val getPlayerIndex = enterServerInsertedAdBreakStateFingerprint.patternMatch.startIndex enterServerInsertedAdBreakStateFingerprint.method.apply { // Get register that stores VideoPlayer: // invoke-virtual ->getPrimaryPlayer() diff --git a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/baconreader/api/SpoofClientPatch.kt b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/baconreader/api/SpoofClientPatch.kt index 85062f414..0e98f5295 100644 --- a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/baconreader/api/SpoofClientPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/baconreader/api/SpoofClientPatch.kt @@ -23,7 +23,7 @@ val spoofClientPatch = spoofClientPatch(redirectUri = "http://baconreader.com/au execute { fun Fingerprint.patch(replacementString: String) { - val clientIdIndex = stringMatches!!.first().index + val clientIdIndex = stringMatches.first().index method.apply { val clientIdRegister = getInstruction(clientIdIndex).registerA diff --git a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/api/SpoofClientPatch.kt b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/api/SpoofClientPatch.kt index 392490411..b4046aed0 100644 --- a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/api/SpoofClientPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/api/SpoofClientPatch.kt @@ -24,7 +24,7 @@ val spoofClientPatch = spoofClientPatch(redirectUri = "http://rubenmayayo.com") val randomName = (0..100000).random() val userAgent = "$randomName:app.revanced.$randomName:v1.0.0 (by /u/revanced)" buildUserAgentFingerprint.let { - val userAgentTemplateIndex = it.stringMatches!!.first().index + val userAgentTemplateIndex = it.stringMatches.first().index val register = it.method.getInstruction(userAgentTemplateIndex).registerA it.method.replaceInstruction(userAgentTemplateIndex, "const-string v$register, \"$userAgent\"") diff --git a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/redditisfun/api/SpoofClientPatch.kt b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/redditisfun/api/SpoofClientPatch.kt index ae0bc647c..8cb7a226b 100644 --- a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/redditisfun/api/SpoofClientPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/redditisfun/api/SpoofClientPatch.kt @@ -34,7 +34,7 @@ val spoofClientPatch = spoofClientPatch(redirectUri = "redditisfun://auth") { cl string: String, getReplacementIndex: List.() -> Int, ) = method.apply { - val replacementIndex = stringMatches!!.getReplacementIndex() + val replacementIndex = stringMatches.getReplacementIndex() val clientIdRegister = getInstruction(replacementIndex).registerA replaceInstruction(replacementIndex, "const-string v$clientIdRegister, \"$string\"") diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/layout/theme/LithoColorHookPatch.kt b/patches/src/main/kotlin/app/revanced/patches/shared/layout/theme/LithoColorHookPatch.kt index ca1584dd6..7518776ca 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/layout/theme/LithoColorHookPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/layout/theme/LithoColorHookPatch.kt @@ -11,7 +11,7 @@ val lithoColorHookPatch = bytecodePatch( ) { execute { - var insertionIndex = lithoOnBoundsChangeFingerprint.patternMatch!!.endIndex - 1 + var insertionIndex = lithoOnBoundsChangeFingerprint.patternMatch.endIndex - 1 lithoColorOverrideHook = { targetMethodClass, targetMethodName -> lithoOnBoundsChangeFingerprint.method.addInstructions( diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/misc/gms/GmsCoreSupportPatch.kt b/patches/src/main/kotlin/app/revanced/patches/shared/misc/gms/GmsCoreSupportPatch.kt index ad15f314c..bf0a8b2cc 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/misc/gms/GmsCoreSupportPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/misc/gms/GmsCoreSupportPatch.kt @@ -79,33 +79,41 @@ fun gmsCoreSupportPatch( val gmsCoreVendorGroupId by gmsCoreVendorGroupIdOption execute { - fun transformStringReferences(transform: (str: String) -> String?) = classDefs.forEach { - val mutableClass by lazy { it.mutable() } + fun transformStringReferences(transform: (str: String) -> String?) { + val transformations = mutableListOf<() -> Unit>() - it.methods.forEach classLoop@{ method -> - val implementation = method.implementation ?: return@classLoop + classDefs.forEach { classDef -> + val mutableClass by lazy { classDef.mutable() } - val mutableMethod by lazy { - mutableClass.methods.first { MethodUtil.methodSignaturesMatch(it, method) } - } + classDef.methods.forEach classLoop@{ method -> + val implementation = method.implementation ?: return@classLoop - implementation.instructions.forEachIndexed { index, instruction -> - val string = ((instruction as? Instruction21c)?.reference as? StringReference)?.string - ?: return@forEachIndexed + val mutableMethod by lazy { + mutableClass.methods.first { MethodUtil.methodSignaturesMatch(it, method) } + } - // Apply transformation. - val transformedString = transform(string) ?: return@forEachIndexed + implementation.instructions.forEachIndexed { index, instruction -> + val string = ((instruction as? Instruction21c)?.reference as? StringReference)?.string + ?: return@forEachIndexed - mutableMethod.replaceInstruction( - index, - BuilderInstruction21c( - Opcode.CONST_STRING, - instruction.registerA, - ImmutableStringReference(transformedString), - ), - ) + // Apply transformation. + val transformedString = transform(string) ?: return@forEachIndexed + + transformations += { + mutableMethod.replaceInstruction( + index, + BuilderInstruction21c( + Opcode.CONST_STRING, + instruction.registerA, + ImmutableStringReference(transformedString), + ), + ) + } + } } } + + transformations.forEach { it() } } // region Collection of transformations that are applied to all strings. diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/misc/mapping/ResourceMappingPatch.kt b/patches/src/main/kotlin/app/revanced/patches/shared/misc/mapping/ResourceMappingPatch.kt index 16b7f6fcc..bea541c7c 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/misc/mapping/ResourceMappingPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/misc/mapping/ResourceMappingPatch.kt @@ -2,11 +2,13 @@ package app.revanced.patches.shared.misc.mapping import app.revanced.patcher.InstructionLocation import app.revanced.patcher.LiteralFilter +import app.revanced.patcher.extensions.wideLiteral import app.revanced.patcher.literal import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.resourcePatch +import com.android.tools.smali.dexlib2.iface.instruction.Instruction import org.w3c.dom.Element -import java.util.Collections +import java.util.* enum class ResourceType(val value: String) { ANIM("anim"), @@ -35,6 +37,9 @@ enum class ResourceType(val value: String) { VALUES("values"), XML("xml"); + operator fun invoke(name: String): Instruction.() -> Boolean = + getResourceId(this, name).let { { wideLiteral(it) } } + companion object { private val VALUE_MAP: Map = entries.associateBy { it.value } @@ -77,10 +82,9 @@ fun hasResourceId(type: ResourceType, name: String) = resourceMappings[type.valu fun resourceLiteral( type: ResourceType, name: String, - location : InstructionLocation = InstructionLocation.MatchAfterAnywhere() + location: InstructionLocation = InstructionLocation.MatchAfterAnywhere() ) = literal({ getResourceId(type, name) }, null, location) - val resourceMappingPatch = resourcePatch { execute { // Use a stream of the file, since no modifications are done diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/misc/spoof/SpoofVideoStreamsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/shared/misc/spoof/SpoofVideoStreamsPatch.kt index 3dd5e9dd2..d902e0b35 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/misc/spoof/SpoofVideoStreamsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/misc/spoof/SpoofVideoStreamsPatch.kt @@ -283,7 +283,7 @@ internal fun spoofVideoStreamsPatch( // If SABR is disabled, it seems 'MediaFetchHotConfig' may no longer need an override (not confirmed). val (mediaFetchEnumClass, sabrFieldReference) = with(mediaFetchEnumConstructorFingerprint.method) { - val stringIndex = mediaFetchEnumConstructorFingerprint.stringMatches!!.first { + val stringIndex = mediaFetchEnumConstructorFingerprint.stringMatches.first { it.string == DISABLED_BY_SABR_STREAMING_URI_STRING }.index diff --git a/patches/src/main/kotlin/app/revanced/patches/viber/ads/HideAdsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/viber/ads/HideAdsPatch.kt index 7c5b7ea7c..5e02955b8 100644 --- a/patches/src/main/kotlin/app/revanced/patches/viber/ads/HideAdsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/viber/ads/HideAdsPatch.kt @@ -20,7 +20,7 @@ val hideAdsPatch = bytecodePatch( val method = findAdStringFingerprint.method // Find the ads free string index - val stringIndex = findAdStringFingerprint.stringMatches!!.first().index + val stringIndex = findAdStringFingerprint.stringMatches.first().index // Search backwards from the string to find the `new-instance` (TypeReference) instruction val typeRefIndex = method.indexOfFirstInstructionReversedOrThrow(stringIndex) { this.opcode == Opcode.NEW_INSTANCE } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/ad/general/HideAdsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/ad/general/HideAdsPatch.kt index f7cd5efa4..23165780d 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/ad/general/HideAdsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/ad/general/HideAdsPatch.kt @@ -1,7 +1,9 @@ package app.revanced.patches.youtube.ad.general import app.revanced.patcher.extensions.getInstruction +import app.revanced.patcher.extensions.instructions import app.revanced.patcher.extensions.replaceInstruction +import app.revanced.patcher.extensions.wideLiteral import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.resourcePatch import app.revanced.patches.all.misc.resources.addResources @@ -17,12 +19,10 @@ import app.revanced.patches.youtube.misc.litho.filter.addLithoFilter import app.revanced.patches.youtube.misc.litho.filter.lithoFilterPatch import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.settingsPatch -import app.revanced.util.findMutableMethodOf +import app.revanced.util.forEachInstructionAsSequence import app.revanced.util.injectHideViewCall import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction -import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction31i -import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c internal var adAttributionId = -1L private set @@ -84,7 +84,7 @@ val hideAdsPatch = bytecodePatch( ) execute { - // Hide end screen store banner + // Hide end screen store banner. fullScreenEngagementAdContainerFingerprint.method.apply { val addListIndex = indexOfAddListInstruction(this) @@ -99,42 +99,19 @@ val hideAdsPatch = bytecodePatch( ) } - // Hide ad views + // Hide ad views. - classDefs.forEach { classDef -> - classDef.methods.forEach { method -> - with(method.implementation) { - this?.instructions?.forEachIndexed { index, instruction -> - if (instruction.opcode != Opcode.CONST) { - return@forEachIndexed - } - // Instruction to store the id adAttribution into a register - if ((instruction as Instruction31i).wideLiteral != adAttributionId) { - return@forEachIndexed - } + forEachInstructionAsSequence { _, method, index, instruction -> + if (instruction.opcode != Opcode.CONST) return@forEachInstructionAsSequence + if (instruction.wideLiteral != adAttributionId) return@forEachInstructionAsSequence - val insertIndex = index + 1 - // Call to get the view with the id adAttribution - with(instructions.elementAt(insertIndex)) { - if (opcode != Opcode.INVOKE_VIRTUAL) { - return@forEachIndexed - } + val insertIndex = index + 1 - // Hide the view - val viewRegister = (this as Instruction35c).registerC - classDef.mutable() - .findMutableMethodOf(method) - .injectHideViewCall( - insertIndex, - viewRegister, - EXTENSION_CLASS_DESCRIPTOR, - "hideAdAttributionView", - ) - } - } - } - } + // Call to get the view with the id adAttribution, + if (method.instructions[insertIndex].opcode != Opcode.INVOKE_VIRTUAL) return@forEachInstructionAsSequence + val viewRegister = method.getInstruction(insertIndex).registerC + method.injectHideViewCall(insertIndex, viewRegister, EXTENSION_CLASS_DESCRIPTOR, "hideAdAttributionView") } } } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/branding/header/ChangeHeaderPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/branding/header/ChangeHeaderPatch.kt index 05ab9a3d5..e7600187e 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/branding/header/ChangeHeaderPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/branding/header/ChangeHeaderPatch.kt @@ -2,6 +2,7 @@ package app.revanced.patches.youtube.layout.branding.header import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.getInstruction +import app.revanced.patcher.extensions.wideLiteral import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.resourcePatch @@ -19,7 +20,7 @@ import app.revanced.util.ResourceGroup import app.revanced.util.Utils.trimIndentMultiline import app.revanced.util.copyResources import app.revanced.util.findElementByAttributeValueOrThrow -import app.revanced.util.forEachLiteralValueInstruction +import app.revanced.util.forEachInstructionAsSequence import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import java.io.File @@ -75,12 +76,14 @@ private val changeHeaderBytecodePatch = bytecodePatch { "ytWordmarkHeader", "ytPremiumWordmarkHeader" ).forEach { resourceName -> - val resourceId = getResourceId(ResourceType.ATTR, resourceName) + val id = getResourceId(ResourceType.ATTR, resourceName) - forEachLiteralValueInstruction(resourceId) { literalIndex -> - val register = getInstruction(literalIndex).registerA - addInstructions( - literalIndex + 1, + forEachInstructionAsSequence { _, method, i, instruction -> + if (instruction.wideLiteral != id) return@forEachInstructionAsSequence + + val register = method.getInstruction(i).registerA + method.addInstructions( + i + 1, """ invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->getHeaderAttributeId(I)I move-result v$register @@ -214,21 +217,24 @@ val changeHeaderPatch = resourcePatch( if (custom != null) { val customFile = File(custom!!.trim()) if (!customFile.exists()) { - throw PatchException("The custom header path cannot be found: " + - customFile.absolutePath + throw PatchException( + "The custom header path cannot be found: " + + customFile.absolutePath ) } if (!customFile.isDirectory) { - throw PatchException("The custom header path must be a folder: " - + customFile.absolutePath) + throw PatchException( + "The custom header path must be a folder: " + + customFile.absolutePath + ) } var copiedFiles = false // For each source folder, copy the files to the target resource directories. - customFile.listFiles { - file -> file.isDirectory && file.name in targetResourceDirectoryNames + customFile.listFiles { file -> + file.isDirectory && file.name in targetResourceDirectoryNames }!!.forEach { dpiSourceFolder -> val targetDpiFolder = get("res").resolve(dpiSourceFolder.name) if (!targetDpiFolder.exists()) { @@ -241,8 +247,9 @@ val changeHeaderPatch = resourcePatch( }!! if (customFiles.isNotEmpty() && customFiles.size != variants.size) { - throw PatchException("Both light/dark mode images " + - "must be specified but only found: " + customFiles.map { it.name }) + throw PatchException( + "Both light/dark mode images " + + "must be specified but only found: " + customFiles.map { it.name }) } customFiles.forEach { imgSourceFile -> @@ -254,9 +261,11 @@ val changeHeaderPatch = resourcePatch( } if (!copiedFiles) { - throw PatchException("Expected to find directories and files: " - + customHeaderResourceFileNames.contentToString() - + "\nBut none were found in the provided option file path: " + customFile.absolutePath) + throw PatchException( + "Expected to find directories and files: " + + customHeaderResourceFileNames.contentToString() + + "\nBut none were found in the provided option file path: " + customFile.absolutePath + ) } } } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsPatch.kt index e28e50aae..390ae6540 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsPatch.kt @@ -2,26 +2,15 @@ package app.revanced.patches.youtube.layout.hide.general import app.revanced.patcher.Fingerprint import app.revanced.patcher.Match -import app.revanced.patcher.extensions.addInstruction -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.extensions.addInstructionsWithLabels -import app.revanced.patcher.extensions.getInstruction -import app.revanced.patcher.extensions.instructions -import app.revanced.patcher.extensions.removeInstruction -import app.revanced.patcher.extensions.replaceInstruction +import app.revanced.patcher.extensions.* import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.resourcePatch -import app.revanced.patcher.extensions.ExternalLabel import app.revanced.patches.all.misc.resources.addResources import app.revanced.patches.all.misc.resources.addResourcesPatch import app.revanced.patches.shared.misc.mapping.ResourceType import app.revanced.patches.shared.misc.mapping.getResourceId import app.revanced.patches.shared.misc.mapping.resourceMappingPatch -import app.revanced.patches.shared.misc.settings.preference.InputType -import app.revanced.patches.shared.misc.settings.preference.NonInteractivePreference -import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference -import app.revanced.patches.shared.misc.settings.preference.SwitchPreference -import app.revanced.patches.shared.misc.settings.preference.TextPreference +import app.revanced.patches.shared.misc.settings.preference.* import app.revanced.patches.youtube.misc.litho.filter.addLithoFilter import app.revanced.patches.youtube.misc.litho.filter.lithoFilterPatch import app.revanced.patches.youtube.misc.navigation.navigationBarHookPatch @@ -32,13 +21,13 @@ import app.revanced.patches.youtube.misc.settings.settingsPatch import app.revanced.util.findFreeRegister import app.revanced.util.findInstructionIndicesReversedOrThrow import app.revanced.util.getReference +import app.revanced.util.indexOfFirstInstructionReversedOrThrow import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.Method import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction import com.android.tools.smali.dexlib2.iface.reference.MethodReference -import app.revanced.util.indexOfFirstInstructionReversedOrThrow internal var albumCardId = -1L private set @@ -390,7 +379,7 @@ val hideLayoutComponentsPatch = bytecodePatch( // region hide view count hideViewCountFingerprint.method.apply { - val startIndex = hideViewCountFingerprint.patternMatch!!.startIndex + val startIndex = hideViewCountFingerprint.patternMatch.startIndex var returnStringRegister = getInstruction(startIndex).registerA // Find the instruction where the text dimension is retrieved. diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsPatch.kt index c3350642c..f5d17744d 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsPatch.kt @@ -3,6 +3,7 @@ package app.revanced.patches.youtube.layout.hide.shorts import app.revanced.patcher.extensions.addInstruction import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.getInstruction +import app.revanced.patcher.extensions.wideLiteral import app.revanced.patcher.patch.booleanOption import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.resourcePatch @@ -17,19 +18,10 @@ import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch import app.revanced.patches.youtube.misc.litho.filter.addLithoFilter import app.revanced.patches.youtube.misc.litho.filter.lithoFilterPatch import app.revanced.patches.youtube.misc.navigation.navigationBarHookPatch -import app.revanced.patches.youtube.misc.playservice.is_19_41_or_greater -import app.revanced.patches.youtube.misc.playservice.is_20_07_or_greater -import app.revanced.patches.youtube.misc.playservice.is_20_22_or_greater -import app.revanced.patches.youtube.misc.playservice.is_20_45_or_greater -import app.revanced.patches.youtube.misc.playservice.versionCheckPatch +import app.revanced.patches.youtube.misc.playservice.* import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.settingsPatch -import app.revanced.util.findElementByAttributeValueOrThrow -import app.revanced.util.forEachLiteralValueInstruction -import app.revanced.util.getReference -import app.revanced.util.indexOfFirstInstructionOrThrow -import app.revanced.util.removeFromParent -import app.revanced.util.returnLate +import app.revanced.util.* import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.reference.MethodReference import java.util.logging.Logger @@ -194,16 +186,18 @@ val hideShortsComponentsPatch = bytecodePatch( execute { addLithoFilter(FILTER_CLASS_DESCRIPTOR) - forEachLiteralValueInstruction( - getResourceId(ResourceType.DIMEN, "reel_player_right_pivot_v2_size") - ) { literalInstructionIndex -> - val targetIndex = indexOfFirstInstructionOrThrow(literalInstructionIndex) { + val id = getResourceId(ResourceType.DIMEN, "reel_player_right_pivot_v2_size") + + forEachInstructionAsSequence { _, method, i, instruction -> + if (instruction.wideLiteral != id) return@forEachInstructionAsSequence + + val targetIndex = method.indexOfFirstInstructionOrThrow(i) { getReference()?.name == "getDimensionPixelSize" } + 1 - val sizeRegister = getInstruction(targetIndex).registerA + val sizeRegister = method.getInstruction(targetIndex).registerA - addInstructions( + method.addInstructions( targetIndex + 1, """ invoke-static { v$sizeRegister }, $FILTER_CLASS_DESCRIPTOR->getSoundButtonSize(I)I @@ -212,6 +206,7 @@ val hideShortsComponentsPatch = bytecodePatch( ) } + // endregion // region Hide the navigation bar. @@ -226,7 +221,7 @@ val hideShortsComponentsPatch = bytecodePatch( addInstruction( insertIndex, "invoke-static {v$viewRegister}," + - " $FILTER_CLASS_DESCRIPTOR->setNavigationBar(Lcom/google/android/libraries/youtube/rendering/ui/pivotbar/PivotBar;)V", + " $FILTER_CLASS_DESCRIPTOR->setNavigationBar(Lcom/google/android/libraries/youtube/rendering/ui/pivotbar/PivotBar;)V", ) } } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/BackgroundPlaybackPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/BackgroundPlaybackPatch.kt index bcc1d96cd..e36f43322 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/BackgroundPlaybackPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/BackgroundPlaybackPatch.kt @@ -88,7 +88,8 @@ val backgroundPlaybackPatch = bytecodePatch( } val settingsBooleanIndex = booleanCalls.elementAt(1).index - val settingsBooleanMethod by navigate(this).to(settingsBooleanIndex) + + val settingsBooleanMethod = navigate(this).to(settingsBooleanIndex).stop() settingsBooleanMethod.returnEarly(true) } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/backtoexitgesture/FixBackToExitGesturePatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/backtoexitgesture/FixBackToExitGesturePatch.kt index 3a76c547a..45c507763 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/backtoexitgesture/FixBackToExitGesturePatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/backtoexitgesture/FixBackToExitGesturePatch.kt @@ -25,7 +25,7 @@ internal val fixBackToExitGesturePatch = bytecodePatch( scrollPositionFingerprint.let { navigate(it.originalMethod) - .to(it.patternMatch!!.startIndex + 1) + .to(it.patternMatch.startIndex + 1) .stop().apply { val index = indexOfFirstInstructionOrThrow { opcode == Opcode.INVOKE_VIRTUAL && getReference()?.definingClass == diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playbackspeed/FIxPlaybackSpeedWhilePlayingPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playbackspeed/FixPlaybackSpeedWhilePlayingPatch.kt similarity index 97% rename from patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playbackspeed/FIxPlaybackSpeedWhilePlayingPatch.kt rename to patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playbackspeed/FixPlaybackSpeedWhilePlayingPatch.kt index afa3b5319..d7f8dd099 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playbackspeed/FIxPlaybackSpeedWhilePlayingPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playbackspeed/FixPlaybackSpeedWhilePlayingPatch.kt @@ -1,9 +1,9 @@ package app.revanced.patches.youtube.misc.fix.playbackspeed +import app.revanced.patcher.extensions.ExternalLabel import app.revanced.patcher.extensions.addInstructionsWithLabels import app.revanced.patcher.extensions.getInstruction import app.revanced.patcher.patch.bytecodePatch -import app.revanced.patcher.extensions.ExternalLabel import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch import app.revanced.patches.youtube.misc.playertype.playerTypeHookPatch import app.revanced.patches.youtube.misc.playservice.is_19_34_or_greater @@ -29,7 +29,7 @@ private const val EXTENSION_CLASS_DESCRIPTOR = * 6. Resume the video * 7. Playback speed will incorrectly change to 1.0x. */ -val fixPlaybackSpeedWhilePlayingPatch = bytecodePatch{ +val fixPlaybackSpeedWhilePlayingPatch = bytecodePatch { dependsOn( sharedExtensionPatch, playerTypeHookPatch, diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/navigation/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/navigation/Fingerprints.kt index bf6d4f8fc..b10f2ecdc 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/navigation/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/navigation/Fingerprints.kt @@ -1,11 +1,7 @@ package app.revanced.patches.youtube.misc.navigation +import app.revanced.patcher.* import app.revanced.patcher.InstructionLocation.MatchAfterWithin -import app.revanced.patcher.checkCast -import app.revanced.patcher.fingerprint -import app.revanced.patcher.methodCall -import app.revanced.patcher.opcode -import app.revanced.patcher.string import app.revanced.patches.shared.misc.mapping.ResourceType import app.revanced.patches.shared.misc.mapping.resourceLiteral import app.revanced.patches.youtube.layout.buttons.navigation.navigationButtonsPatch @@ -79,6 +75,7 @@ internal val navigationEnumFingerprint = fingerprint { "TAB_ACTIVITY", "VIDEO_LIBRARY_WHITE", "INCOGNITO_CIRCLE", + "UNKNOWN" // Required to distinguish from patch extension class. ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/navigation/NavigationBarHookPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/navigation/NavigationBarHookPatch.kt index 144a0b0ed..e854b2a7e 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/navigation/NavigationBarHookPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/navigation/NavigationBarHookPatch.kt @@ -1,5 +1,7 @@ package app.revanced.patches.youtube.misc.navigation +import app.revanced.patcher.dex.mutable.MutableMethod +import app.revanced.patcher.dex.mutable.MutableMethod.Companion.toMutable import app.revanced.patcher.extensions.addInstruction import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.getInstruction @@ -7,16 +9,10 @@ import app.revanced.patcher.extensions.instructions import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.resourcePatch -import app.revanced.patcher.dex.mutable.MutableMethod -import app.revanced.patcher.dex.mutable.MutableMethod.Companion.toMutable import app.revanced.patches.shared.misc.mapping.resourceMappingPatch import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch import app.revanced.patches.youtube.misc.playertype.playerTypeHookPatch -import app.revanced.patches.youtube.misc.playservice.is_19_35_or_greater -import app.revanced.patches.youtube.misc.playservice.is_20_21_or_greater -import app.revanced.patches.youtube.misc.playservice.is_20_28_or_greater -import app.revanced.patches.youtube.misc.playservice.is_20_39_or_greater -import app.revanced.patches.youtube.misc.playservice.versionCheckPatch +import app.revanced.patches.youtube.misc.playservice.* import app.revanced.patches.youtube.shared.mainActivityOnBackPressedFingerprint import app.revanced.util.ResourceGroup import app.revanced.util.copyResources @@ -74,7 +70,7 @@ val navigationBarHookPatch = bytecodePatch(description = "Hooks the active navig addInstruction( insertIndex, "invoke-static { v$register }, " + - "$EXTENSION_CLASS_DESCRIPTOR->${hook.methodName}(${hook.parameters})V", + "$EXTENSION_CLASS_DESCRIPTOR->${hook.methodName}(${hook.parameters})V", ) } } @@ -84,7 +80,7 @@ val navigationBarHookPatch = bytecodePatch(description = "Hooks the active navig val navigationEnumClassName = navigationEnumFingerprint.classDef.type addHook(NavigationHook.SET_LAST_APP_NAVIGATION_ENUM) { opcode == Opcode.INVOKE_STATIC && - getReference()?.definingClass == navigationEnumClassName + getReference()?.definingClass == navigationEnumClassName } // Hook the creation of navigation tab views. @@ -206,7 +202,7 @@ val navigationBarHookPatch = bytecodePatch(description = "Hooks the active navig navigationBarHookCallbackFingerprint.method.addInstruction( 0, "invoke-static { p0, p1 }, $extensionClassDescriptor->navigationTabCreated" + - "(${EXTENSION_NAVIGATION_BUTTON_DESCRIPTOR}Landroid/view/View;)V", + "(${EXTENSION_NAVIGATION_BUTTON_DESCRIPTOR}Landroid/view/View;)V", ) } @@ -221,21 +217,19 @@ val navigationBarHookPatch = bytecodePatch(description = "Hooks the active navig val cairoNotificationEnumReference = imageEnumConstructorFingerprint .instructionMatches.last().getInstruction().reference - setEnumMapFingerprint.let { - it.method.apply { - val setEnumIntegerIndex = it.instructionMatches.last().index - val enumMapRegister = getInstruction(setEnumIntegerIndex).registerC - val insertIndex = setEnumIntegerIndex + 1 - val freeRegister = findFreeRegister(insertIndex, enumMapRegister) + setEnumMapFingerprint.method.apply { + val setEnumIntegerIndex = setEnumMapFingerprint.instructionMatches.last().index + val enumMapRegister = getInstruction(setEnumIntegerIndex).registerC + val insertIndex = setEnumIntegerIndex + 1 + val freeRegister = findFreeRegister(insertIndex, enumMapRegister) - addInstructions( - insertIndex, - """ - sget-object v$freeRegister, $cairoNotificationEnumReference - invoke-static { v$enumMapRegister, v$freeRegister }, $EXTENSION_CLASS_DESCRIPTOR->setCairoNotificationFilledIcon(Ljava/util/EnumMap;Ljava/lang/Enum;)V - """ - ) - } + addInstructions( + insertIndex, + """ + sget-object v$freeRegister, $cairoNotificationEnumReference + invoke-static { v$enumMapRegister, v$freeRegister }, $EXTENSION_CLASS_DESCRIPTOR->setCairoNotificationFilledIcon(Ljava/util/EnumMap;Ljava/lang/Enum;)V + """ + ) } } } diff --git a/patches/src/main/kotlin/app/revanced/util/BytecodeUtils.kt b/patches/src/main/kotlin/app/revanced/util/BytecodeUtils.kt index a1c0ca336..cdc7d8e90 100644 --- a/patches/src/main/kotlin/app/revanced/util/BytecodeUtils.kt +++ b/patches/src/main/kotlin/app/revanced/util/BytecodeUtils.kt @@ -86,8 +86,10 @@ fun Method.findFreeRegister(startIndex: Int, vararg registersToExclude: Int): In return bestFreeRegisterFound } // This method is simple and does not follow branching. - throw IllegalArgumentException("Encountered a branch statement before " + - "a free register could be found from startIndex: $startIndex") + throw IllegalArgumentException( + "Encountered a branch statement before " + + "a free register could be found from startIndex: $startIndex" + ) } if (instruction.isReturnInstruction) { @@ -104,8 +106,10 @@ fun Method.findFreeRegister(startIndex: Int, vararg registersToExclude: Int): In // Somehow every method register was read from before any register was wrote to. // In practice this never occurs. - throw IllegalArgumentException("Could not find a free register from startIndex: " + - "$startIndex excluding: $registersToExclude") + throw IllegalArgumentException( + "Could not find a free register from startIndex: " + + "$startIndex excluding: $registersToExclude" + ) } } @@ -170,7 +174,7 @@ internal val Instruction.isReturnInstruction: Boolean * * @param fieldName The name of the field to find. Partial matches are allowed. */ -private fun Method.findInstructionIndexFromToString(fieldName: String) : Int { +private fun Method.findInstructionIndexFromToString(fieldName: String): Int { val stringIndex = indexOfFirstInstruction { val reference = getReference() reference?.string?.contains(fieldName) == true @@ -210,7 +214,8 @@ private fun Method.findInstructionIndexFromToString(fieldName: String) : Int { val fieldSetOpcode = getInstruction(fieldSetIndex).opcode if (fieldSetOpcode == MOVE_RESULT || fieldSetOpcode == MOVE_RESULT_WIDE || - fieldSetOpcode == MOVE_RESULT_OBJECT) { + fieldSetOpcode == MOVE_RESULT_OBJECT + ) { fieldSetIndex-- } @@ -223,7 +228,7 @@ private fun Method.findInstructionIndexFromToString(fieldName: String) : Int { * @param fieldName The name of the field to find. Partial matches are allowed. */ context(BytecodePatchContext) -internal fun Method.findMethodFromToString(fieldName: String) : MutableMethod { +internal fun Method.findMethodFromToString(fieldName: String): MutableMethod { val methodUsageIndex = findInstructionIndexFromToString(fieldName) return navigate(this).to(methodUsageIndex).stop() } @@ -233,7 +238,7 @@ internal fun Method.findMethodFromToString(fieldName: String) : MutableMethod { * * @param fieldName The name of the field to find. Partial matches are allowed. */ -internal fun Method.findFieldFromToString(fieldName: String) : FieldReference { +internal fun Method.findFieldFromToString(fieldName: String): FieldReference { val methodUsageIndex = findInstructionIndexFromToString(fieldName) return getInstruction(methodUsageIndex).getReference()!! } @@ -792,36 +797,34 @@ internal fun MutableMethod.insertLiteralOverride(literalIndex: Int, override: Bo } /** - * Called for _all_ methods with the given literal value. - * Method indices are iterated from last to first. + * Iterates all instructions as sequence in all methods of all classes in the [BytecodePatchContext]. + * The instructions are provided in reverse order (last to first). + * The [block] is invoked after collecting all instructions to avoid concurrent modification issues. */ -fun BytecodePatchContext.forEachLiteralValueInstruction( - literal: Long, - block: MutableMethod.(matchingIndex: Int) -> Unit, +fun BytecodePatchContext.forEachInstructionAsSequence( + block: (classDef: MutableClassDef, method: MutableMethod, matchingIndex: Int, instruction: Instruction) -> Unit, ) { - val matchingIndexes = ArrayList() + classDefs.asSequence().flatMap { classDef -> + val mutableClassDef by lazy { classDef.mutable() } - classDefs.forEach { classDef -> - classDef.methods.forEach { method -> - method.implementation?.instructions?.let { instructions -> - matchingIndexes.clear() + classDef.methods.asSequence().flatMap { method -> + val instructions = + method.instructionsOrNull as? List ?: return@flatMap emptySequence<() -> Unit>() - instructions.forEachIndexed { index, instruction -> - if ((instruction as? WideLiteralInstruction)?.wideLiteral == literal) { - matchingIndexes.add(index) - } - } + val mutableMethod by lazy { mutableClassDef.findMutableMethodOf(method) } - if (matchingIndexes.isNotEmpty()) { - val mutableMethod = classDef.mutable().findMutableMethodOf(method) - matchingIndexes.asReversed().forEach { index -> - block.invoke(mutableMethod, index) - } - } + instructions.asReversed().asSequence().mapIndexed { index, instruction -> + { + block( + mutableClassDef, + mutableMethod, + instructions.size - 1 - index, + instruction + ) + } // Reverse indices again. } } - } - + }.forEach { it() } } private const val RETURN_TYPE_MISMATCH = "Mismatch between override type and Method return type" @@ -1090,7 +1093,7 @@ fun MutableMethod.returnLate(value: Void?) { } private fun MutableMethod.overrideReturnValue(value: String, returnLate: Boolean) { - val instructions = if (returnType == "Ljava/lang/String;" || returnType == "Ljava/lang/CharSequence;" ) { + val instructions = if (returnType == "Ljava/lang/String;" || returnType == "Ljava/lang/CharSequence;") { """ const-string v0, "$value" return-object v0