From 4a1d850bd4dfddb9a5e7214445b77cd0363cc8d1 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Mon, 2 Feb 2026 15:59:38 +0100 Subject: [PATCH] a couple more fixes --- .../TransformInstructionsPatch.kt | 13 ++- ...ontent.kt => HideSuggestedContentPatch.kt} | 2 +- .../BypassCertificateChecksPatch.kt | 3 - .../signature/SignatureDetectionPatch.kt | 1 - .../unlock/bookpoint/EnableBookpointPatch.kt | 1 - .../reddit/ad/comments/HideCommentAdsPatch.kt | 1 - .../misc/privacy/SanitizeSharingLinksPatch.kt | 45 +++++---- ...veGroupKudosButtonToGroupActivityPatch.kt} | 2 +- .../tiktok/feedfilter/FeedFilterPatch.kt | 4 +- .../interaction/downloads/DownloadsPatch.kt | 7 +- .../tiktok/misc/settings/SettingsPatch.kt | 3 +- .../tiktok/misc/spoof/sim/SpoofSimPatch.kt | 4 +- .../patches/twitch/ad/audio/AudioAdsPatch.kt | 4 +- .../twitch/ad/embedded/EmbeddedAdsPatch.kt | 4 +- .../patches/twitch/ad/video/VideoAdsPatch.kt | 4 +- .../antidelete/ShowDeletedMessagesPatch.kt | 4 +- .../autoclaim/AutoClaimChannelPointsPatch.kt | 4 +- .../patches/twitch/debug/DebugModePatch.kt | 4 +- .../twitch/misc/settings/SettingsPatch.kt | 3 +- .../youtube/ad/general/HideAdsPatch.kt | 17 ++-- .../interaction/downloads/DownloadsPatch.kt | 3 +- .../interaction/seekbar/Fingerprints.kt | 4 +- .../interaction/seekbar/HideSeekbarPatch.kt | 4 +- .../interaction/seekbar/SeekbarPatch.kt | 3 +- .../branding/header/ChangeHeaderPatch.kt | 22 +++-- .../hide/shorts/HideShortsComponentsPatch.kt | 44 +++++---- .../layout/miniplayer/MiniplayerPatch.kt | 3 +- .../ReturnYouTubeDislikePatch.kt | 15 +-- .../layout/sponsorblock/SponsorBlockPatch.kt | 7 +- .../misc/announcements/AnnouncementsPatch.kt | 3 +- .../youtube/misc/navigation/Fingerprints.kt | 4 +- .../patches/youtube/shared/Fingerprints.kt | 2 +- .../video/codecs/DisableVideoCodecsPatch.kt | 3 +- .../kotlin/app/revanced/util/BytecodeUtils.kt | 92 ++++++++++--------- 34 files changed, 184 insertions(+), 155 deletions(-) rename patches/src/main/kotlin/app/revanced/patches/instagram/hide/suggestions/{HideSuggestedContent.kt => HideSuggestedContentPatch.kt} (95%) rename patches/src/main/kotlin/app/revanced/patches/strava/groupkudos/{AddGiveGroupKudosButtonToGroupActivity.kt => AddGiveGroupKudosButtonToGroupActivityPatch.kt} (99%) 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 17e6a9384c..914d8ab85e 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 @@ -7,13 +7,16 @@ 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 +@Deprecated( + "Use forEachInstructionAsSequence directly within a bytecodePatch", ReplaceWith( + "bytecodePatch { apply { forEachInstructionAsSequence(filterMap, transform) } }", + "app.revanced.util.forEachInstructionAsSequence", + "app.revanced.patcher.patch.bytecodePatch", + ) +) fun transformInstructionsPatch( filterMap: (ClassDef, Method, Instruction, Int) -> T?, transform: (MutableMethod, T) -> Unit, ) = bytecodePatch { - apply { - forEachInstructionAsSequence { classDef, method, i, instruction -> - transform(method, filterMap(classDef, method, instruction, i) ?: return@forEachInstructionAsSequence) - } - } + apply { forEachInstructionAsSequence(filterMap, transform) } } diff --git a/patches/src/main/kotlin/app/revanced/patches/instagram/hide/suggestions/HideSuggestedContent.kt b/patches/src/main/kotlin/app/revanced/patches/instagram/hide/suggestions/HideSuggestedContentPatch.kt similarity index 95% rename from patches/src/main/kotlin/app/revanced/patches/instagram/hide/suggestions/HideSuggestedContent.kt rename to patches/src/main/kotlin/app/revanced/patches/instagram/hide/suggestions/HideSuggestedContentPatch.kt index 29d389d6da..f82335e186 100644 --- a/patches/src/main/kotlin/app/revanced/patches/instagram/hide/suggestions/HideSuggestedContent.kt +++ b/patches/src/main/kotlin/app/revanced/patches/instagram/hide/suggestions/HideSuggestedContentPatch.kt @@ -6,7 +6,7 @@ import app.revanced.patcher.patch.bytecodePatch import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction @Suppress("unused") -val hideSuggestedContent = bytecodePatch( +val hideSuggestedContentPatch = bytecodePatch( name = "Hide suggested content", description = "Hides suggested stories, reels, threads and survey from feed (Suggested posts will still be shown).", use = false, diff --git a/patches/src/main/kotlin/app/revanced/patches/music/misc/androidauto/BypassCertificateChecksPatch.kt b/patches/src/main/kotlin/app/revanced/patches/music/misc/androidauto/BypassCertificateChecksPatch.kt index 4e360abe77..26d2de4fb5 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/misc/androidauto/BypassCertificateChecksPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/misc/androidauto/BypassCertificateChecksPatch.kt @@ -1,9 +1,6 @@ package app.revanced.patches.music.misc.androidauto import app.revanced.patcher.patch.bytecodePatch -import app.revanced.patches.music.misc.extension.sharedExtensionPatch -import app.revanced.patches.music.misc.settings.settingsPatch -import app.revanced.util.returnEarly @Deprecated("This patch is useless by itself and has been merged into another patch.", ReplaceWith("unlockAndroidAutoMediaBrowserPatch")) @Suppress("unused") diff --git a/patches/src/main/kotlin/app/revanced/patches/photomath/detection/signature/SignatureDetectionPatch.kt b/patches/src/main/kotlin/app/revanced/patches/photomath/detection/signature/SignatureDetectionPatch.kt index 4bdeaf882d..a4d81d204e 100644 --- a/patches/src/main/kotlin/app/revanced/patches/photomath/detection/signature/SignatureDetectionPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/photomath/detection/signature/SignatureDetectionPatch.kt @@ -5,7 +5,6 @@ import app.revanced.patcher.extensions.replaceInstruction import app.revanced.patcher.patch.bytecodePatch import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction -@Suppress("unused") val signatureDetectionPatch = bytecodePatch( description = "Disables detection of incorrect signature.", ) { diff --git a/patches/src/main/kotlin/app/revanced/patches/photomath/misc/unlock/bookpoint/EnableBookpointPatch.kt b/patches/src/main/kotlin/app/revanced/patches/photomath/misc/unlock/bookpoint/EnableBookpointPatch.kt index ee7972a171..77475d2990 100644 --- a/patches/src/main/kotlin/app/revanced/patches/photomath/misc/unlock/bookpoint/EnableBookpointPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/photomath/misc/unlock/bookpoint/EnableBookpointPatch.kt @@ -3,7 +3,6 @@ package app.revanced.patches.photomath.misc.unlock.bookpoint import app.revanced.patcher.patch.bytecodePatch import app.revanced.util.returnEarly -@Suppress("unused") val enableBookpointPatch = bytecodePatch( description = "Enables textbook access", ) { diff --git a/patches/src/main/kotlin/app/revanced/patches/reddit/ad/comments/HideCommentAdsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/reddit/ad/comments/HideCommentAdsPatch.kt index 9ebbf78ba6..4baebd53be 100644 --- a/patches/src/main/kotlin/app/revanced/patches/reddit/ad/comments/HideCommentAdsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/reddit/ad/comments/HideCommentAdsPatch.kt @@ -3,7 +3,6 @@ package app.revanced.patches.reddit.ad.comments import app.revanced.patcher.extensions.replaceInstructions import app.revanced.patcher.patch.bytecodePatch -@Suppress("unused") val hideCommentAdsPatch = bytecodePatch( description = "Removes ads in the comments." ) { diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/misc/privacy/SanitizeSharingLinksPatch.kt b/patches/src/main/kotlin/app/revanced/patches/shared/misc/privacy/SanitizeSharingLinksPatch.kt index 9f557c14e6..ed5f349155 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/misc/privacy/SanitizeSharingLinksPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/misc/privacy/SanitizeSharingLinksPatch.kt @@ -60,34 +60,41 @@ internal fun sanitizeSharingLinksPatch( }, ) - fun Match.hook( - getInsertIndex: List.() -> Int, - getUrlRegister: MutableMethod.(insertIndex: Int) -> Int, - ) { - val insertIndex = indices[0].getInsertIndex() - val urlRegister = method.getUrlRegister(insertIndex) + + fun Match.hookUrlString(matchIndex: Int) { + val index = get(matchIndex) + val urlRegister = method.getInstruction(index).registerA method.addInstructions( - insertIndex, + index + 1, """ - invoke-static {v$urlRegister}, $EXTENSION_CLASS_DESCRIPTOR->sanitize(Ljava/lang/String;)Ljava/lang/String; + invoke-static { v$urlRegister }, $EXTENSION_CLASS_DESCRIPTOR->sanitize(Ljava/lang/String;)Ljava/lang/String; move-result-object v$urlRegister - """, + """ ) } - // YouTube share sheet.\ - youTubeShareSheetMethodMatch.hook(getInsertIndex = { first() + 1 }) { insertIndex -> - getInstruction(insertIndex - 1).registerA + fun Match.hookIntentPutExtra(matchIndex: Int) { + val index = get(matchIndex) + val urlRegister = method.getInstruction(index).registerE + + method.addInstructionsAtControlFlowLabel( + index, + """ + invoke-static { v$urlRegister }, $EXTENSION_CLASS_DESCRIPTOR->sanitize(Ljava/lang/String;)Ljava/lang/String; + move-result-object v$urlRegister + """ + ) } + + // YouTube share sheet copy link. + youTubeCopyTextMethodMatch.hookUrlString(0) + + // YouTube share sheet other apps. + youTubeShareSheetMethodMatch.hookIntentPutExtra(3) + // Native system share sheet. - youTubeSystemShareSheetMethodMatch.hook(getInsertIndex = { last() }) { insertIndex -> - getInstruction(insertIndex - 1).registerA - } - - youTubeCopyTextMethodMatch.hook(getInsertIndex = { first() + 2 }) { insertIndex -> - getInstruction(insertIndex - 2).registerA - } + youTubeSystemShareSheetMethodMatch.hookIntentPutExtra(3) } } diff --git a/patches/src/main/kotlin/app/revanced/patches/strava/groupkudos/AddGiveGroupKudosButtonToGroupActivity.kt b/patches/src/main/kotlin/app/revanced/patches/strava/groupkudos/AddGiveGroupKudosButtonToGroupActivityPatch.kt similarity index 99% rename from patches/src/main/kotlin/app/revanced/patches/strava/groupkudos/AddGiveGroupKudosButtonToGroupActivity.kt rename to patches/src/main/kotlin/app/revanced/patches/strava/groupkudos/AddGiveGroupKudosButtonToGroupActivityPatch.kt index adca886e41..9d4756f455 100644 --- a/patches/src/main/kotlin/app/revanced/patches/strava/groupkudos/AddGiveGroupKudosButtonToGroupActivity.kt +++ b/patches/src/main/kotlin/app/revanced/patches/strava/groupkudos/AddGiveGroupKudosButtonToGroupActivityPatch.kt @@ -93,7 +93,7 @@ private val addGiveKudosButtonToLayoutPatch = resourcePatch { } @Suppress("unused") -val addGiveGroupKudosButtonToGroupActivity = bytecodePatch( +val addGiveGroupKudosButtonToGroupActivityPatch = bytecodePatch( name = "Add 'Give Kudos' button to 'Group Activity'", description = "Adds a button that triggers the same action as shaking your phone would.", ) { diff --git a/patches/src/main/kotlin/app/revanced/patches/tiktok/feedfilter/FeedFilterPatch.kt b/patches/src/main/kotlin/app/revanced/patches/tiktok/feedfilter/FeedFilterPatch.kt index 40755038d3..57dfdbd3c3 100644 --- a/patches/src/main/kotlin/app/revanced/patches/tiktok/feedfilter/FeedFilterPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/tiktok/feedfilter/FeedFilterPatch.kt @@ -4,7 +4,7 @@ import app.revanced.patcher.extensions.addInstruction import app.revanced.patcher.extensions.instructions import app.revanced.patcher.patch.bytecodePatch import app.revanced.patches.tiktok.misc.extension.sharedExtensionPatch -import app.revanced.patches.tiktok.misc.settings.Settings +import app.revanced.patches.tiktok.misc.settings.settingsPatch import app.revanced.patches.tiktok.misc.settings.settingsStatusLoadMethod import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction @@ -19,7 +19,7 @@ val feedFilterPatch = bytecodePatch( ) { dependsOn( sharedExtensionPatch, - Settings, + settingsPatch, ) compatibleWith( diff --git a/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/DownloadsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/DownloadsPatch.kt index 464a294a8b..3150c6a190 100644 --- a/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/DownloadsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/DownloadsPatch.kt @@ -3,7 +3,7 @@ package app.revanced.patches.tiktok.interaction.downloads import app.revanced.patcher.extensions.* import app.revanced.patcher.patch.bytecodePatch import app.revanced.patches.tiktok.misc.extension.sharedExtensionPatch -import app.revanced.patches.tiktok.misc.settings.Settings +import app.revanced.patches.tiktok.misc.settings.settingsPatch import app.revanced.patches.tiktok.misc.settings.settingsStatusLoadMethod import app.revanced.util.findInstructionIndicesReversedOrThrow import app.revanced.util.getReference @@ -15,12 +15,13 @@ import com.android.tools.smali.dexlib2.iface.reference.FieldReference private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/tiktok/download/DownloadsPatch;" @Suppress("unused") -val Downloads = bytecodePatch( +val downloadsPatch = bytecodePatch( + name = "Downloads", description = "Removes download restrictions and changes the default path to download to.", ) { dependsOn( sharedExtensionPatch, - Settings, + settingsPatch, ) compatibleWith( diff --git a/patches/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/SettingsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/SettingsPatch.kt index 5400829b8f..4e6a43b3a6 100644 --- a/patches/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/SettingsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/SettingsPatch.kt @@ -12,7 +12,8 @@ import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/tiktok/settings/TikTokActivityHook;" -val Settings = bytecodePatch( +val settingsPatch = bytecodePatch( + name = "Settings", description = "Adds ReVanced settings to TikTok.", ) { dependsOn(sharedExtensionPatch, addBrandLicensePatch) diff --git a/patches/src/main/kotlin/app/revanced/patches/tiktok/misc/spoof/sim/SpoofSimPatch.kt b/patches/src/main/kotlin/app/revanced/patches/tiktok/misc/spoof/sim/SpoofSimPatch.kt index 9e39796ec8..cec6fa3f19 100644 --- a/patches/src/main/kotlin/app/revanced/patches/tiktok/misc/spoof/sim/SpoofSimPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/tiktok/misc/spoof/sim/SpoofSimPatch.kt @@ -6,7 +6,7 @@ import app.revanced.patcher.extensions.getInstruction import app.revanced.patcher.firstMutableMethod import app.revanced.patcher.patch.bytecodePatch import app.revanced.patches.tiktok.misc.extension.sharedExtensionPatch -import app.revanced.patches.tiktok.misc.settings.Settings +import app.revanced.patches.tiktok.misc.settings.settingsPatch import app.revanced.patches.tiktok.misc.settings.settingsStatusLoadMethod import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction @@ -21,7 +21,7 @@ val sIMSpoofPatch = bytecodePatch( ) { dependsOn( sharedExtensionPatch, - Settings, + settingsPatch, ) compatibleWith( diff --git a/patches/src/main/kotlin/app/revanced/patches/twitch/ad/audio/AudioAdsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/twitch/ad/audio/AudioAdsPatch.kt index 36e5446560..340757c58d 100644 --- a/patches/src/main/kotlin/app/revanced/patches/twitch/ad/audio/AudioAdsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/twitch/ad/audio/AudioAdsPatch.kt @@ -9,7 +9,7 @@ import app.revanced.patches.all.misc.resources.addResourcesPatch import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.twitch.misc.extension.sharedExtensionPatch import app.revanced.patches.twitch.misc.settings.PreferenceScreen -import app.revanced.patches.twitch.misc.settings.Settings +import app.revanced.patches.twitch.misc.settings.settingsPatch @Suppress("unused") val blockAudioAdsPatch = bytecodePatch( @@ -18,7 +18,7 @@ val blockAudioAdsPatch = bytecodePatch( ) { dependsOn( sharedExtensionPatch, - Settings, + settingsPatch, addResourcesPatch, ) diff --git a/patches/src/main/kotlin/app/revanced/patches/twitch/ad/embedded/EmbeddedAdsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/twitch/ad/embedded/EmbeddedAdsPatch.kt index 3cd2154317..57bb6635da 100644 --- a/patches/src/main/kotlin/app/revanced/patches/twitch/ad/embedded/EmbeddedAdsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/twitch/ad/embedded/EmbeddedAdsPatch.kt @@ -7,7 +7,7 @@ import app.revanced.patches.shared.misc.settings.preference.ListPreference import app.revanced.patches.twitch.ad.video.blockVideoAdsPatch import app.revanced.patches.twitch.misc.extension.sharedExtensionPatch import app.revanced.patches.twitch.misc.settings.PreferenceScreen -import app.revanced.patches.twitch.misc.settings.Settings +import app.revanced.patches.twitch.misc.settings.settingsPatch @Suppress("unused") val blockEmbeddedAdsPatch = bytecodePatch( @@ -17,7 +17,7 @@ val blockEmbeddedAdsPatch = bytecodePatch( dependsOn( blockVideoAdsPatch, sharedExtensionPatch, - Settings, + settingsPatch, ) compatibleWith("tv.twitch.android.app"("16.9.1", "25.3.0")) diff --git a/patches/src/main/kotlin/app/revanced/patches/twitch/ad/video/VideoAdsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/twitch/ad/video/VideoAdsPatch.kt index 7e2f80a078..91b78aa4bf 100644 --- a/patches/src/main/kotlin/app/revanced/patches/twitch/ad/video/VideoAdsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/twitch/ad/video/VideoAdsPatch.kt @@ -12,7 +12,7 @@ import app.revanced.patches.twitch.ad.shared.util.ReturnMethod import app.revanced.patches.twitch.ad.shared.util.adPatch import app.revanced.patches.twitch.misc.extension.sharedExtensionPatch import app.revanced.patches.twitch.misc.settings.PreferenceScreen -import app.revanced.patches.twitch.misc.settings.Settings +import app.revanced.patches.twitch.misc.settings.settingsPatch @Suppress("ObjectPropertyName") val blockVideoAdsPatch = bytecodePatch( @@ -24,7 +24,7 @@ val blockVideoAdsPatch = bytecodePatch( dependsOn( sharedExtensionPatch, - Settings, + settingsPatch, addResourcesPatch, adPatch(conditionCall, skipLabelName) { createConditionInstructions, blockMethods -> diff --git a/patches/src/main/kotlin/app/revanced/patches/twitch/chat/antidelete/ShowDeletedMessagesPatch.kt b/patches/src/main/kotlin/app/revanced/patches/twitch/chat/antidelete/ShowDeletedMessagesPatch.kt index 5cea39b26e..13f93f8bcf 100644 --- a/patches/src/main/kotlin/app/revanced/patches/twitch/chat/antidelete/ShowDeletedMessagesPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/twitch/chat/antidelete/ShowDeletedMessagesPatch.kt @@ -10,7 +10,7 @@ import app.revanced.patches.all.misc.resources.addResourcesPatch import app.revanced.patches.shared.misc.settings.preference.ListPreference import app.revanced.patches.twitch.misc.extension.sharedExtensionPatch import app.revanced.patches.twitch.misc.settings.PreferenceScreen -import app.revanced.patches.twitch.misc.settings.Settings +import app.revanced.patches.twitch.misc.settings.settingsPatch @Suppress("unused") val showDeletedMessagesPatch = bytecodePatch( @@ -19,7 +19,7 @@ val showDeletedMessagesPatch = bytecodePatch( ) { dependsOn( sharedExtensionPatch, - Settings, + settingsPatch, addResourcesPatch, ) diff --git a/patches/src/main/kotlin/app/revanced/patches/twitch/chat/autoclaim/AutoClaimChannelPointsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/twitch/chat/autoclaim/AutoClaimChannelPointsPatch.kt index 06745c5a54..eaea93417a 100644 --- a/patches/src/main/kotlin/app/revanced/patches/twitch/chat/autoclaim/AutoClaimChannelPointsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/twitch/chat/autoclaim/AutoClaimChannelPointsPatch.kt @@ -9,7 +9,7 @@ import app.revanced.patches.all.misc.resources.addResources import app.revanced.patches.all.misc.resources.addResourcesPatch import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.twitch.misc.settings.PreferenceScreen -import app.revanced.patches.twitch.misc.settings.Settings +import app.revanced.patches.twitch.misc.settings.settingsPatch @Suppress("unused") val autoClaimChannelPointsPatch = bytecodePatch( @@ -17,7 +17,7 @@ val autoClaimChannelPointsPatch = bytecodePatch( description = "Automatically claim Channel Points.", ) { dependsOn( - Settings, + settingsPatch, addResourcesPatch, ) diff --git a/patches/src/main/kotlin/app/revanced/patches/twitch/debug/DebugModePatch.kt b/patches/src/main/kotlin/app/revanced/patches/twitch/debug/DebugModePatch.kt index 451ac5b86f..c0686d8b44 100644 --- a/patches/src/main/kotlin/app/revanced/patches/twitch/debug/DebugModePatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/twitch/debug/DebugModePatch.kt @@ -7,7 +7,7 @@ import app.revanced.patches.all.misc.resources.addResourcesPatch import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.twitch.misc.extension.sharedExtensionPatch import app.revanced.patches.twitch.misc.settings.PreferenceScreen -import app.revanced.patches.twitch.misc.settings.Settings +import app.revanced.patches.twitch.misc.settings.settingsPatch @Suppress("ObjectPropertyName") val debugModePatch = bytecodePatch( @@ -17,7 +17,7 @@ val debugModePatch = bytecodePatch( ) { dependsOn( sharedExtensionPatch, - Settings, + settingsPatch, addResourcesPatch, ) diff --git a/patches/src/main/kotlin/app/revanced/patches/twitch/misc/settings/SettingsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/twitch/misc/settings/SettingsPatch.kt index 26d82f42eb..e99788f5d9 100644 --- a/patches/src/main/kotlin/app/revanced/patches/twitch/misc/settings/SettingsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/twitch/misc/settings/SettingsPatch.kt @@ -36,7 +36,8 @@ fun addSettingPreference(screen: BasePreference) { preferences += screen } -val Settings = bytecodePatch( +val settingsPatch = bytecodePatch( + name = "Settings", description = "Adds settings menu to Twitch.", ) { dependsOn( 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 6de6152bef..75800993aa 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 @@ -4,6 +4,7 @@ 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.firstMutableMethod import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.resourcePatch import app.revanced.patches.all.misc.resources.addResources @@ -94,21 +95,25 @@ val hideAdsPatch = bytecodePatch( replaceInstruction( addListIndex, "invoke-static { v$listRegister, v$objectRegister }, $EXTENSION_CLASS_DESCRIPTOR" + - "->hideEndScreenStoreBanner(Ljava/util/List;Ljava/lang/Object;)V", + "->hideEndScreenStoreBanner(Ljava/util/List;Ljava/lang/Object;)V", ) } // Hide ad views. - forEachInstructionAsSequence { _, method, index, instruction -> - if (instruction.opcode != Opcode.CONST) return@forEachInstructionAsSequence - if (instruction.wideLiteral != adAttributionId) return@forEachInstructionAsSequence + forEachInstructionAsSequence({ _, method, instruction, index -> + if (instruction.opcode != Opcode.CONST) return@forEachInstructionAsSequence null + if (instruction.wideLiteral != adAttributionId) return@forEachInstructionAsSequence null val insertIndex = index + 1 - // Call to get the view with the id adAttribution, - if (method.instructions[insertIndex].opcode != Opcode.INVOKE_VIRTUAL) return@forEachInstructionAsSequence + // Call to get the view with the id adAttribution. + if (method.instructions.elementAt(insertIndex).opcode != Opcode.INVOKE_VIRTUAL) return@forEachInstructionAsSequence null val viewRegister = method.getInstruction(insertIndex).registerC + + return@forEachInstructionAsSequence insertIndex to viewRegister + + }) { method, (insertIndex, viewRegister) -> method.injectHideViewCall(insertIndex, viewRegister, EXTENSION_CLASS_DESCRIPTOR, "hideAdAttributionView") } } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/DownloadsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/DownloadsPatch.kt index e18ef3d408..c1d1cdcbc4 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/DownloadsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/DownloadsPatch.kt @@ -60,7 +60,8 @@ private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/ internal const val BUTTON_DESCRIPTOR = "Lapp/revanced/extension/youtube/videoplayer/ExternalDownloadButton;" @Suppress("unused") -val Downloads = bytecodePatch( +val downloadsPatch = bytecodePatch( + name = "Downloads", description = "Adds support to download videos with an external downloader app " + "using the in-app download button or a video player action button.", ) { diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/Fingerprints.kt index c9fe13ba8a..6d6f90659d 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/Fingerprints.kt @@ -112,9 +112,9 @@ internal val BytecodePatchContext.seekbarTappingMethodMatch by composingFirstMet Int.MAX_VALUE.toLong()(), allOf(Opcode.NEW_INSTANCE(), type("Landroid/graphics/Point;")), after(method { toString() == "Landroid/graphics/Point;->(II)V" }), - after(method { toString() == "Landroid/view/MotionEvent;->getX()F" }), + after(method { toString() == "Lj$/util/Optional;->of(Ljava/lang/Object;)Lj$/util/Optional;" }), after(Opcode.MOVE_RESULT_OBJECT()), - after(allOf(Opcode.IPUT_OBJECT(), field { type == "Lj\$/util/Optional;" })), + after(allOf(Opcode.IPUT_OBJECT(), field { type == "Lj$/util/Optional;" })), afterAtMost(10, Opcode.INVOKE_VIRTUAL()), ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/HideSeekbarPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/HideSeekbarPatch.kt index 47b69d8b35..185ef9385c 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/HideSeekbarPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/HideSeekbarPatch.kt @@ -13,7 +13,7 @@ import app.revanced.patches.youtube.misc.playservice.versionCheckPatch import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.settingsPatch import app.revanced.patches.youtube.shared.seekbarMethod -import app.revanced.patches.youtube.shared.seekbarOnDrawMethodMatch +import app.revanced.patches.youtube.shared.getSeekbarOnDrawMethodMatch import app.revanced.util.insertLiteralOverride private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/HideSeekbarPatch;" @@ -38,7 +38,7 @@ val hideSeekbarPatch = bytecodePatch( SwitchPreference("revanced_fullscreen_large_seekbar"), ) - seekbarMethod.immutableClassDef.seekbarOnDrawMethodMatch.method.addInstructionsWithLabels( + seekbarMethod.immutableClassDef.getSeekbarOnDrawMethodMatch().method.addInstructionsWithLabels( 0, """ const/4 v0, 0x0 diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/SeekbarPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/SeekbarPatch.kt index c3fe162a58..6033875241 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/SeekbarPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/SeekbarPatch.kt @@ -3,7 +3,8 @@ package app.revanced.patches.youtube.interaction.seekbar import app.revanced.patcher.patch.bytecodePatch @Suppress("unused") -val Seekbar = bytecodePatch( +val seekbarPatch = bytecodePatch( + name = "Seekbar", description = "Adds options to disable precise seeking when swiping up on the seekbar, " + "slide to seek instead of playing at 2x speed when pressing and holding, " + "tapping the player seekbar to seek, " + 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 97eb235c69..d6effd1efe 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 @@ -3,6 +3,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.firstMutableMethod import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.resourcePatch @@ -77,12 +78,15 @@ private val changeHeaderBytecodePatch = bytecodePatch { ).forEach { resourceName -> val id = ResourceType.ATTR[resourceName] - forEachInstructionAsSequence { _, method, i, instruction -> - if (instruction.wideLiteral != id) return@forEachInstructionAsSequence + forEachInstructionAsSequence({ _, method, instruction, index -> + if (instruction.wideLiteral != id) return@forEachInstructionAsSequence null - val register = method.getInstruction(i).registerA + val register = method.getInstruction(index).registerA + + return@forEachInstructionAsSequence index to register + }) { method, (index, register) -> method.addInstructions( - i + 1, + index + 1, """ invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->getHeaderAttributeId(I)I move-result v$register @@ -218,14 +222,14 @@ val changeHeaderPatch = resourcePatch( if (!customFile.exists()) { throw PatchException( "The custom header path cannot be found: " + - customFile.absolutePath, + customFile.absolutePath, ) } if (!customFile.isDirectory) { throw PatchException( "The custom header path must be a folder: " + - customFile.absolutePath, + customFile.absolutePath, ) } @@ -248,7 +252,7 @@ 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 }, + "must be specified but only found: " + customFiles.map { it.name }, ) } @@ -263,8 +267,8 @@ 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, + 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/shorts/HideShortsComponentsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsPatch.kt index 111d2dfd4b..f1d9d66166 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,7 +3,9 @@ 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.methodReference import app.revanced.patcher.extensions.wideLiteral +import app.revanced.patcher.firstMutableMethod import app.revanced.patcher.immutableClassDef import app.revanced.patcher.patch.booleanOption import app.revanced.patcher.patch.bytecodePatch @@ -66,9 +68,9 @@ private val hideShortsComponentsResourcePatch = resourcePatch { // FIXME: The buffer is very different for 20.22+ and these current cannot be hidden. Logger.getLogger(this::class.java.name).warning( "\n!!!" + - "\n!!! Shorts action buttons currently cannot be set hidden when patching 20.22+" + - "\n!!! Patch 20.21.37 or lower if you want to hide Shorts action buttons" + - "\n!!!", + "\n!!! Shorts action buttons currently cannot be set hidden when patching 20.22+" + + "\n!!! Patch 20.21.37 or lower if you want to hide Shorts action buttons" + + "\n!!!", ) } else { preferences.addAll( @@ -188,16 +190,18 @@ val hideShortsComponentsPatch = bytecodePatch( val id = ResourceType.DIMEN["reel_player_right_pivot_v2_size"] - forEachInstructionAsSequence { _, method, i, instruction -> - if (instruction.wideLiteral != id) return@forEachInstructionAsSequence + forEachInstructionAsSequence({ _, method, instruction, index -> + if (instruction.wideLiteral != id) return@forEachInstructionAsSequence null - val targetIndex = method.indexOfFirstInstructionOrThrow(i) { - getReference()?.name == "getDimensionPixelSize" + val targetIndex = method.indexOfFirstInstructionOrThrow(index) { + methodReference?.name == "getDimensionPixelSize" } + 1 val sizeRegister = method.getInstruction(targetIndex).registerA - method.addInstructions( + return@forEachInstructionAsSequence targetIndex to sizeRegister + }) { method, (targetIndex, sizeRegister) -> + firstMutableMethod(method).addInstructions( targetIndex + 1, """ invoke-static { v$sizeRegister }, $FILTER_CLASS_DESCRIPTOR->getSoundButtonSize(I)I @@ -218,24 +222,24 @@ 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", ) } } // Hook to hide the shared navigation bar when the Shorts player is opened. ( - if (is_20_45_or_greater) { - renderBottomNavigationBarParentMethod - } else if (is_19_41_or_greater) { - renderBottomNavigationBarLegacy1941ParentMethod - } else { - legacyRenderBottomNavigationBarLegacyParentMethod - } - ).immutableClassDef.getRenderBottomNavigationBarMethodMatch().addInstruction( - 0, - "invoke-static { p1 }, $FILTER_CLASS_DESCRIPTOR->hideNavigationBar(Ljava/lang/String;)V", - ) + if (is_20_45_or_greater) { + renderBottomNavigationBarParentMethod + } else if (is_19_41_or_greater) { + renderBottomNavigationBarLegacy1941ParentMethod + } else { + legacyRenderBottomNavigationBarLegacyParentMethod + } + ).immutableClassDef.getRenderBottomNavigationBarMethodMatch().addInstruction( + 0, + "invoke-static { p1 }, $FILTER_CLASS_DESCRIPTOR->hideNavigationBar(Ljava/lang/String;)V", + ) // Hide the bottom bar container of the Shorts player. shortsBottomBarContainerMethodMatch.let { diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/MiniplayerPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/MiniplayerPatch.kt index e17b393537..a2effc6a04 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/MiniplayerPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/MiniplayerPatch.kt @@ -62,7 +62,8 @@ private val miniplayerResourcePatch = resourcePatch { private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/MiniplayerPatch;" @Suppress("unused") -val Miniplayer = bytecodePatch( +val miniplayerPatch = bytecodePatch( + name = "Miniplayer", description = "Adds options to change the in-app minimized player.", ) { dependsOn( diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/ReturnYouTubeDislikePatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/ReturnYouTubeDislikePatch.kt index 9cbf3a299a..c7a12b6f59 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/ReturnYouTubeDislikePatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/ReturnYouTubeDislikePatch.kt @@ -164,27 +164,22 @@ val returnYouTubeDislikePatch = bytecodePatch( charSequenceRegister = getInstruction(charSequenceIndex).registerA } - val free1 = findFreeRegister(insertIndex, charSequenceRegister) - val free2 = findFreeRegister(insertIndex, charSequenceRegister, free1) + val conversionContext = findFreeRegister(insertIndex, charSequenceRegister) addInstructionsAtControlFlowLabel( insertIndex, """ # Copy conversion context. - move-object/from16 v$free1, p0 + move-object/from16 v$conversionContext, p0 - # 20.41 field is the abstract superclass. - # Verify it's the expected subclass just in case. - instance-of v$free2, v$free1, ${textComponentConversionContextField.type} - if-eqz v$free2, :ignore + iget-object v$conversionContext, v$conversionContext, $textComponentConversionContextField - check-cast v$free1, $conversionContextClass - invoke-static { v$free1, v$charSequenceRegister }, $EXTENSION_CLASS_DESCRIPTOR->onLithoTextLoaded(Ljava/lang/Object;Ljava/lang/CharSequence;)Ljava/lang/CharSequence; + invoke-static { v$conversionContext, v$charSequenceRegister }, $EXTENSION_CLASS_DESCRIPTOR->onLithoTextLoaded(Ljava/lang/Object;Ljava/lang/CharSequence;)Ljava/lang/CharSequence; move-result-object v$charSequenceRegister :ignore nop - """, + """ ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/SponsorBlockPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/SponsorBlockPatch.kt index 0c85591803..d17441dea9 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/SponsorBlockPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/SponsorBlockPatch.kt @@ -22,7 +22,7 @@ import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.settingsPatch import app.revanced.patches.youtube.shared.getLayoutConstructorMethodMatch import app.revanced.patches.youtube.shared.seekbarMethod -import app.revanced.patches.youtube.shared.seekbarOnDrawMethodMatch +import app.revanced.patches.youtube.shared.getSeekbarOnDrawMethodMatch import app.revanced.patches.youtube.video.information.onCreateHook import app.revanced.patches.youtube.video.information.videoInformationPatch import app.revanced.patches.youtube.video.information.videoTimeHook @@ -111,7 +111,8 @@ private const val EXTENSION_SPONSORBLOCK_VIEW_CONTROLLER_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/sponsorblock/ui/SponsorBlockViewController;" @Suppress("unused") -val SponsorBlock = bytecodePatch( +val sponsorBlockPatch = bytecodePatch( + name = "SponsorBlock", description = "Adds options to enable and configure SponsorBlock, which can skip undesired video segments such as sponsored content.", ) { dependsOn( @@ -164,7 +165,7 @@ val SponsorBlock = bytecodePatch( // Cannot match using original immutable class because // class may have been modified by other patches - seekbarMethod.immutableClassDef.seekbarOnDrawMethodMatch.let { + seekbarMethod.immutableClassDef.getSeekbarOnDrawMethodMatch().let { it.method.apply { // Set seekbar thickness. val thicknessIndex = it[-1] diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/announcements/AnnouncementsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/announcements/AnnouncementsPatch.kt index c4e3d59ed6..e50b59c3d2 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/announcements/AnnouncementsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/announcements/AnnouncementsPatch.kt @@ -13,7 +13,8 @@ private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/announcements/AnnouncementsPatch;" @Suppress("unused") -val Announcements = bytecodePatch( +val announcementsPatch = bytecodePatch( + name = "Announcements", description = "Adds an option to show announcements from ReVanced on app startup.", ) { dependsOn( 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 cbd10c78b6..b6a923d1de 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 @@ -136,7 +136,9 @@ internal val BytecodePatchContext.imageEnumConstructorMethodMatch by composingFi internal val BytecodePatchContext.setEnumMapMethodMatch by composingFirstMethod { instructions( ResourceType.DRAWABLE("yt_fill_bell_black_24"), - afterAtMost(10, method { toString() == "Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;" }), + afterAtMost( + 10, + method { toString() == "Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;" }), afterAtMost( 10, method { toString() == "Ljava/util/EnumMap;->put(Ljava/lang/Enum;Ljava/lang/Object;)Ljava/lang/Object;" }, diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/shared/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/shared/Fingerprints.kt index 6bb0e60754..5072656462 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/shared/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/shared/Fingerprints.kt @@ -113,7 +113,7 @@ internal val BytecodePatchContext.seekbarMethod by gettingFirstMethodDeclarative /** * Matches to _mutable_ class found in [seekbarMethod]. */ -internal val ClassDef.seekbarOnDrawMethodMatch by ClassDefComposing.composingFirstMethod { +internal fun ClassDef.getSeekbarOnDrawMethodMatch() = firstMethodComposite { name("onDraw") instructions( method { toString() == "Ljava/lang/Math;->round(F)I" }, diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/video/codecs/DisableVideoCodecsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/video/codecs/DisableVideoCodecsPatch.kt index de45b8cc65..a7f027fd73 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/video/codecs/DisableVideoCodecsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/video/codecs/DisableVideoCodecsPatch.kt @@ -46,7 +46,8 @@ val disableVideoCodecsPatch = bytecodePatch( method.replaceInstruction( index, - "invoke-static/range { v$register .. v$register }, $EXTENSION_CLASS_DESCRIPTOR->" + "disableHdrVideo(Landroid/view/Display\$HdrCapabilities;)[I", + "invoke-static/range { v$register .. v$register }, $EXTENSION_CLASS_DESCRIPTOR->" + + $$"disableHdrVideo(Landroid/view/Display$HdrCapabilities;)[I", ) }, ), diff --git a/patches/src/main/kotlin/app/revanced/util/BytecodeUtils.kt b/patches/src/main/kotlin/app/revanced/util/BytecodeUtils.kt index 78a784e89c..b29c2485dd 100644 --- a/patches/src/main/kotlin/app/revanced/util/BytecodeUtils.kt +++ b/patches/src/main/kotlin/app/revanced/util/BytecodeUtils.kt @@ -18,6 +18,7 @@ import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode.* import com.android.tools.smali.dexlib2.analysis.reflection.util.ReflectionUtils import com.android.tools.smali.dexlib2.formatter.DexFormatter +import com.android.tools.smali.dexlib2.iface.ClassDef import com.android.tools.smali.dexlib2.iface.Method import com.android.tools.smali.dexlib2.iface.instruction.* import com.android.tools.smali.dexlib2.iface.reference.FieldReference @@ -27,8 +28,8 @@ import com.android.tools.smali.dexlib2.iface.reference.StringReference import com.android.tools.smali.dexlib2.iface.value.* import com.android.tools.smali.dexlib2.immutable.ImmutableField import com.android.tools.smali.dexlib2.immutable.value.* -import com.android.tools.smali.dexlib2.util.MethodUtil import java.util.* +import kotlin.collections.ArrayDeque /** * Starting from and including the instruction at index [startIndex], @@ -89,7 +90,7 @@ fun Method.findFreeRegister(startIndex: Int, vararg registersToExclude: Int): In // 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", + "a free register could be found from startIndex: $startIndex", ) } @@ -109,7 +110,7 @@ fun Method.findFreeRegister(startIndex: Int, vararg registersToExclude: Int): In // In practice this never occurs. throw IllegalArgumentException( "Could not find a free register from startIndex: " + - "$startIndex excluding: $registersToExclude", + "$startIndex excluding: $registersToExclude", ) } } @@ -193,7 +194,7 @@ private fun Method.findInstructionIndexFromToString(fieldName: String): Int { val stringUsageIndex = indexOfFirstInstruction(stringIndex) { val reference = getReference() reference?.definingClass == "Ljava/lang/StringBuilder;" && - (this as? FiveRegisterInstruction)?.registerD == stringRegister + (this as? FiveRegisterInstruction)?.registerD == stringRegister } if (stringUsageIndex < 0) { throw IllegalArgumentException("Could not find StringBuilder usage in: $this") @@ -345,7 +346,8 @@ fun MutableMethod.addInstructionsAtControlFlowLabel( * @throws PatchException if the resource cannot be found. * @see [indexOfFirstResourceIdOrThrow], [indexOfFirstLiteralInstructionReversed] */ -fun Method.indexOfFirstResourceId(resourceName: String): Int = indexOfFirstLiteralInstruction(ResourceType.ID[resourceName]) +fun Method.indexOfFirstResourceId(resourceName: String): Int = + indexOfFirstLiteralInstruction(ResourceType.ID[resourceName]) /** * Get the index of the first instruction with the id of the given resource name or throw a [PatchException]. @@ -458,7 +460,8 @@ fun Method.indexOfFirstLiteralInstructionReversedOrThrow(literal: Long): Int { * @return the last literal instruction with the value, or -1 if not found. * @see indexOfFirstLiteralInstructionOrThrow */ -fun Method.indexOfFirstLiteralInstructionReversed(literal: Float) = indexOfFirstLiteralInstructionReversed(literal.toRawBits().toLong()) +fun Method.indexOfFirstLiteralInstructionReversed(literal: Float) = + indexOfFirstLiteralInstructionReversed(literal.toRawBits().toLong()) /** * Find the index of the last wide literal instruction with the given float value, @@ -478,7 +481,8 @@ fun Method.indexOfFirstLiteralInstructionReversedOrThrow(literal: Float): Int { * @return the last literal instruction with the value, or -1 if not found. * @see indexOfFirstLiteralInstructionOrThrow */ -fun Method.indexOfFirstLiteralInstructionReversed(literal: Double) = indexOfFirstLiteralInstructionReversed(literal.toRawBits()) +fun Method.indexOfFirstLiteralInstructionReversed(literal: Double) = + indexOfFirstLiteralInstructionReversed(literal.toRawBits()) /** * Find the index of the last wide literal instruction with the given double value, @@ -550,9 +554,10 @@ fun Method.indexOfFirstInstruction(targetOpcode: Opcode): Int = indexOfFirstInst * @return The index of the first opcode specified, or -1 if not found. * @see indexOfFirstInstructionOrThrow */ -fun Method.indexOfFirstInstruction(startIndex: Int = 0, targetOpcode: Opcode): Int = indexOfFirstInstruction(startIndex) { - opcode == targetOpcode -} +fun Method.indexOfFirstInstruction(startIndex: Int = 0, targetOpcode: Opcode): Int = + indexOfFirstInstruction(startIndex) { + opcode == targetOpcode + } /** * Get the index of the first [Instruction] that matches the predicate, starting from [startIndex]. @@ -587,9 +592,10 @@ fun Method.indexOfFirstInstructionOrThrow(targetOpcode: Opcode): Int = indexOfFi * @throws PatchException * @see indexOfFirstInstruction */ -fun Method.indexOfFirstInstructionOrThrow(startIndex: Int = 0, targetOpcode: Opcode): Int = indexOfFirstInstructionOrThrow(startIndex) { - opcode == targetOpcode -} +fun Method.indexOfFirstInstructionOrThrow(startIndex: Int = 0, targetOpcode: Opcode): Int = + indexOfFirstInstructionOrThrow(startIndex) { + opcode == targetOpcode + } /** * Get the index of the first [Instruction] that matches the predicate, starting from [startIndex]. @@ -615,9 +621,10 @@ fun Method.indexOfFirstInstructionOrThrow(startIndex: Int = 0, filter: Instructi * @return -1 if the instruction is not found. * @see indexOfFirstInstructionReversedOrThrow */ -fun Method.indexOfFirstInstructionReversed(startIndex: Int? = null, targetOpcode: Opcode): Int = indexOfFirstInstructionReversed(startIndex) { - opcode == targetOpcode -} +fun Method.indexOfFirstInstructionReversed(startIndex: Int? = null, targetOpcode: Opcode): Int = + indexOfFirstInstructionReversed(startIndex) { + opcode == targetOpcode + } /** * Get the index of matching instruction, @@ -654,9 +661,10 @@ fun Method.indexOfFirstInstructionReversed(targetOpcode: Opcode): Int = indexOfF * @return The index of the instruction. * @see indexOfFirstInstructionReversed */ -fun Method.indexOfFirstInstructionReversedOrThrow(startIndex: Int? = null, targetOpcode: Opcode): Int = indexOfFirstInstructionReversedOrThrow(startIndex) { - opcode == targetOpcode -} +fun Method.indexOfFirstInstructionReversedOrThrow(startIndex: Int? = null, targetOpcode: Opcode): Int = + indexOfFirstInstructionReversedOrThrow(startIndex) { + opcode == targetOpcode + } /** * Get the index of matching instruction, @@ -713,7 +721,8 @@ fun Method.findInstructionIndicesReversedOrThrow(filter: Instruction.() -> Boole * _Returns an empty list if no indices are found_ * @see findInstructionIndicesReversedOrThrow */ -fun Method.findInstructionIndicesReversed(opcode: Opcode): List = findInstructionIndicesReversed { this.opcode == opcode } +fun Method.findInstructionIndicesReversed(opcode: Opcode): List = + findInstructionIndicesReversed { this.opcode == opcode } /** * @return An immutable list of indices of the opcode in reverse order. @@ -779,33 +788,30 @@ internal fun MutableMethod.insertLiteralOverride(literalIndex: Int, override: Bo /** * 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. + * + * @param match A function that matches instructions. If a match is found, it returns a value of type [T], otherwise null. + * @param transform A function that transforms the matched instruction using the mutable method and the matched value + * of type [T]. */ -fun BytecodePatchContext.forEachInstructionAsSequence( - block: (classDef: MutableClassDef, method: MutableMethod, matchingIndex: Int, instruction: Instruction) -> Unit, +fun BytecodePatchContext.forEachInstructionAsSequence( + match: (classDef: ClassDef, method: Method, instruction: Instruction, index: Int) -> T?, + transform: (MutableMethod, T) -> Unit ) { - classDefs.asSequence().flatMap { classDef -> - val mutableClassDef by lazy { classDefs.getOrReplaceMutable(classDef) } + classDefs.flatMap { classDef -> + classDef.methods.mapNotNull { method -> + val matches = method.instructionsOrNull?.mapIndexedNotNull { index, instruction -> + match(classDef, method, instruction, index) + } ?: return@mapNotNull null - classDef.methods.asSequence().flatMap { method -> - val instructions = - method.instructionsOrNull as? List ?: return@flatMap emptySequence<() -> Unit>() - - val mutableMethod by lazy { mutableClassDef.firstMutableMethod(method) } - - instructions.asReversed().asSequence().mapIndexed { index, instruction -> - { - block( - mutableClassDef, - mutableMethod, - instructions.size - 1 - index, - instruction, - ) - } // Reverse indices again. - } + if (matches.any()) method to matches else null } - }.forEach { it() } + }.forEach { (method, matches) -> + + val method = firstMutableMethod(method) + val matches = matches.toCollection(ArrayDeque()) + + while (!matches.isEmpty()) transform(method, matches.removeLast()) + } } private fun MutableMethod.checkReturnType(expectedTypes: Iterable>) {