Merge branch 'dev' into revanced-extended

This commit is contained in:
inotia00 2024-09-29 00:26:24 +09:00
commit b725e54aee
363 changed files with 38650 additions and 15715 deletions

View File

@ -44,6 +44,8 @@ ReVanced Extended Patches.
| `Hide layout components` | Adds options to hide general layout components. | 18.29.38 ~ 19.16.39 | | `Hide layout components` | Adds options to hide general layout components. | 18.29.38 ~ 19.16.39 |
| `Hide player buttons` | Adds options to hide buttons in the video player. | 18.29.38 ~ 19.16.39 | | `Hide player buttons` | Adds options to hide buttons in the video player. | 18.29.38 ~ 19.16.39 |
| `Hide player flyout menu` | Adds options to hide player flyout menu components. | 18.29.38 ~ 19.16.39 | | `Hide player flyout menu` | Adds options to hide player flyout menu components. | 18.29.38 ~ 19.16.39 |
| `Hide shortcuts` | Remove, at compile time, the app shortcuts that appears when app icon is long pressed. | 18.29.38 ~ 19.16.39 |
| `Hook YouTube Music actions` | Adds support for opening music in RVX Music using the in-app YouTube Music button. | 18.29.38 ~ 19.16.39 |
| `Hook download actions` | Adds support to download videos with an external downloader app using the in-app download button. | 18.29.38 ~ 19.16.39 | | `Hook download actions` | Adds support to download videos with an external downloader app using the in-app download button. | 18.29.38 ~ 19.16.39 |
| `Layout switch` | Adds an option to spoof the dpi in order to use a tablet or phone layout. | 18.29.38 ~ 19.16.39 | | `Layout switch` | Adds an option to spoof the dpi in order to use a tablet or phone layout. | 18.29.38 ~ 19.16.39 |
| `MaterialYou` | Applies the MaterialYou theme for Android 12+ devices. | 18.29.38 ~ 19.16.39 | | `MaterialYou` | Applies the MaterialYou theme for Android 12+ devices. | 18.29.38 ~ 19.16.39 |
@ -66,7 +68,7 @@ ReVanced Extended Patches.
| `Toolbar components` | Adds options to hide or change components located on the toolbar, such as toolbar buttons, search bar, and header. | 18.29.38 ~ 19.16.39 | | `Toolbar components` | Adds options to hide or change components located on the toolbar, such as toolbar buttons, search bar, and header. | 18.29.38 ~ 19.16.39 |
| `Translations for YouTube` | Add translations or remove string resources. | 18.29.38 ~ 19.16.39 | | `Translations for YouTube` | Add translations or remove string resources. | 18.29.38 ~ 19.16.39 |
| `Video playback` | Adds options to customize settings related to video playback, such as default video quality and playback speed. | 18.29.38 ~ 19.16.39 | | `Video playback` | Adds options to customize settings related to video playback, such as default video quality and playback speed. | 18.29.38 ~ 19.16.39 |
| `Visual preferences icons` | Adds icons to specific preferences in the settings. | 18.29.38 ~ 19.16.39 | | `Visual preferences icons for YouTube` | Adds icons to specific preferences in the settings. | 18.29.38 ~ 19.16.39 |
| `Watch history` | Adds an option to change the domain of the watch history or check its status. | 18.29.38 ~ 19.16.39 | | `Watch history` | Adds an option to change the domain of the watch history or check its status. | 18.29.38 ~ 19.16.39 |
</details> </details>
@ -75,41 +77,42 @@ ReVanced Extended Patches.
| 💊 Patch | 📜 Description | 🏹 Target Version | | 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:| |:--------:|:--------------:|:-----------------:|
| `Amoled` | Applies a pure black theme to some components. | 6.29.58 ~ 7.17.51 | | `Amoled` | Applies a pure black theme to some components. | 6.20.51 ~ 7.16.53 |
| `Bitrate default value` | Sets the audio quality to 'Always High' when you first install the app. | 6.29.58 ~ 7.17.51 | | `Bitrate default value` | Sets the audio quality to 'Always High' when you first install the app. | 6.20.51 ~ 7.16.53 |
| `Bypass image region restrictions` | Adds an option to use a different host for static images, so that images blocked in some countries can be received. | 6.29.58 ~ 7.17.51 | | `Bypass image region restrictions` | Adds an option to use a different host for static images, so that images blocked in some countries can be received. | 6.20.51 ~ 7.16.53 |
| `Certificate spoof` | Enables YouTube Music to work with Android Auto by spoofing the YouTube Music certificate. | 6.29.58 ~ 7.17.51 | | `Certificate spoof` | Enables YouTube Music to work with Android Auto by spoofing the YouTube Music certificate. | 6.20.51 ~ 7.16.53 |
| `Change share sheet` | Add option to change from in-app share sheet to system share sheet. | 6.29.58 ~ 7.17.51 | | `Change share sheet` | Add option to change from in-app share sheet to system share sheet. | 6.20.51 ~ 7.16.53 |
| `Change start page` | Adds an option to set which page the app opens in instead of the homepage. | 6.29.58 ~ 7.17.51 | | `Change start page` | Adds an option to set which page the app opens in instead of the homepage. | 6.20.51 ~ 7.16.53 |
| `Custom branding icon for YouTube Music` | Changes the YouTube Music app icon to the icon specified in options.json. | 6.29.58 ~ 7.17.51 | | `Custom branding icon for YouTube Music` | Changes the YouTube Music app icon to the icon specified in options.json. | 6.20.51 ~ 7.16.53 |
| `Custom branding name for YouTube Music` | Renames the YouTube Music app to the name specified in options.json. | 6.29.58 ~ 7.17.51 | | `Custom branding name for YouTube Music` | Renames the YouTube Music app to the name specified in options.json. | 6.20.51 ~ 7.16.53 |
| `Custom header for YouTube Music` | Applies a custom header in the top left corner within the app. | 6.29.58 ~ 7.17.51 | | `Custom header for YouTube Music` | Applies a custom header in the top left corner within the app. | 6.20.51 ~ 7.16.53 |
| `Disable Cairo splash animation` | Adds an option to disable Cairo splash animation. | 7.06.54 ~ 7.17.51 | | `Disable Cairo splash animation` | Adds an option to disable Cairo splash animation. | 7.06.54 ~ 7.16.53 |
| `Disable auto captions` | Adds an option to disable captions from being automatically enabled. | 6.29.58 ~ 7.17.51 | | `Disable auto captions` | Adds an option to disable captions from being automatically enabled. | 6.20.51 ~ 7.16.53 |
| `Disable dislike redirection` | Adds an option to disable redirection to the next track when clicking the Dislike button. | 6.29.58 ~ 7.17.51 | | `Disable dislike redirection` | Adds an option to disable redirection to the next track when clicking the Dislike button. | 6.20.51 ~ 7.16.53 |
| `Enable OPUS codec` | Adds an options to enable the OPUS audio codec if the player response includes. | 6.29.58 ~ 7.17.51 | | `Enable OPUS codec` | Adds an options to enable the OPUS audio codec if the player response includes. | 6.20.51 ~ 7.16.53 |
| `Enable debug logging` | Adds an option to enable debug logging. | 6.29.58 ~ 7.17.51 | | `Enable debug logging` | Adds an option to enable debug logging. | 6.20.51 ~ 7.16.53 |
| `Enable landscape mode` | Adds an option to enable landscape mode when rotating the screen on phones. | 6.29.58 ~ 7.17.51 | | `Enable landscape mode` | Adds an option to enable landscape mode when rotating the screen on phones. | 6.20.51 ~ 7.16.53 |
| `Flyout menu components` | Adds options to hide or change flyout menu components. | 6.29.58 ~ 7.17.51 | | `Flyout menu components` | Adds options to hide or change flyout menu components. | 6.20.51 ~ 7.16.53 |
| `GmsCore support` | Allows patched Google apps to run without root and under a different package name by using GmsCore instead of Google Play Services. | 6.29.58 ~ 7.17.51 | | `GmsCore support` | Allows patched Google apps to run without root and under a different package name by using GmsCore instead of Google Play Services. | 6.20.51 ~ 7.16.53 |
| `Hide account components` | Adds options to hide components related to the account menu. | 6.29.58 ~ 7.17.51 | | `Hide account components` | Adds options to hide components related to the account menu. | 6.20.51 ~ 7.16.53 |
| `Hide action bar components` | Adds options to hide action bar components and replace the offline download button with an external download button. | 6.29.58 ~ 7.17.51 | | `Hide action bar components` | Adds options to hide action bar components and replace the offline download button with an external download button. | 6.20.51 ~ 7.16.53 |
| `Hide ads` | Adds options to hide ads. | 6.29.58 ~ 7.17.51 | | `Hide ads` | Adds options to hide ads. | 6.20.51 ~ 7.16.53 |
| `Hide layout components` | Adds options to hide general layout components. | 6.29.58 ~ 7.17.51 | | `Hide layout components` | Adds options to hide general layout components. | 6.20.51 ~ 7.16.53 |
| `Hide overlay filter` | Removes, at compile time, the dark overlay that appears when player flyout menus are open. | 6.29.58 ~ 7.17.51 | | `Hide overlay filter` | Removes, at compile time, the dark overlay that appears when player flyout menus are open. | 6.20.51 ~ 7.16.53 |
| `Hide player overlay filter` | Removes, at compile time, the dark overlay that appears when single-tapping in the player. | 6.29.58 ~ 7.17.51 | | `Hide player overlay filter` | Removes, at compile time, the dark overlay that appears when single-tapping in the player. | 6.20.51 ~ 7.16.53 |
| `Navigation bar components` | Adds options to hide or change components related to the navigation bar. | 6.29.58 ~ 7.17.51 | | `Navigation bar components` | Adds options to hide or change components related to the navigation bar. | 6.20.51 ~ 7.16.53 |
| `Player components` | Adds options to hide or change components related to the player. | 6.29.58 ~ 7.17.51 | | `Player components` | Adds options to hide or change components related to the player. | 6.20.51 ~ 7.16.53 |
| `Remove background playback restrictions` | Removes restrictions on background playback, including for kids videos. | 6.29.58 ~ 7.17.51 | | `Remove background playback restrictions` | Removes restrictions on background playback, including for kids videos. | 6.20.51 ~ 7.16.53 |
| `Remove viewer discretion dialog` | Adds an option to remove the dialog that appears when opening a video that has been age-restricted by accepting it automatically. This does not bypass the age restriction. | 6.29.58 ~ 7.17.51 | | `Remove viewer discretion dialog` | Adds an option to remove the dialog that appears when opening a video that has been age-restricted by accepting it automatically. This does not bypass the age restriction. | 6.20.51 ~ 7.16.53 |
| `Restore old style library shelf` | Adds an option to return the Library tab to the old style. | 6.29.58 ~ 7.17.51 | | `Restore old style library shelf` | Adds an option to return the Library tab to the old style. | 6.20.51 ~ 7.16.53 |
| `Return YouTube Dislike` | Adds an option to show the dislike count of songs using the Return YouTube Dislike API. | 6.29.58 ~ 7.17.51 | | `Return YouTube Dislike` | Adds an option to show the dislike count of songs using the Return YouTube Dislike API. | 6.20.51 ~ 7.16.53 |
| `Sanitize sharing links` | Adds an option to remove tracking query parameters from URLs when sharing links. | 6.29.58 ~ 7.17.51 | | `Sanitize sharing links` | Adds an option to remove tracking query parameters from URLs when sharing links. | 6.20.51 ~ 7.16.53 |
| `Settings for YouTube Music` | Applies mandatory patches to implement ReVanced Extended settings into the application. | 6.29.58 ~ 7.17.51 | | `Settings for YouTube Music` | Applies mandatory patches to implement ReVanced Extended settings into the application. | 6.20.51 ~ 7.16.53 |
| `SponsorBlock` | Adds options to enable and configure SponsorBlock, which can skip undesired video segments, such as non-music sections. | 6.29.58 ~ 7.17.51 | | `SponsorBlock` | Adds options to enable and configure SponsorBlock, which can skip undesired video segments, such as non-music sections. | 6.20.51 ~ 7.16.53 |
| `Spoof app version` | Adds options to spoof the YouTube Music client version. This can remove the radio mode restriction in Canadian regions or disable real-time lyrics. | 6.29.58 ~ 7.17.51 | | `Spoof app version` | Adds options to spoof the YouTube Music client version. This can remove the radio mode restriction in Canadian regions or disable real-time lyrics. | 6.20.51 ~ 7.16.53 |
| `Translations for YouTube Music` | Add translations or remove string resources. | 6.29.58 ~ 7.17.51 | | `Translations for YouTube Music` | Add translations or remove string resources. | 6.20.51 ~ 7.16.53 |
| `Video playback` | Adds options to customize settings related to video playback, such as default video quality and playback speed. | 6.29.58 ~ 7.17.51 | | `Video playback` | Adds options to customize settings related to video playback, such as default video quality and playback speed. | 6.20.51 ~ 7.16.53 |
| `Visual preferences icons for YouTube Music` | Adds icons to specific preferences in the settings. | 6.20.51 ~ 7.16.53 |
</details> </details>
### [📦 `com.reddit.frontpage`](https://play.google.com/store/apps/details?id=com.reddit.frontpage) ### [📦 `com.reddit.frontpage`](https://play.google.com/store/apps/details?id=com.reddit.frontpage)
@ -169,12 +172,11 @@ Example:
{ {
"name": "com.google.android.apps.youtube.music", "name": "com.google.android.apps.youtube.music",
"versions": [ "versions": [
"6.29.58", "6.20.51",
"6.33.52", "6.29.59",
"6.42.55", "6.42.55",
"6.51.53", "6.51.53",
"7.16.53", "7.16.53"
"7.17.51"
] ]
} }
], ],

View File

@ -1,4 +1,4 @@
org.gradle.parallel = true org.gradle.parallel = true
org.gradle.caching = true org.gradle.caching = true
kotlin.code.style = official kotlin.code.style = official
version = 4.13.1 version = 4.14.1

File diff suppressed because one or more lines are too long

View File

@ -14,12 +14,14 @@ import app.revanced.patches.music.utils.integrations.Constants.ACCOUNT_CLASS_DES
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch
import app.revanced.patches.music.utils.settings.CategoryType import app.revanced.patches.music.utils.settings.CategoryType
import app.revanced.patches.music.utils.settings.SettingsPatch import app.revanced.patches.music.utils.settings.SettingsPatch
import app.revanced.util.getTargetIndexWithMethodReferenceNameOrThrow import app.revanced.util.getReference
import app.revanced.util.getTargetIndexWithReferenceOrThrow import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.patch.BaseBytecodePatch import app.revanced.util.patch.BaseBytecodePatch
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
@Suppress("unused") @Suppress("unused")
object AccountComponentsPatch : BaseBytecodePatch( object AccountComponentsPatch : BaseBytecodePatch(
@ -43,8 +45,14 @@ object AccountComponentsPatch : BaseBytecodePatch(
MenuEntryFingerprint.resultOrThrow().let { MenuEntryFingerprint.resultOrThrow().let {
it.mutableMethod.apply { it.mutableMethod.apply {
val textIndex = getTargetIndexWithMethodReferenceNameOrThrow("setText") val textIndex = indexOfFirstInstructionOrThrow {
val viewIndex = getTargetIndexWithMethodReferenceNameOrThrow("addView") opcode == Opcode.INVOKE_VIRTUAL &&
getReference<MethodReference>()?.name == "setText"
}
val viewIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.INVOKE_VIRTUAL &&
getReference<MethodReference>()?.name == "addView"
}
val textRegister = getInstruction<FiveRegisterInstruction>(textIndex).registerD val textRegister = getInstruction<FiveRegisterInstruction>(textIndex).registerD
val viewRegister = getInstruction<FiveRegisterInstruction>(viewIndex).registerD val viewRegister = getInstruction<FiveRegisterInstruction>(viewIndex).registerD
@ -64,9 +72,14 @@ object AccountComponentsPatch : BaseBytecodePatch(
AccountSwitcherAccessibilityLabelFingerprint.resultOrThrow().let { result -> AccountSwitcherAccessibilityLabelFingerprint.resultOrThrow().let { result ->
result.mutableMethod.apply { result.mutableMethod.apply {
val textColorIndex = getTargetIndexWithMethodReferenceNameOrThrow("setTextColor") val textColorIndex = indexOfFirstInstructionOrThrow {
val setVisibilityIndex = opcode == Opcode.INVOKE_VIRTUAL &&
getTargetIndexWithMethodReferenceNameOrThrow(textColorIndex, "setVisibility") getReference<MethodReference>()?.name == "setTextColor"
}
val setVisibilityIndex = indexOfFirstInstructionOrThrow(textColorIndex) {
opcode == Opcode.INVOKE_VIRTUAL &&
getReference<MethodReference>()?.name == "setVisibility"
}
val textViewInstruction = val textViewInstruction =
getInstruction<FiveRegisterInstruction>(setVisibilityIndex) getInstruction<FiveRegisterInstruction>(setVisibilityIndex)
@ -98,8 +111,12 @@ object AccountComponentsPatch : BaseBytecodePatch(
TermsOfServiceFingerprint.resultOrThrow().let { TermsOfServiceFingerprint.resultOrThrow().let {
it.mutableMethod.apply { it.mutableMethod.apply {
val insertIndex = val insertIndex = indexOfFirstInstructionOrThrow {
getTargetIndexWithReferenceOrThrow("/PrivacyTosFooter;->setVisibility(I)V") val reference = getReference<MethodReference>()
opcode == Opcode.INVOKE_VIRTUAL &&
reference?.name == "setVisibility" &&
reference.definingClass.endsWith("/PrivacyTosFooter;")
}
val visibilityRegister = val visibilityRegister =
getInstruction<FiveRegisterInstruction>(insertIndex).registerD getInstruction<FiveRegisterInstruction>(insertIndex).registerD

View File

@ -15,10 +15,9 @@ import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.LikeDis
import app.revanced.patches.music.utils.settings.CategoryType import app.revanced.patches.music.utils.settings.CategoryType
import app.revanced.patches.music.utils.settings.SettingsPatch import app.revanced.patches.music.utils.settings.SettingsPatch
import app.revanced.patches.music.video.information.VideoInformationPatch import app.revanced.patches.music.video.information.VideoInformationPatch
import app.revanced.util.getTargetIndexWithMethodReferenceNameOrThrow import app.revanced.util.getReference
import app.revanced.util.getTargetIndexWithReferenceOrThrow
import app.revanced.util.getWideLiteralInstructionIndex
import app.revanced.util.indexOfFirstInstructionOrThrow import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow
import app.revanced.util.patch.BaseBytecodePatch import app.revanced.util.patch.BaseBytecodePatch
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
@ -26,6 +25,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
import kotlin.math.min import kotlin.math.min
@Suppress("unused") @Suppress("unused")
@ -48,7 +48,10 @@ object ActionBarComponentsPatch : BaseBytecodePatch(
it.mutableMethod.apply { it.mutableMethod.apply {
// hook download button // hook download button
val addViewIndex = getTargetIndexWithMethodReferenceNameOrThrow("addView") val addViewIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.INVOKE_VIRTUAL &&
getReference<MethodReference>()?.name == "addView"
}
val addViewRegister = val addViewRegister =
getInstruction<FiveRegisterInstruction>(addViewIndex).registerD getInstruction<FiveRegisterInstruction>(addViewIndex).registerD
@ -83,10 +86,15 @@ object ActionBarComponentsPatch : BaseBytecodePatch(
removeInstruction(replaceIndex) removeInstruction(replaceIndex)
// hide action button // hide action button
val hasNextIndex = getTargetIndexWithMethodReferenceNameOrThrow("hasNext") val hasNextIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.INVOKE_INTERFACE &&
getReference<MethodReference>()?.name == "hasNext"
}
val freeRegister = min(implementation!!.registerCount - parameters.size - 2, 15) val freeRegister = min(implementation!!.registerCount - parameters.size - 2, 15)
val spannedIndex = getTargetIndexWithReferenceOrThrow(")Landroid/text/Spanned;") val spannedIndex = indexOfFirstInstructionOrThrow {
getReference<MethodReference>()?.returnType == "Landroid/text/Spanned;"
}
val spannedRegister = val spannedRegister =
getInstruction<FiveRegisterInstruction>(spannedIndex).registerC getInstruction<FiveRegisterInstruction>(spannedIndex).registerC
val spannedReference = getInstruction<ReferenceInstruction>(spannedIndex).reference val spannedReference = getInstruction<ReferenceInstruction>(spannedIndex).reference
@ -124,7 +132,8 @@ object ActionBarComponentsPatch : BaseBytecodePatch(
LikeDislikeContainerFingerprint.resultOrThrow().let { LikeDislikeContainerFingerprint.resultOrThrow().let {
it.mutableMethod.apply { it.mutableMethod.apply {
val insertIndex = getWideLiteralInstructionIndex(LikeDislikeContainer) + 2 val insertIndex =
indexOfFirstWideLiteralInstructionValueOrThrow(LikeDislikeContainer) + 2
val insertRegister = getInstruction<OneRegisterInstruction>(insertIndex).registerA val insertRegister = getInstruction<OneRegisterInstruction>(insertIndex).registerA
addInstruction( addInstruction(

View File

@ -22,19 +22,21 @@ import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.ButtonContainer import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.ButtonContainer
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.FloatingLayout import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.FloatingLayout
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.InterstitialsContainer import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.InterstitialsContainer
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.PrivacyTosFooter
import app.revanced.patches.music.utils.settings.CategoryType import app.revanced.patches.music.utils.settings.CategoryType
import app.revanced.patches.music.utils.settings.SettingsPatch import app.revanced.patches.music.utils.settings.SettingsPatch
import app.revanced.patches.shared.litho.LithoFilterPatch import app.revanced.patches.shared.litho.LithoFilterPatch
import app.revanced.util.getTargetIndexOrThrow import app.revanced.util.getReference
import app.revanced.util.getTargetIndexWithReferenceOrThrow
import app.revanced.util.getWalkerMethod import app.revanced.util.getWalkerMethod
import app.revanced.util.getWideLiteralInstructionIndex import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow
import app.revanced.util.patch.BaseBytecodePatch import app.revanced.util.patch.BaseBytecodePatch
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
@Suppress("unused") @Suppress("unused")
object AdsPatch : BaseBytecodePatch( object AdsPatch : BaseBytecodePatch(
@ -61,9 +63,6 @@ object AdsPatch : BaseBytecodePatch(
private const val ADS_FILTER_CLASS_DESCRIPTOR = private const val ADS_FILTER_CLASS_DESCRIPTOR =
"$COMPONENTS_PATH/AdsFilter;" "$COMPONENTS_PATH/AdsFilter;"
private const val FULLSCREEN_ADS_FILTER_CLASS_DESCRIPTOR =
"${app.revanced.patches.shared.integrations.Constants.COMPONENTS_PATH}/FullscreenAdsFilter;"
private const val PREMIUM_PROMOTION_POP_UP_CLASS_DESCRIPTOR = private const val PREMIUM_PROMOTION_POP_UP_CLASS_DESCRIPTOR =
"$ADS_PATH/PremiumPromotionPatch;" "$ADS_PATH/PremiumPromotionPatch;"
@ -82,7 +81,7 @@ object AdsPatch : BaseBytecodePatch(
// litho view, used in 'ShowDialogCommandOuterClass' in innertube // litho view, used in 'ShowDialogCommandOuterClass' in innertube
ShowDialogCommandFingerprint ShowDialogCommandFingerprint
.resultOrThrow() .resultOrThrow()
.hookLithoFullscreenAds(context) .hookLithoFullscreenAds()
// endregion // endregion
@ -90,7 +89,7 @@ object AdsPatch : BaseBytecodePatch(
FloatingLayoutFingerprint.resultOrThrow().let { FloatingLayoutFingerprint.resultOrThrow().let {
it.mutableMethod.apply { it.mutableMethod.apply {
val targetIndex = getWideLiteralInstructionIndex(FloatingLayout) + 2 val targetIndex = indexOfFirstWideLiteralInstructionValueOrThrow(FloatingLayout) + 2
val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
addInstruction( addInstruction(
@ -106,7 +105,8 @@ object AdsPatch : BaseBytecodePatch(
NotifierShelfFingerprint.resultOrThrow().let { NotifierShelfFingerprint.resultOrThrow().let {
it.mutableMethod.apply { it.mutableMethod.apply {
val linearLayoutIndex = getWideLiteralInstructionIndex(ButtonContainer) + 3 val linearLayoutIndex =
indexOfFirstWideLiteralInstructionValueOrThrow(ButtonContainer) + 3
val linearLayoutRegister = val linearLayoutRegister =
getInstruction<OneRegisterInstruction>(linearLayoutIndex).registerA getInstruction<OneRegisterInstruction>(linearLayoutIndex).registerA
@ -138,16 +138,20 @@ object AdsPatch : BaseBytecodePatch(
AccountMenuFooterFingerprint.resultOrThrow().let { AccountMenuFooterFingerprint.resultOrThrow().let {
it.mutableMethod.apply { it.mutableMethod.apply {
val constIndex = val constIndex =
getWideLiteralInstructionIndex(SharedResourceIdPatch.PrivacyTosFooter) indexOfFirstWideLiteralInstructionValueOrThrow(PrivacyTosFooter)
val walkerIndex = getTargetIndexOrThrow(constIndex + 2, Opcode.INVOKE_VIRTUAL) val walkerIndex =
val viewIndex = getTargetIndexOrThrow(constIndex, Opcode.IGET_OBJECT) indexOfFirstInstructionOrThrow(constIndex + 2, Opcode.INVOKE_VIRTUAL)
val viewIndex = indexOfFirstInstructionOrThrow(constIndex, Opcode.IGET_OBJECT)
val viewReference = val viewReference =
getInstruction<ReferenceInstruction>(viewIndex).reference.toString() getInstruction<ReferenceInstruction>(viewIndex).reference.toString()
val walkerMethod = getWalkerMethod(context, walkerIndex) val walkerMethod = getWalkerMethod(context, walkerIndex)
walkerMethod.apply { walkerMethod.apply {
val insertIndex = getTargetIndexWithReferenceOrThrow(viewReference) val insertIndex = indexOfFirstInstructionOrThrow {
val nullCheckIndex = getTargetIndexOrThrow(insertIndex - 1, Opcode.IF_NEZ) getReference<FieldReference>()?.toString() == viewReference
}
val nullCheckIndex =
indexOfFirstInstructionOrThrow(insertIndex - 1, Opcode.IF_NEZ)
val nullCheckRegister = val nullCheckRegister =
getInstruction<OneRegisterInstruction>(nullCheckIndex).registerA getInstruction<OneRegisterInstruction>(nullCheckIndex).registerA
@ -174,19 +178,12 @@ object AdsPatch : BaseBytecodePatch(
// endregion // endregion
LithoFilterPatch.addFilter(ADS_FILTER_CLASS_DESCRIPTOR) LithoFilterPatch.addFilter(ADS_FILTER_CLASS_DESCRIPTOR)
LithoFilterPatch.addFilter(FULLSCREEN_ADS_FILTER_CLASS_DESCRIPTOR)
SettingsPatch.addSwitchPreference( SettingsPatch.addSwitchPreference(
CategoryType.ADS, CategoryType.ADS,
"revanced_hide_fullscreen_ads", "revanced_hide_fullscreen_ads",
"true" "true"
) )
SettingsPatch.addSwitchPreference(
CategoryType.ADS,
"revanced_hide_fullscreen_ads_type",
"true",
"revanced_hide_fullscreen_ads"
)
SettingsPatch.addSwitchPreference( SettingsPatch.addSwitchPreference(
CategoryType.ADS, CategoryType.ADS,
"revanced_hide_general_ads", "revanced_hide_general_ads",

View File

@ -4,14 +4,14 @@ import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.ButtonContainer import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.ButtonContainer
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.MusicNotifierShelf import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.MusicNotifierShelf
import app.revanced.util.containsWideLiteralInstructionIndex import app.revanced.util.containsWideLiteralInstructionValue
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
internal object NotifierShelfFingerprint : MethodFingerprint( internal object NotifierShelfFingerprint : MethodFingerprint(
returnType = "V", returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
customFingerprint = { methodDef, _ -> customFingerprint = { methodDef, _ ->
methodDef.containsWideLiteralInstructionIndex(MusicNotifierShelf) methodDef.containsWideLiteralInstructionValue(MusicNotifierShelf)
&& methodDef.containsWideLiteralInstructionIndex(ButtonContainer) && methodDef.containsWideLiteralInstructionValue(ButtonContainer)
} }
) )

View File

@ -1,17 +1,28 @@
package app.revanced.patches.music.ads.general.fingerprints package app.revanced.patches.music.ads.general.fingerprints
import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.SlidingDialogAnimation import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.SlidingDialogAnimation
import app.revanced.util.fingerprint.LiteralValueFingerprint import app.revanced.util.containsWideLiteralInstructionValue
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
internal object ShowDialogCommandFingerprint : LiteralValueFingerprint( internal object ShowDialogCommandFingerprint : MethodFingerprint(
returnType = "V", returnType = "V",
parameters = listOf("[B", "L"),
opcodes = listOf( opcodes = listOf(
Opcode.IF_EQ, Opcode.IF_EQ,
Opcode.IGET_OBJECT, Opcode.IGET_OBJECT,
Opcode.INVOKE_VIRTUAL, Opcode.INVOKE_VIRTUAL,
Opcode.IGET, // get dialog code Opcode.IGET, // get dialog code
), ),
literalSupplier = { SlidingDialogAnimation } // 6.26 and earlier has a different first parameter.
// Since this fingerprint is somewhat weak, work around by checking for both method parameter signatures.
customFingerprint = custom@{ methodDef, _ ->
if (!methodDef.containsWideLiteralInstructionValue(SlidingDialogAnimation)) {
return@custom false
}
// 6.26 and earlier parameters are: "L", "L"
// 6.27+ parameters are "[B", "L"
val parameterTypes = methodDef.parameterTypes
parameterTypes.size == 2 && parameterTypes[1].startsWith("L")
},
) )

View File

@ -5,7 +5,6 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.util.smali.ExternalLabel import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.music.flyoutmenu.components.fingerprints.DialogSolidFingerprint import app.revanced.patches.music.flyoutmenu.components.fingerprints.DialogSolidFingerprint
import app.revanced.patches.music.flyoutmenu.components.fingerprints.EndButtonsContainerFingerprint import app.revanced.patches.music.flyoutmenu.components.fingerprints.EndButtonsContainerFingerprint
@ -20,17 +19,18 @@ import app.revanced.patches.music.utils.integrations.Constants.COMPONENTS_PATH
import app.revanced.patches.music.utils.integrations.Constants.FLYOUT_CLASS_DESCRIPTOR import app.revanced.patches.music.utils.integrations.Constants.FLYOUT_CLASS_DESCRIPTOR
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.EndButtonsContainer import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.EndButtonsContainer
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.TrimSilenceSwitch
import app.revanced.patches.music.utils.settings.CategoryType import app.revanced.patches.music.utils.settings.CategoryType
import app.revanced.patches.music.utils.settings.SettingsPatch import app.revanced.patches.music.utils.settings.SettingsPatch
import app.revanced.patches.music.utils.videotype.VideoTypeHookPatch import app.revanced.patches.music.utils.videotype.VideoTypeHookPatch
import app.revanced.patches.music.video.information.VideoInformationPatch import app.revanced.patches.music.video.information.VideoInformationPatch
import app.revanced.patches.shared.litho.LithoFilterPatch import app.revanced.patches.shared.litho.LithoFilterPatch
import app.revanced.util.getTargetIndexOrThrow import app.revanced.util.findMethodOrThrow
import app.revanced.util.getTargetIndexWithMethodReferenceNameOrThrow import app.revanced.util.getReference
import app.revanced.util.getWalkerMethod import app.revanced.util.getWalkerMethod
import app.revanced.util.getWideLiteralInstructionIndex
import app.revanced.util.indexOfFirstInstructionOrThrow import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.literalInstructionBooleanHook import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow
import app.revanced.util.injectLiteralInstructionBooleanCall
import app.revanced.util.patch.BaseBytecodePatch import app.revanced.util.patch.BaseBytecodePatch
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
@ -88,7 +88,7 @@ object FlyoutMenuComponentsPatch : BaseBytecodePatch(
// region patch for enable trim silence // region patch for enable trim silence
TrimSilenceConfigFingerprint.result?.let { TrimSilenceConfigFingerprint.result?.let {
TrimSilenceConfigFingerprint.literalInstructionBooleanHook( TrimSilenceConfigFingerprint.injectLiteralInstructionBooleanCall(
45619123, 45619123,
"$FLYOUT_CLASS_DESCRIPTOR->enableTrimSilence(Z)Z" "$FLYOUT_CLASS_DESCRIPTOR->enableTrimSilence(Z)Z"
) )
@ -96,40 +96,39 @@ object FlyoutMenuComponentsPatch : BaseBytecodePatch(
TrimSilenceSwitchFingerprint.resultOrThrow().let { TrimSilenceSwitchFingerprint.resultOrThrow().let {
it.mutableMethod.apply { it.mutableMethod.apply {
val constIndex = val constIndex =
getWideLiteralInstructionIndex(SharedResourceIdPatch.TrimSilenceSwitch) indexOfFirstWideLiteralInstructionValueOrThrow(TrimSilenceSwitch)
val onCheckedChangedListenerIndex = val onCheckedChangedListenerIndex =
getTargetIndexOrThrow(constIndex, Opcode.INVOKE_DIRECT) indexOfFirstInstructionOrThrow(constIndex, Opcode.INVOKE_DIRECT)
val onCheckedChangedListenerReference = val onCheckedChangedListenerReference =
getInstruction<ReferenceInstruction>(onCheckedChangedListenerIndex).reference getInstruction<ReferenceInstruction>(onCheckedChangedListenerIndex).reference
val onCheckedChangedListenerDefiningClass = val onCheckedChangedListenerDefiningClass =
(onCheckedChangedListenerReference as MethodReference).definingClass (onCheckedChangedListenerReference as MethodReference).definingClass
val onCheckedChangedListenerClass =
context.findClass(onCheckedChangedListenerDefiningClass)!!.mutableClass
onCheckedChangedListenerClass.methods.find { method -> method.name == "onCheckedChanged" }
?.apply {
val walkerIndex = indexOfFirstInstructionOrThrow {
val reference =
((this as? ReferenceInstruction)?.reference as? MethodReference)
context.findMethodOrThrow(onCheckedChangedListenerDefiningClass) {
name == "onCheckedChanged"
}.apply {
val onCheckedChangedWalkerIndex =
indexOfFirstInstructionOrThrow {
val reference = getReference<MethodReference>()
opcode == Opcode.INVOKE_VIRTUAL opcode == Opcode.INVOKE_VIRTUAL
&& reference?.returnType == "V" && reference?.returnType == "V"
&& reference.parameterTypes.size == 1 && reference.parameterTypes.size == 1
&& reference.parameterTypes[0] == "Z" && reference.parameterTypes[0] == "Z"
} }
getWalkerMethod(context, walkerIndex).apply {
val insertIndex = getTargetIndexOrThrow(Opcode.MOVE_RESULT)
val insertRegister =
getInstruction<OneRegisterInstruction>(insertIndex).registerA
addInstructions( getWalkerMethod(context, onCheckedChangedWalkerIndex).apply {
insertIndex + 1, """ val insertIndex = indexOfFirstInstructionOrThrow(Opcode.MOVE_RESULT)
val insertRegister =
getInstruction<OneRegisterInstruction>(insertIndex).registerA
addInstructions(
insertIndex + 1, """
invoke-static {v$insertRegister}, $FLYOUT_CLASS_DESCRIPTOR->enableTrimSilenceSwitch(Z)Z invoke-static {v$insertRegister}, $FLYOUT_CLASS_DESCRIPTOR->enableTrimSilenceSwitch(Z)Z
move-result v$insertRegister move-result v$insertRegister
""" """
) )
} }
} ?: throw PatchException("onClickClass not found!") }
} }
} }
@ -142,7 +141,7 @@ object FlyoutMenuComponentsPatch : BaseBytecodePatch(
MenuItemFingerprint.resultOrThrow().let { MenuItemFingerprint.resultOrThrow().let {
it.mutableMethod.apply { it.mutableMethod.apply {
val freeIndex = getTargetIndexOrThrow(Opcode.OR_INT_LIT16) val freeIndex = indexOfFirstInstructionOrThrow(Opcode.OR_INT_LIT16)
val textViewIndex = it.scanResult.patternScanResult!!.startIndex val textViewIndex = it.scanResult.patternScanResult!!.startIndex
val imageViewIndex = it.scanResult.patternScanResult!!.endIndex val imageViewIndex = it.scanResult.patternScanResult!!.endIndex
@ -175,8 +174,10 @@ object FlyoutMenuComponentsPatch : BaseBytecodePatch(
TouchOutsideFingerprint.resultOrThrow().let { TouchOutsideFingerprint.resultOrThrow().let {
it.mutableMethod.apply { it.mutableMethod.apply {
val setOnClickListenerIndex = val setOnClickListenerIndex = indexOfFirstInstructionOrThrow {
getTargetIndexWithMethodReferenceNameOrThrow("setOnClickListener") opcode == Opcode.INVOKE_VIRTUAL &&
getReference<MethodReference>()?.name == "setOnClickListener"
}
val setOnClickListenerRegister = val setOnClickListenerRegister =
getInstruction<FiveRegisterInstruction>(setOnClickListenerIndex).registerC getInstruction<FiveRegisterInstruction>(setOnClickListenerIndex).registerC
@ -189,8 +190,10 @@ object FlyoutMenuComponentsPatch : BaseBytecodePatch(
EndButtonsContainerFingerprint.resultOrThrow().let { EndButtonsContainerFingerprint.resultOrThrow().let {
it.mutableMethod.apply { it.mutableMethod.apply {
val startIndex = getWideLiteralInstructionIndex(EndButtonsContainer) val startIndex =
val targetIndex = getTargetIndexOrThrow(startIndex, Opcode.MOVE_RESULT_OBJECT) indexOfFirstWideLiteralInstructionValueOrThrow(EndButtonsContainer)
val targetIndex =
indexOfFirstInstructionOrThrow(startIndex, Opcode.MOVE_RESULT_OBJECT)
val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
addInstruction( addInstruction(

View File

@ -1,39 +1,24 @@
package app.revanced.patches.music.general.autocaptions package app.revanced.patches.music.general.autocaptions
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patches.music.utils.compatibility.Constants.COMPATIBLE_PACKAGE import app.revanced.patches.music.utils.compatibility.Constants.COMPATIBLE_PACKAGE
import app.revanced.patches.music.utils.integrations.Constants.GENERAL_CLASS_DESCRIPTOR
import app.revanced.patches.music.utils.settings.CategoryType import app.revanced.patches.music.utils.settings.CategoryType
import app.revanced.patches.music.utils.settings.SettingsPatch import app.revanced.patches.music.utils.settings.SettingsPatch
import app.revanced.patches.shared.fingerprints.SubtitleTrackFingerprint import app.revanced.patches.shared.captions.BaseAutoCaptionsPatch
import app.revanced.util.patch.BaseBytecodePatch import app.revanced.util.patch.BaseBytecodePatch
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
@Suppress("unused") @Suppress("unused")
object AutoCaptionsPatch : BaseBytecodePatch( object AutoCaptionsPatch : BaseBytecodePatch(
name = "Disable auto captions", name = "Disable auto captions",
description = "Adds an option to disable captions from being automatically enabled.", description = "Adds an option to disable captions from being automatically enabled.",
dependencies = setOf(SettingsPatch::class), dependencies = setOf(
BaseAutoCaptionsPatch::class,
SettingsPatch::class
),
compatiblePackages = COMPATIBLE_PACKAGE, compatiblePackages = COMPATIBLE_PACKAGE,
fingerprints = setOf(SubtitleTrackFingerprint),
) { ) {
override fun execute(context: BytecodeContext) { override fun execute(context: BytecodeContext) {
SubtitleTrackFingerprint.resultOrThrow().mutableMethod.apply {
val index = implementation!!.instructions.lastIndex
val register = getInstruction<OneRegisterInstruction>(index).registerA
addInstructions(
index, """
invoke-static {v$register}, $GENERAL_CLASS_DESCRIPTOR->disableAutoCaptions(Z)Z
move-result v$register
"""
)
}
SettingsPatch.addSwitchPreference( SettingsPatch.addSwitchPreference(
CategoryType.GENERAL, CategoryType.GENERAL,
"revanced_disable_auto_captions", "revanced_disable_auto_captions",

View File

@ -27,15 +27,17 @@ import app.revanced.patches.music.utils.compatibility.Constants.COMPATIBLE_PACKA
import app.revanced.patches.music.utils.integrations.Constants.COMPONENTS_PATH import app.revanced.patches.music.utils.integrations.Constants.COMPONENTS_PATH
import app.revanced.patches.music.utils.integrations.Constants.GENERAL_CLASS_DESCRIPTOR import app.revanced.patches.music.utils.integrations.Constants.GENERAL_CLASS_DESCRIPTOR
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.MusicTasteBuilderShelf
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.PlayerOverlayChip
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.TopBarMenuItemImageView import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.TopBarMenuItemImageView
import app.revanced.patches.music.utils.settings.CategoryType import app.revanced.patches.music.utils.settings.CategoryType
import app.revanced.patches.music.utils.settings.SettingsPatch import app.revanced.patches.music.utils.settings.SettingsPatch
import app.revanced.patches.shared.litho.LithoFilterPatch import app.revanced.patches.shared.litho.LithoFilterPatch
import app.revanced.patches.shared.settingmenu.SettingsMenuPatch import app.revanced.patches.shared.settingmenu.SettingsMenuPatch
import app.revanced.util.getTargetIndexOrThrow import app.revanced.util.alsoResolve
import app.revanced.util.getTargetIndexWithMethodReferenceNameOrThrow import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.getWideLiteralInstructionIndex import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow
import app.revanced.util.literalInstructionBooleanHook import app.revanced.util.injectLiteralInstructionBooleanCall
import app.revanced.util.patch.BaseBytecodePatch import app.revanced.util.patch.BaseBytecodePatch
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
@ -99,7 +101,7 @@ object LayoutComponentsPatch : BaseBytecodePatch(
PlayerOverlayChipFingerprint.resultOrThrow().let { PlayerOverlayChipFingerprint.resultOrThrow().let {
it.mutableMethod.apply { it.mutableMethod.apply {
val targetIndex = val targetIndex =
getWideLiteralInstructionIndex(SharedResourceIdPatch.PlayerOverlayChip) + 2 indexOfFirstWideLiteralInstructionValueOrThrow(PlayerOverlayChip) + 2
val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
addInstruction( addInstruction(
@ -176,8 +178,10 @@ object LayoutComponentsPatch : BaseBytecodePatch(
if (SettingsPatch.upward0642) { if (SettingsPatch.upward0642) {
TopBarMenuItemImageViewFingerprint.resultOrThrow().mutableMethod.apply { TopBarMenuItemImageViewFingerprint.resultOrThrow().mutableMethod.apply {
val constIndex = getWideLiteralInstructionIndex(TopBarMenuItemImageView) val constIndex =
val targetIndex = getTargetIndexOrThrow(constIndex, Opcode.MOVE_RESULT_OBJECT) indexOfFirstWideLiteralInstructionValueOrThrow(TopBarMenuItemImageView)
val targetIndex =
indexOfFirstInstructionOrThrow(constIndex, Opcode.MOVE_RESULT_OBJECT)
val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
addInstruction( addInstruction(
@ -193,7 +197,7 @@ object LayoutComponentsPatch : BaseBytecodePatch(
// region patch for hide sound search button // region patch for hide sound search button
SoundSearchFingerprint.result?.let { SoundSearchFingerprint.result?.let {
SoundSearchFingerprint.literalInstructionBooleanHook( SoundSearchFingerprint.injectLiteralInstructionBooleanCall(
45625491, 45625491,
"$GENERAL_CLASS_DESCRIPTOR->hideSoundSearchButton(Z)Z" "$GENERAL_CLASS_DESCRIPTOR->hideSoundSearchButton(Z)Z"
) )
@ -227,8 +231,9 @@ object LayoutComponentsPatch : BaseBytecodePatch(
parentResult.mutableMethod.apply { parentResult.mutableMethod.apply {
val constIndex = val constIndex =
getWideLiteralInstructionIndex(SharedResourceIdPatch.MusicTasteBuilderShelf) indexOfFirstWideLiteralInstructionValueOrThrow(MusicTasteBuilderShelf)
val targetIndex = getTargetIndexOrThrow(constIndex, Opcode.MOVE_RESULT_OBJECT) val targetIndex =
indexOfFirstInstructionOrThrow(constIndex, Opcode.MOVE_RESULT_OBJECT)
val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
addInstruction( addInstruction(
@ -263,14 +268,11 @@ object LayoutComponentsPatch : BaseBytecodePatch(
// region patch for hide voice search button // region patch for hide voice search button
SearchBarFingerprint.resolve( SearchBarFingerprint.alsoResolve(
context, context, SearchBarParentFingerprint
SearchBarParentFingerprint.resultOrThrow().classDef ).let {
)
SearchBarFingerprint.resultOrThrow().let {
it.mutableMethod.apply { it.mutableMethod.apply {
val setVisibilityIndex = val setVisibilityIndex = SearchBarFingerprint.indexOfVisibilityInstruction(this)
getTargetIndexWithMethodReferenceNameOrThrow("setVisibility")
val setVisibilityInstruction = val setVisibilityInstruction =
getInstruction<FiveRegisterInstruction>(setVisibilityIndex) getInstruction<FiveRegisterInstruction>(setVisibilityIndex)

View File

@ -3,7 +3,7 @@ package app.revanced.patches.music.general.components.fingerprints
import app.revanced.patcher.extensions.or import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.HistoryMenuItem import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.HistoryMenuItem
import app.revanced.util.containsWideLiteralInstructionIndex import app.revanced.util.containsWideLiteralInstructionValue
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
@ -16,7 +16,7 @@ internal object HistoryMenuItemFingerprint : MethodFingerprint(
Opcode.RETURN_VOID Opcode.RETURN_VOID
), ),
customFingerprint = { methodDef, classDef -> customFingerprint = { methodDef, classDef ->
methodDef.containsWideLiteralInstructionIndex(HistoryMenuItem) methodDef.containsWideLiteralInstructionValue(HistoryMenuItem)
&& classDef.methods.count() == 5 && classDef.methods.count() == 5
} }
) )

View File

@ -4,7 +4,7 @@ import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.HistoryMenuItem import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.HistoryMenuItem
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.OfflineSettingsMenuItem import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.OfflineSettingsMenuItem
import app.revanced.util.containsWideLiteralInstructionIndex import app.revanced.util.containsWideLiteralInstructionValue
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
@ -17,7 +17,7 @@ internal object HistoryMenuItemOfflineTabFingerprint : MethodFingerprint(
Opcode.RETURN_VOID Opcode.RETURN_VOID
), ),
customFingerprint = { methodDef, _ -> customFingerprint = { methodDef, _ ->
methodDef.containsWideLiteralInstructionIndex(HistoryMenuItem) methodDef.containsWideLiteralInstructionValue(HistoryMenuItem)
&& methodDef.containsWideLiteralInstructionIndex(OfflineSettingsMenuItem) && methodDef.containsWideLiteralInstructionValue(OfflineSettingsMenuItem)
} }
) )

View File

@ -1,8 +1,22 @@
package app.revanced.patches.music.general.components.fingerprints package app.revanced.patches.music.general.components.fingerprints
import app.revanced.util.fingerprint.MethodReferenceNameFingerprint import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patches.music.general.components.fingerprints.SearchBarFingerprint.indexOfVisibilityInstruction
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionReversed
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
object SearchBarFingerprint : MethodReferenceNameFingerprint( object SearchBarFingerprint : MethodFingerprint(
returnType = "V", returnType = "V",
reference = { "setVisibility" } customFingerprint = { methodDef, _ ->
) indexOfVisibilityInstruction(methodDef) >= 0
}
) {
fun indexOfVisibilityInstruction(methodDef: Method) =
methodDef.indexOfFirstInstructionReversed {
opcode == Opcode.INVOKE_VIRTUAL &&
getReference<MethodReference>()?.name == "setVisibility"
}
}

View File

@ -8,8 +8,8 @@ import app.revanced.patches.music.utils.compatibility.Constants.COMPATIBLE_PACKA
import app.revanced.patches.music.utils.integrations.Constants.GENERAL_CLASS_DESCRIPTOR import app.revanced.patches.music.utils.integrations.Constants.GENERAL_CLASS_DESCRIPTOR
import app.revanced.patches.music.utils.settings.CategoryType import app.revanced.patches.music.utils.settings.CategoryType
import app.revanced.patches.music.utils.settings.SettingsPatch import app.revanced.patches.music.utils.settings.SettingsPatch
import app.revanced.util.getStringInstructionIndex import app.revanced.util.indexOfFirstInstructionReversedOrThrow
import app.revanced.util.getTargetIndexReversedOrThrow import app.revanced.util.indexOfFirstStringInstructionOrThrow
import app.revanced.util.patch.BaseBytecodePatch import app.revanced.util.patch.BaseBytecodePatch
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
@ -27,8 +27,9 @@ object OldStyleLibraryShelfPatch : BaseBytecodePatch(
BrowseIdFingerprint.resultOrThrow().let { BrowseIdFingerprint.resultOrThrow().let {
it.mutableMethod.apply { it.mutableMethod.apply {
val stringIndex = getStringInstructionIndex("FEmusic_offline") val stringIndex = indexOfFirstStringInstructionOrThrow("FEmusic_offline")
val targetIndex = getTargetIndexReversedOrThrow(stringIndex, Opcode.IGET_OBJECT) val targetIndex =
indexOfFirstInstructionReversedOrThrow(stringIndex, Opcode.IGET_OBJECT)
val targetRegister = getInstruction<TwoRegisterInstruction>(targetIndex).registerA val targetRegister = getInstruction<TwoRegisterInstruction>(targetIndex).registerA
addInstructions( addInstructions(

View File

@ -11,11 +11,11 @@ import app.revanced.patches.music.utils.fingerprints.PendingIntentReceiverFinger
import app.revanced.patches.music.utils.integrations.Constants.GENERAL_CLASS_DESCRIPTOR import app.revanced.patches.music.utils.integrations.Constants.GENERAL_CLASS_DESCRIPTOR
import app.revanced.patches.music.utils.settings.CategoryType import app.revanced.patches.music.utils.settings.CategoryType
import app.revanced.patches.music.utils.settings.SettingsPatch import app.revanced.patches.music.utils.settings.SettingsPatch
import app.revanced.util.getStringInstructionIndex import app.revanced.util.getReference
import app.revanced.util.getTargetIndexReversedOrThrow
import app.revanced.util.getTargetIndexWithReferenceOrThrow
import app.revanced.util.getWalkerMethod import app.revanced.util.getWalkerMethod
import app.revanced.util.indexOfFirstInstructionOrThrow import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
import app.revanced.util.indexOfFirstStringInstructionOrThrow
import app.revanced.util.patch.BaseBytecodePatch import app.revanced.util.patch.BaseBytecodePatch
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
@ -41,13 +41,14 @@ object DislikeRedirectionPatch : BaseBytecodePatch(
PendingIntentReceiverFingerprint.resultOrThrow().let { PendingIntentReceiverFingerprint.resultOrThrow().let {
it.mutableMethod.apply { it.mutableMethod.apply {
val startIndex = getStringInstructionIndex("YTM Dislike") val startIndex = indexOfFirstStringInstructionOrThrow("YTM Dislike")
val onClickRelayIndex = val onClickRelayIndex =
getTargetIndexReversedOrThrow(startIndex, Opcode.INVOKE_VIRTUAL) indexOfFirstInstructionReversedOrThrow(startIndex, Opcode.INVOKE_VIRTUAL)
val onClickRelayMethod = getWalkerMethod(context, onClickRelayIndex) val onClickRelayMethod = getWalkerMethod(context, onClickRelayIndex)
onClickRelayMethod.apply { onClickRelayMethod.apply {
val onClickMethodIndex = getTargetIndexReversedOrThrow(Opcode.INVOKE_DIRECT) val onClickMethodIndex =
indexOfFirstInstructionReversedOrThrow(Opcode.INVOKE_DIRECT)
val onClickMethod = getWalkerMethod(context, onClickMethodIndex) val onClickMethod = getWalkerMethod(context, onClickMethodIndex)
onClickMethod.apply { onClickMethod.apply {
@ -70,7 +71,9 @@ object DislikeRedirectionPatch : BaseBytecodePatch(
DislikeButtonOnClickListenerFingerprint.resultOrThrow().let { DislikeButtonOnClickListenerFingerprint.resultOrThrow().let {
it.mutableMethod.apply { it.mutableMethod.apply {
val onClickIndex = getTargetIndexWithReferenceOrThrow(onClickReference.toString()) val onClickIndex = indexOfFirstInstructionOrThrow {
getReference<MethodReference>()?.toString() == onClickReference.toString()
}
injectCall(onClickIndex) injectCall(onClickIndex)
} }
} }
@ -84,7 +87,7 @@ object DislikeRedirectionPatch : BaseBytecodePatch(
} }
private fun MutableMethod.injectCall(onClickIndex: Int) { private fun MutableMethod.injectCall(onClickIndex: Int) {
val targetIndex = getTargetIndexReversedOrThrow(onClickIndex, Opcode.IF_EQZ) val targetIndex = indexOfFirstInstructionReversedOrThrow(onClickIndex, Opcode.IF_EQZ)
val insertRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA val insertRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
addInstructionsWithLabels( addInstructionsWithLabels(

View File

@ -2,7 +2,7 @@ package app.revanced.patches.music.general.redirection.fingerprints
import app.revanced.patcher.extensions.or import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.util.containsWideLiteralInstructionIndex import app.revanced.util.containsWideLiteralInstructionValue
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
internal object DislikeButtonOnClickListenerFingerprint : MethodFingerprint( internal object DislikeButtonOnClickListenerFingerprint : MethodFingerprint(
@ -10,7 +10,7 @@ internal object DislikeButtonOnClickListenerFingerprint : MethodFingerprint(
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("Landroid/view/View;"), parameters = listOf("Landroid/view/View;"),
customFingerprint = handler@{ methodDef, _ -> customFingerprint = handler@{ methodDef, _ ->
if (!methodDef.containsWideLiteralInstructionIndex(53465)) if (!methodDef.containsWideLiteralInstructionValue(53465))
return@handler false return@handler false
methodDef.name == "onClick" methodDef.name == "onClick"

View File

@ -79,7 +79,7 @@ object CustomBrandingIconPatch : BaseResourcePatch(
private val splashIconResourceGroups = private val splashIconResourceGroups =
largeDrawableDirectories.getResourceGroup(splashIconResourceFileNames) largeDrawableDirectories.getResourceGroup(splashIconResourceFileNames)
private val AppIcon = stringPatchOption( val AppIcon = stringPatchOption(
key = "AppIcon", key = "AppIcon",
default = DEFAULT_ICON, default = DEFAULT_ICON,
values = availableIcon, values = availableIcon,
@ -198,7 +198,11 @@ object CustomBrandingIconPatch : BaseResourcePatch(
if (oldSplashIconNotExists) { if (oldSplashIconNotExists) {
splashIconResourceGroups.let { resourceGroups -> splashIconResourceGroups.let { resourceGroups ->
resourceGroups.forEach { resourceGroups.forEach {
context.copyResources("$youtubeMusicIconResourcePath/splash", it, createDirectoryIfNotExist = true) context.copyResources(
"$youtubeMusicIconResourcePath/splash",
it,
createDirectoryIfNotExist = true
)
} }
} }
} }

View File

@ -0,0 +1,147 @@
package app.revanced.patches.music.layout.visual
import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption
import app.revanced.patches.music.layout.branding.icon.CustomBrandingIconPatch
import app.revanced.patches.music.utils.compatibility.Constants.COMPATIBLE_PACKAGE
import app.revanced.patches.music.utils.settings.ResourceUtils.SETTINGS_HEADER_PATH
import app.revanced.patches.music.utils.settings.SettingsPatch
import app.revanced.util.ResourceGroup
import app.revanced.util.copyResources
import app.revanced.util.doRecursively
import app.revanced.util.patch.BaseResourcePatch
import app.revanced.util.underBarOrThrow
import org.w3c.dom.Element
import java.io.Closeable
@Suppress("DEPRECATION", "unused")
object VisualPreferencesIconsPatch : BaseResourcePatch(
name = "Visual preferences icons for YouTube Music",
description = "Adds icons to specific preferences in the settings.",
dependencies = setOf(SettingsPatch::class),
compatiblePackages = COMPATIBLE_PACKAGE
), Closeable {
private const val DEFAULT_ICON = "extension"
private val RVXSettingsMenuIcon = stringPatchOption(
key = "RVXSettingsMenuIcon",
default = DEFAULT_ICON,
values = mapOf(
"Custom branding icon" to "custom_branding_icon",
"Extension" to DEFAULT_ICON,
"Gear" to "gear",
"ReVanced" to "revanced",
"ReVanced Colored" to "revanced_colored",
),
title = "RVX settings menu icon",
description = "The icon for the RVX settings menu.",
required = true
)
private lateinit var context: ResourceContext
override fun execute(context: ResourceContext) {
this.context = context
// Check patch options first.
val selectedIconType = RVXSettingsMenuIcon
.underBarOrThrow()
val customBrandingIconType = CustomBrandingIconPatch.AppIcon
.underBarOrThrow()
// region copy shared resources.
arrayOf(
ResourceGroup(
"drawable",
*preferenceKey.map { it + "_icon.xml" }.toTypedArray()
),
).forEach { resourceGroup ->
context.copyResources("music/visual/shared", resourceGroup)
}
// endregion.
// region copy RVX settings menu icon.
val iconPath = when (selectedIconType) {
"custom_branding_icon" -> "music/branding/$customBrandingIconType/settings"
else -> "music/visual/icons/$selectedIconType"
}
val resourceGroup = ResourceGroup(
"drawable",
"revanced_extended_settings_icon.xml"
)
try {
context.copyResources(iconPath, resourceGroup)
} catch (_: Exception) {
// Ignore if resource copy fails
}
// endregion.
}
override fun close() {
// region set visual preferences icon.
context.xmlEditor[SETTINGS_HEADER_PATH].use { editor ->
editor.file.doRecursively loop@{ node ->
if (node !is Element) return@loop
node.getAttributeNode("android:key")
?.textContent
?.removePrefix("@string/")
?.let { title ->
val drawableName = when (title) {
in preferenceKey -> title + "_icon"
else -> null
}
drawableName?.let {
node.setAttribute("android:icon", "@drawable/$it")
}
}
}
}
// endregion.
}
// region preference key and icon.
private val preferenceKey = setOf(
// YouTube settings.
"pref_key_parent_tools",
"settings_header_general",
"settings_header_playback",
"settings_header_data_saving",
"settings_header_downloads_and_storage",
"settings_header_notifications",
"settings_header_privacy_and_location",
"settings_header_recommendations",
"settings_header_paid_memberships",
"settings_header_about_youtube_music",
// RVX settings.
"revanced_extended_settings",
"revanced_preference_screen_account",
"revanced_preference_screen_action_bar",
"revanced_preference_screen_ads",
"revanced_preference_screen_flyout",
"revanced_preference_screen_general",
"revanced_preference_screen_navigation",
"revanced_preference_screen_player",
"revanced_preference_screen_video",
"revanced_preference_screen_ryd",
"revanced_preference_screen_sb",
"revanced_preference_screen_misc",
)
// endregion.
}

View File

@ -10,15 +10,16 @@ import app.revanced.patches.music.misc.backgroundplayback.fingerprints.KidsBackg
import app.revanced.patches.music.misc.backgroundplayback.fingerprints.MusicBrowserServiceFingerprint import app.revanced.patches.music.misc.backgroundplayback.fingerprints.MusicBrowserServiceFingerprint
import app.revanced.patches.music.misc.backgroundplayback.fingerprints.PodCastConfigFingerprint import app.revanced.patches.music.misc.backgroundplayback.fingerprints.PodCastConfigFingerprint
import app.revanced.patches.music.utils.compatibility.Constants.COMPATIBLE_PACKAGE import app.revanced.patches.music.utils.compatibility.Constants.COMPATIBLE_PACKAGE
import app.revanced.util.getStartsWithStringInstructionIndex import app.revanced.util.getReference
import app.revanced.util.getStringInstructionIndex
import app.revanced.util.getWalkerMethod import app.revanced.util.getWalkerMethod
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
import app.revanced.util.indexOfFirstStringInstructionOrThrow
import app.revanced.util.patch.BaseBytecodePatch import app.revanced.util.patch.BaseBytecodePatch
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction import com.android.tools.smali.dexlib2.iface.reference.MethodReference
@Suppress("unused") @Suppress("unused")
object BackgroundPlaybackPatch : BaseBytecodePatch( object BackgroundPlaybackPatch : BaseBytecodePatch(
@ -51,26 +52,20 @@ object BackgroundPlaybackPatch : BaseBytecodePatch(
// don't play music video // don't play music video
MusicBrowserServiceFingerprint.resultOrThrow().let { MusicBrowserServiceFingerprint.resultOrThrow().let {
it.mutableMethod.apply { it.mutableMethod.apply {
val targetIndex = val stringIndex = MusicBrowserServiceFingerprint.indexOfMBSInstruction(this)
getStartsWithStringInstructionIndex("MBS: Return empty root for client: %s") val targetIndex = indexOfFirstInstructionReversedOrThrow(stringIndex) {
val reference = getReference<MethodReference>()
for (index in targetIndex downTo 0) { opcode == Opcode.INVOKE_VIRTUAL &&
if (getInstruction(index).opcode != Opcode.INVOKE_VIRTUAL) continue reference?.returnType == "Z" &&
reference.parameterTypes.size == 0
val targetReference = getInstruction<ReferenceInstruction>(index).reference
if (!targetReference.toString().endsWith("()Z")) continue
val walkerMethod = getWalkerMethod(context, index)
walkerMethod.addInstructions(
0, """
const/4 v0, 0x1
return v0
"""
)
break
} }
getWalkerMethod(context, targetIndex).addInstructions(
0, """
const/4 v0, 0x1
return v0
"""
)
} }
} }
@ -97,7 +92,8 @@ object BackgroundPlaybackPatch : BaseBytecodePatch(
} }
dataSavingSettingsFragmentFingerprintResult!!.mutableMethod.apply { dataSavingSettingsFragmentFingerprintResult!!.mutableMethod.apply {
val insertIndex = getStringInstructionIndex("pref_key_dont_play_nma_video") + 4 val insertIndex =
indexOfFirstStringInstructionOrThrow("pref_key_dont_play_nma_video") + 4
val targetRegister = getInstruction<FiveRegisterInstruction>(insertIndex).registerD val targetRegister = getInstruction<FiveRegisterInstruction>(insertIndex).registerD
addInstruction( addInstruction(

View File

@ -2,8 +2,13 @@ package app.revanced.patches.music.misc.backgroundplayback.fingerprints
import app.revanced.patcher.extensions.or import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.util.getStartsWithStringInstructionIndex import app.revanced.patches.music.misc.backgroundplayback.fingerprints.MusicBrowserServiceFingerprint.indexOfMBSInstruction
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.reference.StringReference
internal object MusicBrowserServiceFingerprint : MethodFingerprint( internal object MusicBrowserServiceFingerprint : MethodFingerprint(
returnType = "L", returnType = "L",
@ -13,6 +18,12 @@ internal object MusicBrowserServiceFingerprint : MethodFingerprint(
if (!methodDef.definingClass.endsWith("/MusicBrowserService;")) if (!methodDef.definingClass.endsWith("/MusicBrowserService;"))
return@custom false return@custom false
methodDef.getStartsWithStringInstructionIndex("MBS: Return empty root for client: %s") > 0 indexOfMBSInstruction(methodDef) >= 0
} }
) ) {
fun indexOfMBSInstruction(methodDef: Method) =
methodDef.indexOfFirstInstruction {
opcode == Opcode.CONST_STRING &&
getReference<StringReference>()?.string?.startsWith("MBS: Return empty root for client: %s") == true
}
}

View File

@ -12,8 +12,8 @@ import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.BottomS
import app.revanced.patches.music.utils.settings.CategoryType import app.revanced.patches.music.utils.settings.CategoryType
import app.revanced.patches.music.utils.settings.SettingsPatch import app.revanced.patches.music.utils.settings.SettingsPatch
import app.revanced.patches.shared.litho.LithoFilterPatch import app.revanced.patches.shared.litho.LithoFilterPatch
import app.revanced.util.getTargetIndexOrThrow import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.getWideLiteralInstructionIndex import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow
import app.revanced.util.patch.BaseBytecodePatch import app.revanced.util.patch.BaseBytecodePatch
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
@ -40,8 +40,8 @@ object ShareSheetPatch : BaseBytecodePatch(
override fun execute(context: BytecodeContext) { override fun execute(context: BytecodeContext) {
BottomSheetRecyclerViewFingerprint.resultOrThrow().mutableMethod.apply { BottomSheetRecyclerViewFingerprint.resultOrThrow().mutableMethod.apply {
val constIndex = getWideLiteralInstructionIndex(BottomSheetRecyclerView) val constIndex = indexOfFirstWideLiteralInstructionValueOrThrow(BottomSheetRecyclerView)
val targetIndex = getTargetIndexOrThrow(constIndex, Opcode.CHECK_CAST) val targetIndex = indexOfFirstInstructionOrThrow(constIndex, Opcode.CHECK_CAST)
val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
addInstruction( addInstruction(

View File

@ -1,25 +1,41 @@
package app.revanced.patches.music.misc.splash package app.revanced.patches.music.misc.splash
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.music.misc.splash.fingerprints.CairoSplashAnimationConfigFingerprint import app.revanced.patches.music.misc.splash.fingerprints.CairoSplashAnimationConfigFingerprint
import app.revanced.patches.music.utils.integrations.Constants.MISC_PATH import app.revanced.patches.music.utils.integrations.Constants.MISC_PATH
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.MainActivityLaunchAnimation
import app.revanced.patches.music.utils.settings.CategoryType import app.revanced.patches.music.utils.settings.CategoryType
import app.revanced.patches.music.utils.settings.SettingsPatch import app.revanced.patches.music.utils.settings.SettingsPatch
import app.revanced.util.literalInstructionBooleanHook import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow
import app.revanced.util.injectLiteralInstructionBooleanCall
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
@Patch( @Patch(
name = "Disable Cairo splash animation", name = "Disable Cairo splash animation",
description = "Adds an option to disable Cairo splash animation.", description = "Adds an option to disable Cairo splash animation.",
dependencies = [SettingsPatch::class], dependencies = [
SettingsPatch::class,
SharedResourceIdPatch::class
],
compatiblePackages = [ compatiblePackages = [
CompatiblePackage( CompatiblePackage(
"com.google.android.apps.youtube.music", "com.google.android.apps.youtube.music",
[ [
"7.06.54", "7.06.54",
"7.17.51", "7.16.53",
] ]
) )
] ]
@ -28,22 +44,57 @@ import app.revanced.util.literalInstructionBooleanHook
object CairoSplashAnimationPatch : BytecodePatch( object CairoSplashAnimationPatch : BytecodePatch(
setOf(CairoSplashAnimationConfigFingerprint) setOf(CairoSplashAnimationConfigFingerprint)
) { ) {
private const val INTEGRATIONS_METHOD_DESCRIPTOR =
"$MISC_PATH/CairoSplashAnimationPatch;->disableCairoSplashAnimation(Z)Z"
override fun execute(context: BytecodeContext) { override fun execute(context: BytecodeContext) {
CairoSplashAnimationConfigFingerprint.result?.let { if (!SettingsPatch.upward0706) {
CairoSplashAnimationConfigFingerprint.literalInstructionBooleanHook( println("WARNING: This patch is not supported in this version. Use YouTube Music 7.06.54 or later.")
return
} else if (!SettingsPatch.upward0720) {
CairoSplashAnimationConfigFingerprint.injectLiteralInstructionBooleanCall(
45635386, 45635386,
"$MISC_PATH/CairoSplashAnimationPatch;->disableCairoSplashAnimation(Z)Z" INTEGRATIONS_METHOD_DESCRIPTOR
)
SettingsPatch.addSwitchPreference(
CategoryType.MISC,
"revanced_disable_cairo_splash_animation",
"false"
) )
} else {
CairoSplashAnimationConfigFingerprint.resultOrThrow().mutableMethod.apply {
val literalIndex = indexOfFirstWideLiteralInstructionValueOrThrow(
MainActivityLaunchAnimation
)
val insertIndex = indexOfFirstInstructionReversedOrThrow(literalIndex) {
opcode == Opcode.INVOKE_VIRTUAL &&
getReference<MethodReference>()?.name == "setContentView"
} + 1
val viewStubFindViewByIdIndex = indexOfFirstInstructionOrThrow(literalIndex) {
val reference = getReference<MethodReference>()
opcode == Opcode.INVOKE_VIRTUAL &&
reference?.name == "findViewById" &&
reference.definingClass != "Landroid/view/View;"
}
val freeRegister =
getInstruction<FiveRegisterInstruction>(viewStubFindViewByIdIndex).registerD
val jumpIndex = indexOfFirstInstructionReversedOrThrow(
viewStubFindViewByIdIndex,
Opcode.IGET_OBJECT
)
addInstructionsWithLabels(
insertIndex, """
const/4 v$freeRegister, 0x1
invoke-static {v$freeRegister}, $INTEGRATIONS_METHOD_DESCRIPTOR
move-result v$freeRegister
if-eqz v$freeRegister, :skip
""", ExternalLabel("skip", getInstruction(jumpIndex))
)
}
} }
?: println("WARNING: This patch is not supported in this version. Use YouTube Music 7.06.54 or later.")
SettingsPatch.addSwitchPreference(
CategoryType.MISC,
"revanced_disable_cairo_splash_animation",
"false"
)
} }
} }

View File

@ -1,10 +1,25 @@
package app.revanced.patches.music.misc.splash.fingerprints package app.revanced.patches.music.misc.splash.fingerprints
import app.revanced.util.fingerprint.LiteralValueFingerprint import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.MainActivityLaunchAnimation
import app.revanced.patches.music.utils.settings.SettingsPatch
import app.revanced.util.indexOfFirstWideLiteralInstructionValue
/** /**
* This fingerprint is compatible with YouTube Music v7.06.53+ * This fingerprint is compatible with YouTube Music v7.06.53+
*/ */
internal object CairoSplashAnimationConfigFingerprint : LiteralValueFingerprint( internal object CairoSplashAnimationConfigFingerprint : MethodFingerprint(
literalSupplier = { 45635386 } returnType = "V",
customFingerprint = handler@{ methodDef, _ ->
if (methodDef.definingClass != "Lcom/google/android/apps/youtube/music/activities/MusicActivity;")
return@handler false
if (methodDef.name != "onCreate")
return@handler false
if (SettingsPatch.upward0720) {
methodDef.indexOfFirstWideLiteralInstructionValue(MainActivityLaunchAnimation) >= 0
} else {
methodDef.indexOfFirstWideLiteralInstructionValue(45635386) >= 0
}
}
) )

View File

@ -11,13 +11,12 @@ import app.revanced.patches.music.utils.compatibility.Constants.COMPATIBLE_PACKA
import app.revanced.patches.music.utils.integrations.Constants.NAVIGATION_CLASS_DESCRIPTOR import app.revanced.patches.music.utils.integrations.Constants.NAVIGATION_CLASS_DESCRIPTOR
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.ColorGrey import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.ColorGrey
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.Text1
import app.revanced.patches.music.utils.settings.CategoryType import app.revanced.patches.music.utils.settings.CategoryType
import app.revanced.patches.music.utils.settings.SettingsPatch import app.revanced.patches.music.utils.settings.SettingsPatch
import app.revanced.util.getReference import app.revanced.util.getReference
import app.revanced.util.getTargetIndexOrThrow
import app.revanced.util.getTargetIndexWithMethodReferenceNameOrThrow
import app.revanced.util.getWideLiteralInstructionIndex
import app.revanced.util.indexOfFirstInstructionOrThrow import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow
import app.revanced.util.patch.BaseBytecodePatch import app.revanced.util.patch.BaseBytecodePatch
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
@ -50,7 +49,7 @@ object NavigationBarComponentsPatch : BaseBytecodePatch(
* Enable black navigation bar * Enable black navigation bar
*/ */
TabLayoutFingerprint.resultOrThrow().mutableMethod.apply { TabLayoutFingerprint.resultOrThrow().mutableMethod.apply {
val constIndex = getWideLiteralInstructionIndex(ColorGrey) val constIndex = indexOfFirstWideLiteralInstructionValueOrThrow(ColorGrey)
val insertIndex = indexOfFirstInstructionOrThrow(constIndex) { val insertIndex = indexOfFirstInstructionOrThrow(constIndex) {
opcode == Opcode.INVOKE_VIRTUAL opcode == Opcode.INVOKE_VIRTUAL
&& getReference<MethodReference>()?.name == "setBackgroundColor" && getReference<MethodReference>()?.name == "setBackgroundColor"
@ -70,8 +69,9 @@ object NavigationBarComponentsPatch : BaseBytecodePatch(
*/ */
TabLayoutTextFingerprint.resultOrThrow().let { TabLayoutTextFingerprint.resultOrThrow().let {
it.mutableMethod.apply { it.mutableMethod.apply {
val constIndex = getWideLiteralInstructionIndex(SharedResourceIdPatch.Text1) val constIndex =
val targetIndex = getTargetIndexOrThrow(constIndex, Opcode.CHECK_CAST) indexOfFirstWideLiteralInstructionValueOrThrow(Text1)
val targetIndex = indexOfFirstInstructionOrThrow(constIndex, Opcode.CHECK_CAST)
val targetParameter = getInstruction<ReferenceInstruction>(targetIndex).reference val targetParameter = getInstruction<ReferenceInstruction>(targetIndex).reference
val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
@ -105,9 +105,12 @@ object NavigationBarComponentsPatch : BaseBytecodePatch(
it.mutableMethod.apply { it.mutableMethod.apply {
val enumIndex = it.scanResult.patternScanResult!!.startIndex + 3 val enumIndex = it.scanResult.patternScanResult!!.startIndex + 3
val enumRegister = getInstruction<OneRegisterInstruction>(enumIndex).registerA val enumRegister = getInstruction<OneRegisterInstruction>(enumIndex).registerA
val insertEnumIndex = getTargetIndexOrThrow(Opcode.AND_INT_LIT8) - 2 val insertEnumIndex = indexOfFirstInstructionOrThrow(Opcode.AND_INT_LIT8) - 2
val pivotTabIndex = getTargetIndexWithMethodReferenceNameOrThrow("getVisibility") val pivotTabIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.INVOKE_VIRTUAL &&
getReference<MethodReference>()?.name == "getVisibility"
}
val pivotTabRegister = getInstruction<Instruction35c>(pivotTabIndex).registerC val pivotTabRegister = getInstruction<Instruction35c>(pivotTabIndex).registerC
addInstruction( addInstruction(

View File

@ -13,6 +13,8 @@ import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
import app.revanced.patcher.util.smali.ExternalLabel import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.music.player.components.fingerprints.AudioVideoSwitchToggleFingerprint import app.revanced.patches.music.player.components.fingerprints.AudioVideoSwitchToggleFingerprint
import app.revanced.patches.music.player.components.fingerprints.EngagementPanelHeightFingerprint
import app.revanced.patches.music.player.components.fingerprints.EngagementPanelHeightParentFingerprint
import app.revanced.patches.music.player.components.fingerprints.HandleSearchRenderedFingerprint import app.revanced.patches.music.player.components.fingerprints.HandleSearchRenderedFingerprint
import app.revanced.patches.music.player.components.fingerprints.HandleSignInEventFingerprint import app.revanced.patches.music.player.components.fingerprints.HandleSignInEventFingerprint
import app.revanced.patches.music.player.components.fingerprints.InteractionLoggingEnumFingerprint import app.revanced.patches.music.player.components.fingerprints.InteractionLoggingEnumFingerprint
@ -59,17 +61,16 @@ import app.revanced.patches.music.utils.settings.SettingsPatch
import app.revanced.patches.music.utils.videotype.VideoTypeHookPatch import app.revanced.patches.music.utils.videotype.VideoTypeHookPatch
import app.revanced.patches.shared.litho.LithoFilterPatch import app.revanced.patches.shared.litho.LithoFilterPatch
import app.revanced.util.REGISTER_TEMPLATE_REPLACEMENT import app.revanced.util.REGISTER_TEMPLATE_REPLACEMENT
import app.revanced.util.alsoResolve
import app.revanced.util.findMethodOrThrow
import app.revanced.util.getReference import app.revanced.util.getReference
import app.revanced.util.getStringInstructionIndex
import app.revanced.util.getTargetIndex
import app.revanced.util.getTargetIndexOrThrow
import app.revanced.util.getTargetIndexReversedOrThrow
import app.revanced.util.getTargetIndexWithFieldReferenceTypeOrThrow
import app.revanced.util.getWalkerMethod import app.revanced.util.getWalkerMethod
import app.revanced.util.getWideLiteralInstructionIndex
import app.revanced.util.indexOfFirstInstructionOrThrow import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.literalInstructionBooleanHook import app.revanced.util.indexOfFirstInstructionReversedOrThrow
import app.revanced.util.literalInstructionViewHook import app.revanced.util.indexOfFirstStringInstructionOrThrow
import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow
import app.revanced.util.injectLiteralInstructionBooleanCall
import app.revanced.util.injectLiteralInstructionViewCall
import app.revanced.util.patch.BaseBytecodePatch import app.revanced.util.patch.BaseBytecodePatch
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
import app.revanced.util.transformFields import app.revanced.util.transformFields
@ -105,6 +106,7 @@ object PlayerComponentsPatch : BaseBytecodePatch(
compatiblePackages = COMPATIBLE_PACKAGE, compatiblePackages = COMPATIBLE_PACKAGE,
fingerprints = setOf( fingerprints = setOf(
AudioVideoSwitchToggleFingerprint, AudioVideoSwitchToggleFingerprint,
EngagementPanelHeightParentFingerprint,
HandleSearchRenderedFingerprint, HandleSearchRenderedFingerprint,
InteractionLoggingEnumFingerprint, InteractionLoggingEnumFingerprint,
MinimizedPlayerFingerprint, MinimizedPlayerFingerprint,
@ -145,8 +147,8 @@ object PlayerComponentsPatch : BaseBytecodePatch(
PlayerViewPager to "disablePlayerGesture" PlayerViewPager to "disablePlayerGesture"
).forEach { (literal, methodName) -> ).forEach { (literal, methodName) ->
val viewPagerReference = playerViewPagerConstructorMethod.let { val viewPagerReference = playerViewPagerConstructorMethod.let {
val constIndex = it.getWideLiteralInstructionIndex(literal) val constIndex = it.indexOfFirstWideLiteralInstructionValueOrThrow(literal)
val targetIndex = it.getTargetIndexOrThrow(constIndex, Opcode.IPUT_OBJECT) val targetIndex = it.indexOfFirstInstructionOrThrow(constIndex, Opcode.IPUT_OBJECT)
it.getInstruction<ReferenceInstruction>(targetIndex).reference.toString() it.getInstruction<ReferenceInstruction>(targetIndex).reference.toString()
} }
@ -156,7 +158,8 @@ object PlayerComponentsPatch : BaseBytecodePatch(
&& getReference<FieldReference>()?.toString() == viewPagerReference && getReference<FieldReference>()?.toString() == viewPagerReference
} }
val insertRegister = getInstruction<TwoRegisterInstruction>(insertIndex).registerA val insertRegister = getInstruction<TwoRegisterInstruction>(insertIndex).registerA
val jumpIndex = getTargetIndex(insertIndex, Opcode.INVOKE_VIRTUAL) + 1 val jumpIndex =
indexOfFirstInstructionOrThrow(insertIndex, Opcode.INVOKE_VIRTUAL) + 1
addInstructionsWithLabels( addInstructionsWithLabels(
insertIndex, """ insertIndex, """
@ -198,8 +201,8 @@ object PlayerComponentsPatch : BaseBytecodePatch(
val relativeIndex = it.scanResult.patternScanResult!!.endIndex + 1 val relativeIndex = it.scanResult.patternScanResult!!.endIndex + 1
val invokeVirtualIndex = val invokeVirtualIndex =
getTargetIndexOrThrow(relativeIndex, Opcode.INVOKE_VIRTUAL) indexOfFirstInstructionOrThrow(relativeIndex, Opcode.INVOKE_VIRTUAL)
val iGetIndex = getTargetIndexOrThrow(relativeIndex, Opcode.IGET) val iGetIndex = indexOfFirstInstructionOrThrow(relativeIndex, Opcode.IGET)
colorMathPlayerInvokeVirtualReference = colorMathPlayerInvokeVirtualReference =
getInstruction<ReferenceInstruction>(invokeVirtualIndex).reference getInstruction<ReferenceInstruction>(invokeVirtualIndex).reference
@ -207,11 +210,11 @@ object PlayerComponentsPatch : BaseBytecodePatch(
getInstruction<ReferenceInstruction>(iGetIndex).reference getInstruction<ReferenceInstruction>(iGetIndex).reference
// black player background // black player background
val invokeDirectIndex = getTargetIndexOrThrow(Opcode.INVOKE_DIRECT) val invokeDirectIndex = indexOfFirstInstructionOrThrow(Opcode.INVOKE_DIRECT)
val targetMethod = getWalkerMethod(context, invokeDirectIndex) val targetMethod = getWalkerMethod(context, invokeDirectIndex)
targetMethod.apply { targetMethod.apply {
val insertIndex = getTargetIndexOrThrow(0, Opcode.IF_NE) val insertIndex = indexOfFirstInstructionOrThrow(Opcode.IF_NE)
addInstructions( addInstructions(
insertIndex, """ insertIndex, """
@ -225,8 +228,8 @@ object PlayerComponentsPatch : BaseBytecodePatch(
} }
parentResult.mutableMethod.apply { parentResult.mutableMethod.apply {
val colorGreyIndex = getWideLiteralInstructionIndex(ColorGrey) val colorGreyIndex = indexOfFirstWideLiteralInstructionValueOrThrow(ColorGrey)
val iPutIndex = getTargetIndexOrThrow(colorGreyIndex, Opcode.IPUT) val iPutIndex = indexOfFirstInstructionOrThrow(colorGreyIndex, Opcode.IPUT)
colorMathPlayerIPutReference = colorMathPlayerIPutReference =
getInstruction<ReferenceInstruction>(iPutIndex).reference getInstruction<ReferenceInstruction>(iPutIndex).reference
@ -240,7 +243,8 @@ object PlayerComponentsPatch : BaseBytecodePatch(
mutableMethod.apply { mutableMethod.apply {
val freeRegister = implementation!!.registerCount - parameters.size - 3 val freeRegister = implementation!!.registerCount - parameters.size - 3
val invokeDirectIndex = getTargetIndexReversedOrThrow(Opcode.INVOKE_DIRECT) val invokeDirectIndex =
indexOfFirstInstructionReversedOrThrow(Opcode.INVOKE_DIRECT)
val invokeDirectReference = val invokeDirectReference =
getInstruction<ReferenceInstruction>(invokeDirectIndex).reference getInstruction<ReferenceInstruction>(invokeDirectIndex).reference
@ -401,9 +405,9 @@ object PlayerComponentsPatch : BaseBytecodePatch(
reversed: Boolean reversed: Boolean
): Reference { ): Reference {
val targetIndex = if (reversed) val targetIndex = if (reversed)
getTargetIndexReversedOrThrow(swipeToDismissWidgetIndex, opcode) indexOfFirstInstructionReversedOrThrow(swipeToDismissWidgetIndex, opcode)
else else
getTargetIndexOrThrow(swipeToDismissWidgetIndex, opcode) indexOfFirstInstructionOrThrow(swipeToDismissWidgetIndex, opcode)
return getInstruction<ReferenceInstruction>(targetIndex).reference return getInstruction<ReferenceInstruction>(targetIndex).reference
} }
@ -411,7 +415,7 @@ object PlayerComponentsPatch : BaseBytecodePatch(
if (!SettingsPatch.upward0642) { if (!SettingsPatch.upward0642) {
SwipeToCloseFingerprint.resultOrThrow().let { SwipeToCloseFingerprint.resultOrThrow().let {
it.mutableMethod.apply { it.mutableMethod.apply {
val insertIndex = implementation!!.instructions.size - 1 val insertIndex = implementation!!.instructions.lastIndex
val targetRegister = val targetRegister =
getInstruction<OneRegisterInstruction>(insertIndex).registerA getInstruction<OneRegisterInstruction>(insertIndex).registerA
@ -430,8 +434,9 @@ object PlayerComponentsPatch : BaseBytecodePatch(
InteractionLoggingEnumFingerprint.resultOrThrow().let { InteractionLoggingEnumFingerprint.resultOrThrow().let {
it.mutableMethod.apply { it.mutableMethod.apply {
val stringIndex = val stringIndex =
getStringInstructionIndex("INTERACTION_LOGGING_GESTURE_TYPE_SWIPE") indexOfFirstStringInstructionOrThrow("INTERACTION_LOGGING_GESTURE_TYPE_SWIPE")
val sPutObjectIndex = getTargetIndexOrThrow(stringIndex, Opcode.SPUT_OBJECT) val sPutObjectIndex =
indexOfFirstInstructionOrThrow(stringIndex, Opcode.SPUT_OBJECT)
swipeToDismissSGetObjectReference = swipeToDismissSGetObjectReference =
getInstruction<ReferenceInstruction>(sPutObjectIndex).reference getInstruction<ReferenceInstruction>(sPutObjectIndex).reference
@ -440,7 +445,8 @@ object PlayerComponentsPatch : BaseBytecodePatch(
MusicActivityWidgetFingerprint.resultOrThrow().let { MusicActivityWidgetFingerprint.resultOrThrow().let {
it.mutableMethod.apply { it.mutableMethod.apply {
swipeToDismissWidgetIndex = getWideLiteralInstructionIndex(79500) swipeToDismissWidgetIndex =
indexOfFirstWideLiteralInstructionValueOrThrow(79500)
swipeToDismissIGetObjectReference = swipeToDismissIGetObjectReference =
getSwipeToDismissReference(Opcode.IGET_OBJECT, true) getSwipeToDismissReference(Opcode.IGET_OBJECT, true)
@ -468,8 +474,9 @@ object PlayerComponentsPatch : BaseBytecodePatch(
it.getWalkerMethod(context, it.scanResult.patternScanResult!!.startIndex) it.getWalkerMethod(context, it.scanResult.patternScanResult!!.startIndex)
dismissBehaviorMethod.apply { dismissBehaviorMethod.apply {
val insertIndex = val insertIndex = indexOfFirstInstructionOrThrow {
getTargetIndexWithFieldReferenceTypeOrThrow("Ljava/util/concurrent/atomic/AtomicBoolean;") getReference<FieldReference>()?.type == "Ljava/util/concurrent/atomic/AtomicBoolean;"
}
val primaryRegister = val primaryRegister =
getInstruction<TwoRegisterInstruction>(insertIndex).registerB getInstruction<TwoRegisterInstruction>(insertIndex).registerB
val secondaryRegister = primaryRegister + 1 val secondaryRegister = primaryRegister + 1
@ -528,15 +535,12 @@ object PlayerComponentsPatch : BaseBytecodePatch(
it.mutableClass.methods.find { method -> it.mutableClass.methods.find { method ->
method.parameters == listOf("Landroid/view/View;", "I") method.parameters == listOf("Landroid/view/View;", "I")
}?.apply { }?.apply {
val bottomSheetBehaviorIndex = val bottomSheetBehaviorIndex = indexOfFirstInstructionOrThrow {
implementation!!.instructions.indexOfFirst { instruction -> val reference = getReference<MethodReference>()
instruction.opcode == Opcode.INVOKE_VIRTUAL opcode == Opcode.INVOKE_VIRTUAL
&& instruction.getReference<MethodReference>()?.definingClass == "Lcom/google/android/material/bottomsheet/BottomSheetBehavior;" && reference?.definingClass == "Lcom/google/android/material/bottomsheet/BottomSheetBehavior;"
&& instruction.getReference<MethodReference>()?.parameterTypes?.first() == "Z" && reference.parameterTypes.first() == "Z"
} }
if (bottomSheetBehaviorIndex < 0)
throw PatchException("Could not find bottomSheetBehaviorIndex")
val freeRegister = val freeRegister =
getInstruction<FiveRegisterInstruction>(bottomSheetBehaviorIndex).registerD getInstruction<FiveRegisterInstruction>(bottomSheetBehaviorIndex).registerD
@ -592,7 +596,7 @@ object PlayerComponentsPatch : BaseBytecodePatch(
SwitchToggleColorFingerprint.resultOrThrow().let { SwitchToggleColorFingerprint.resultOrThrow().let {
it.mutableMethod.apply { it.mutableMethod.apply {
val invokeDirectIndex = getTargetIndexOrThrow(Opcode.INVOKE_DIRECT) val invokeDirectIndex = indexOfFirstInstructionOrThrow(Opcode.INVOKE_DIRECT)
val walkerMethod = getWalkerMethod(context, invokeDirectIndex) val walkerMethod = getWalkerMethod(context, invokeDirectIndex)
walkerMethod.addInstructions( walkerMethod.addInstructions(
@ -624,8 +628,8 @@ object PlayerComponentsPatch : BaseBytecodePatch(
// region patch for hide audio video switch toggle // region patch for hide audio video switch toggle
AudioVideoSwitchToggleFingerprint.resultOrThrow().mutableMethod.apply { AudioVideoSwitchToggleFingerprint.resultOrThrow().mutableMethod.apply {
val constIndex = getWideLiteralInstructionIndex(AudioVideoSwitchToggle) val constIndex = indexOfFirstWideLiteralInstructionValueOrThrow(AudioVideoSwitchToggle)
val viewIndex = getTargetIndexOrThrow(constIndex, Opcode.MOVE_RESULT_OBJECT) val viewIndex = indexOfFirstInstructionOrThrow(constIndex, Opcode.MOVE_RESULT_OBJECT)
val viewRegister = getInstruction<OneRegisterInstruction>(viewIndex).registerA val viewRegister = getInstruction<OneRegisterInstruction>(viewIndex).registerA
addInstruction( addInstruction(
@ -667,7 +671,7 @@ object PlayerComponentsPatch : BaseBytecodePatch(
DarkBackground, DarkBackground,
TapBloomView TapBloomView
).forEach { literal -> ).forEach { literal ->
QuickSeekOverlayFingerprint.literalInstructionViewHook( QuickSeekOverlayFingerprint.injectLiteralInstructionViewCall(
literal, literal,
smaliInstruction smaliInstruction
) )
@ -742,17 +746,20 @@ object PlayerComponentsPatch : BaseBytecodePatch(
it.mutableMethod.apply { it.mutableMethod.apply {
rememberShuffleStateObjectClass = definingClass rememberShuffleStateObjectClass = definingClass
val constIndex = getWideLiteralInstructionIndex(45468)
val iGetObjectIndex = getTargetIndexOrThrow(constIndex, Opcode.IGET_OBJECT)
val checkCastIndex = getTargetIndexOrThrow(iGetObjectIndex, Opcode.CHECK_CAST)
val ordinalIndex = indexOfOrdinalInstruction(this)
val imageViewIndex = indexOfImageViewInstruction(this) val imageViewIndex = indexOfImageViewInstruction(this)
val ordinalIndex = indexOfOrdinalInstruction(this)
val invokeInterfaceIndex =
indexOfFirstInstructionReversedOrThrow(ordinalIndex, Opcode.INVOKE_INTERFACE)
val iGetObjectIndex =
indexOfFirstInstructionReversedOrThrow(invokeInterfaceIndex, Opcode.IGET_OBJECT)
val checkCastIndex =
indexOfFirstInstructionOrThrow(invokeInterfaceIndex, Opcode.CHECK_CAST)
val iGetObjectReference = val iGetObjectReference =
getInstruction<ReferenceInstruction>(iGetObjectIndex).reference getInstruction<ReferenceInstruction>(iGetObjectIndex).reference
val invokeInterfaceReference = val invokeInterfaceReference =
getInstruction<ReferenceInstruction>(iGetObjectIndex + 1).reference getInstruction<ReferenceInstruction>(invokeInterfaceIndex).reference
val checkCastReference = val checkCastReference =
getInstruction<ReferenceInstruction>(checkCastIndex).reference getInstruction<ReferenceInstruction>(checkCastIndex).reference
val getOrdinalClassReference = val getOrdinalClassReference =
@ -771,7 +778,7 @@ object PlayerComponentsPatch : BaseBytecodePatch(
""" """
rememberShuffleStateShuffleStateLabel += if (getInstruction(checkCastIndex + 1).opcode == Opcode.INVOKE_VIRTUAL) { rememberShuffleStateShuffleStateLabel += if (getInstruction(checkCastIndex + 1).opcode == Opcode.INVOKE_VIRTUAL) {
// YouTube Music 7.16.52+ // YouTube Music 7.16.53+
""" """
invoke-virtual {v1}, $getOrdinalClassReference invoke-virtual {v1}, $getOrdinalClassReference
move-result-object v1 move-result-object v1
@ -887,12 +894,84 @@ object PlayerComponentsPatch : BaseBytecodePatch(
// region patch for restore old comments popup panels // region patch for restore old comments popup panels
OldEngagementPanelFingerprint.result?.let { var restoreOldCommentsPopupPanel = false
OldEngagementPanelFingerprint.literalInstructionBooleanHook(
if (SettingsPatch.upward0627 && !SettingsPatch.upward0718) {
OldEngagementPanelFingerprint.injectLiteralInstructionBooleanCall(
45427672, 45427672,
"$PLAYER_CLASS_DESCRIPTOR->restoreOldCommentsPopUpPanels(Z)Z" "$PLAYER_CLASS_DESCRIPTOR->restoreOldCommentsPopUpPanels(Z)Z"
) )
restoreOldCommentsPopupPanel = true
} else if (SettingsPatch.upward0718) {
// region disable player from being pushed to the top when opening a comment
MppWatchWhileLayoutFingerprint.resultOrThrow().mutableMethod.apply {
val callableIndex =
MppWatchWhileLayoutFingerprint.indexOfCallableInstruction(this)
val insertIndex =
indexOfFirstInstructionReversedOrThrow(callableIndex, Opcode.NEW_INSTANCE)
val insertRegister = getInstruction<OneRegisterInstruction>(insertIndex).registerA
addInstructionsWithLabels(
insertIndex, """
invoke-static {}, $PLAYER_CLASS_DESCRIPTOR->restoreOldCommentsPopUpPanels()Z
move-result v$insertRegister
if-eqz v$insertRegister, :restore
""", ExternalLabel("restore", getInstruction(callableIndex + 1))
)
}
// endregion
// region region limit the height of the engagement panel
EngagementPanelHeightFingerprint.alsoResolve(
context, EngagementPanelHeightParentFingerprint
).let {
it.mutableMethod.apply {
val targetIndex = it.scanResult.patternScanResult!!.endIndex
val targetRegister =
getInstruction<OneRegisterInstruction>(targetIndex).registerA
addInstructions(
targetIndex + 1, """
invoke-static {v$targetRegister}, $PLAYER_CLASS_DESCRIPTOR->restoreOldCommentsPopUpPanels(Z)Z
move-result v$targetRegister
"""
)
}
}
MiniPlayerDefaultViewVisibilityFingerprint.resultOrThrow().let {
it.mutableClass.methods.find { method ->
method.parameters == listOf("Landroid/view/View;", "I")
}?.apply {
val targetIndex = indexOfFirstInstructionOrThrow {
val reference = getReference<MethodReference>()
opcode == Opcode.INVOKE_INTERFACE
&& reference?.returnType == "Z"
&& reference.parameterTypes.size == 0
} + 1
val targetRegister =
getInstruction<OneRegisterInstruction>(targetIndex).registerA
addInstructions(
targetIndex + 1, """
invoke-static {v$targetRegister}, $PLAYER_CLASS_DESCRIPTOR->restoreOldCommentsPopUpPanels(Z)Z
move-result v$targetRegister
"""
)
} ?: throw PatchException("Could not find targetMethod")
}
// endregion
restoreOldCommentsPopupPanel = true
}
if (restoreOldCommentsPopupPanel) {
SettingsPatch.addSwitchPreference( SettingsPatch.addSwitchPreference(
CategoryType.PLAYER, CategoryType.PLAYER,
"revanced_restore_old_comments_popup_panels", "revanced_restore_old_comments_popup_panels",
@ -905,7 +984,7 @@ object PlayerComponentsPatch : BaseBytecodePatch(
// region patch for restore old player background // region patch for restore old player background
OldPlayerBackgroundFingerprint.result?.let { OldPlayerBackgroundFingerprint.result?.let {
OldPlayerBackgroundFingerprint.literalInstructionBooleanHook( OldPlayerBackgroundFingerprint.injectLiteralInstructionBooleanCall(
45415319, 45415319,
"$PLAYER_CLASS_DESCRIPTOR->restoreOldPlayerBackground(Z)Z" "$PLAYER_CLASS_DESCRIPTOR->restoreOldPlayerBackground(Z)Z"
) )
@ -922,7 +1001,7 @@ object PlayerComponentsPatch : BaseBytecodePatch(
// region patch for restore old player layout // region patch for restore old player layout
OldPlayerLayoutFingerprint.result?.let { OldPlayerLayoutFingerprint.result?.let {
OldPlayerLayoutFingerprint.literalInstructionBooleanHook( OldPlayerLayoutFingerprint.injectLiteralInstructionBooleanCall(
45399578, 45399578,
"$PLAYER_CLASS_DESCRIPTOR->restoreOldPlayerLayout(Z)Z" "$PLAYER_CLASS_DESCRIPTOR->restoreOldPlayerLayout(Z)Z"
) )
@ -943,11 +1022,14 @@ object PlayerComponentsPatch : BaseBytecodePatch(
viewId: Long viewId: Long
) { ) {
val miniPlayerPlayPauseReplayButtonIndex = val miniPlayerPlayPauseReplayButtonIndex =
getWideLiteralInstructionIndex(MiniPlayerPlayPauseReplayButton) indexOfFirstWideLiteralInstructionValueOrThrow(MiniPlayerPlayPauseReplayButton)
val miniPlayerPlayPauseReplayButtonRegister = val miniPlayerPlayPauseReplayButtonRegister =
getInstruction<OneRegisterInstruction>(miniPlayerPlayPauseReplayButtonIndex).registerA getInstruction<OneRegisterInstruction>(miniPlayerPlayPauseReplayButtonIndex).registerA
val findViewByIdIndex = val findViewByIdIndex =
getTargetIndexOrThrow(miniPlayerPlayPauseReplayButtonIndex, Opcode.INVOKE_VIRTUAL) indexOfFirstInstructionOrThrow(
miniPlayerPlayPauseReplayButtonIndex,
Opcode.INVOKE_VIRTUAL
)
val parentViewRegister = val parentViewRegister =
getInstruction<FiveRegisterInstruction>(findViewByIdIndex).registerC getInstruction<FiveRegisterInstruction>(findViewByIdIndex).registerC
@ -966,11 +1048,14 @@ object PlayerComponentsPatch : BaseBytecodePatch(
viewId: Long viewId: Long
) { ) {
val miniPlayerPlayPauseReplayButtonIndex = val miniPlayerPlayPauseReplayButtonIndex =
getWideLiteralInstructionIndex(MiniPlayerPlayPauseReplayButton) indexOfFirstWideLiteralInstructionValueOrThrow(MiniPlayerPlayPauseReplayButton)
val constRegister = val constRegister =
getInstruction<OneRegisterInstruction>(miniPlayerPlayPauseReplayButtonIndex).registerA getInstruction<OneRegisterInstruction>(miniPlayerPlayPauseReplayButtonIndex).registerA
val findViewByIdIndex = val findViewByIdIndex =
getTargetIndexOrThrow(miniPlayerPlayPauseReplayButtonIndex, Opcode.INVOKE_VIRTUAL) indexOfFirstInstructionOrThrow(
miniPlayerPlayPauseReplayButtonIndex,
Opcode.INVOKE_VIRTUAL
)
val findViewByIdRegister = val findViewByIdRegister =
getInstruction<FiveRegisterInstruction>(findViewByIdIndex).registerC getInstruction<FiveRegisterInstruction>(findViewByIdIndex).registerC
@ -986,9 +1071,12 @@ object PlayerComponentsPatch : BaseBytecodePatch(
private fun MutableMethod.setViewArray() { private fun MutableMethod.setViewArray() {
val miniPlayerPlayPauseReplayButtonIndex = val miniPlayerPlayPauseReplayButtonIndex =
getWideLiteralInstructionIndex(MiniPlayerPlayPauseReplayButton) indexOfFirstWideLiteralInstructionValueOrThrow(MiniPlayerPlayPauseReplayButton)
val invokeStaticIndex = val invokeStaticIndex =
getTargetIndexOrThrow(miniPlayerPlayPauseReplayButtonIndex, Opcode.INVOKE_STATIC) indexOfFirstInstructionOrThrow(
miniPlayerPlayPauseReplayButtonIndex,
Opcode.INVOKE_STATIC
)
val viewArrayRegister = getInstruction<FiveRegisterInstruction>(invokeStaticIndex).registerC val viewArrayRegister = getInstruction<FiveRegisterInstruction>(invokeStaticIndex).registerC
addInstructions( addInstructions(
@ -1005,21 +1093,18 @@ object PlayerComponentsPatch : BaseBytecodePatch(
methodName: String, methodName: String,
fieldName: String fieldName: String
) { ) {
val startIndex = getStringInstructionIndex(intentString) val startIndex = indexOfFirstStringInstructionOrThrow(intentString)
val onClickIndex = getTargetIndexReversedOrThrow(startIndex, Opcode.INVOKE_VIRTUAL) val onClickIndex = indexOfFirstInstructionReversedOrThrow(startIndex, Opcode.INVOKE_VIRTUAL)
val onClickReference = getInstruction<ReferenceInstruction>(onClickIndex).reference val onClickReference = getInstruction<ReferenceInstruction>(onClickIndex).reference
val onClickReferenceDefiningClass = (onClickReference as MethodReference).definingClass val onClickReferenceDefiningClass = (onClickReference as MethodReference).definingClass
val onClickClass = context.findMethodOrThrow(onClickReferenceDefiningClass)
context.findClass(onClickReferenceDefiningClass)!!.mutableClass .apply {
onClickClass.methods.find { method -> method.name == "<init>" }
?.apply {
addInstruction( addInstruction(
implementation!!.instructions.size - 1, implementation!!.instructions.lastIndex,
"sput-object p0, $PLAYER_CLASS_DESCRIPTOR->$fieldName:$onClickReferenceDefiningClass" "sput-object p0, $PLAYER_CLASS_DESCRIPTOR->$fieldName:$onClickReferenceDefiningClass"
) )
} ?: throw PatchException("onClickClass not found!") }
PlayerPatchConstructorFingerprint.resultOrThrow().let { PlayerPatchConstructorFingerprint.resultOrThrow().let {
val mutableClass = it.mutableClass val mutableClass = it.mutableClass

View File

@ -0,0 +1,26 @@
package app.revanced.patches.music.player.components.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
internal object EngagementPanelHeightFingerprint : MethodFingerprint(
returnType = "L",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
opcodes = listOf(
Opcode.IGET_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT,
),
parameters = emptyList(),
customFingerprint = custom@{ methodDef, _ ->
methodDef.indexOfFirstInstruction {
opcode == Opcode.INVOKE_VIRTUAL &&
getReference<MethodReference>()?.name == "booleanValue"
} >= 0
}
)

View File

@ -0,0 +1,28 @@
package app.revanced.patches.music.player.components.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.util.indexOfFirstInstruction
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
internal object EngagementPanelHeightParentFingerprint : MethodFingerprint(
returnType = "L",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
opcodes = listOf(Opcode.NEW_ARRAY),
parameters = emptyList(),
customFingerprint = custom@{ methodDef, _ ->
if (methodDef.definingClass.startsWith("Lcom/")) {
return@custom false
}
if (methodDef.returnType == "Ljava/lang/Object;") {
return@custom false
}
methodDef.indexOfFirstInstruction {
opcode == Opcode.CHECK_CAST &&
(this as? ReferenceInstruction)?.reference?.toString() == "Lcom/google/android/libraries/youtube/engagementpanel/size/EngagementPanelSizeBehavior;"
} >= 0
}
)

View File

@ -3,13 +3,13 @@ package app.revanced.patches.music.player.components.fingerprints
import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.ColorGrey import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.ColorGrey
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.MiniPlayerPlayPauseReplayButton import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.MiniPlayerPlayPauseReplayButton
import app.revanced.util.containsWideLiteralInstructionIndex import app.revanced.util.containsWideLiteralInstructionValue
internal object MiniPlayerConstructorFingerprint : MethodFingerprint( internal object MiniPlayerConstructorFingerprint : MethodFingerprint(
returnType = "V", returnType = "V",
strings = listOf("sharedToggleMenuItemMutations"), strings = listOf("sharedToggleMenuItemMutations"),
customFingerprint = { methodDef, _ -> customFingerprint = { methodDef, _ ->
methodDef.containsWideLiteralInstructionIndex(ColorGrey) methodDef.containsWideLiteralInstructionValue(ColorGrey)
&& methodDef.containsWideLiteralInstructionIndex(MiniPlayerPlayPauseReplayButton) && methodDef.containsWideLiteralInstructionValue(MiniPlayerPlayPauseReplayButton)
} }
) )

View File

@ -1,16 +1,42 @@
package app.revanced.patches.music.player.components.fingerprints package app.revanced.patches.music.player.components.fingerprints
import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patches.music.player.components.fingerprints.MppWatchWhileLayoutFingerprint.indexOfCallableInstruction
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.MiniPlayerPlayPauseReplayButton import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.MiniPlayerPlayPauseReplayButton
import app.revanced.util.containsWideLiteralInstructionIndex import app.revanced.patches.music.utils.settings.SettingsPatch
import app.revanced.util.containsWideLiteralInstructionValue
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
internal object MppWatchWhileLayoutFingerprint : MethodFingerprint( internal object MppWatchWhileLayoutFingerprint : MethodFingerprint(
returnType = "V", returnType = "V",
opcodes = listOf(Opcode.NEW_ARRAY), opcodes = listOf(Opcode.NEW_ARRAY),
customFingerprint = { methodDef, _ -> customFingerprint = custom@{ methodDef, _ ->
methodDef.definingClass.endsWith("/MppWatchWhileLayout;") if (!methodDef.definingClass.endsWith("/MppWatchWhileLayout;")) {
&& methodDef.name == "onFinishInflate" return@custom false
&& methodDef.containsWideLiteralInstructionIndex(MiniPlayerPlayPauseReplayButton) }
if (methodDef.name != "onFinishInflate") {
return@custom false
}
if (!methodDef.containsWideLiteralInstructionValue(MiniPlayerPlayPauseReplayButton)) {
return@custom false
}
if (!SettingsPatch.upward0718) {
return@custom true
}
indexOfCallableInstruction(methodDef) >= 0
} }
) ) {
fun indexOfCallableInstruction(methodDef: Method) =
methodDef.indexOfFirstInstruction {
val reference = getReference<MethodReference>()
opcode == Opcode.INVOKE_VIRTUAL &&
reference?.returnType == "V" &&
reference.parameterTypes.size == 1 &&
reference.parameterTypes.firstOrNull() == "Ljava/util/concurrent/Callable;"
}
}

View File

@ -1,13 +1,13 @@
package app.revanced.patches.music.player.components.fingerprints package app.revanced.patches.music.player.components.fingerprints
import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.util.containsWideLiteralInstructionIndex import app.revanced.util.containsWideLiteralInstructionValue
internal object MusicActivityWidgetFingerprint : MethodFingerprint( internal object MusicActivityWidgetFingerprint : MethodFingerprint(
customFingerprint = handler@{ methodDef, _ -> customFingerprint = handler@{ methodDef, _ ->
if (!methodDef.definingClass.endsWith("/MusicActivity;")) if (!methodDef.definingClass.endsWith("/MusicActivity;"))
return@handler false return@handler false
methodDef.containsWideLiteralInstructionIndex(79500) methodDef.containsWideLiteralInstructionValue(79500)
} }
) )

View File

@ -4,14 +4,14 @@ import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.MiniPlayerViewPager import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.MiniPlayerViewPager
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.PlayerViewPager import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.PlayerViewPager
import app.revanced.util.containsWideLiteralInstructionIndex import app.revanced.util.containsWideLiteralInstructionValue
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
internal object PlayerViewPagerConstructorFingerprint : MethodFingerprint( internal object PlayerViewPagerConstructorFingerprint : MethodFingerprint(
returnType = "V", returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
customFingerprint = { methodDef, _ -> customFingerprint = { methodDef, _ ->
methodDef.containsWideLiteralInstructionIndex(MiniPlayerViewPager) methodDef.containsWideLiteralInstructionValue(MiniPlayerViewPager)
&& methodDef.containsWideLiteralInstructionIndex(PlayerViewPager) && methodDef.containsWideLiteralInstructionValue(PlayerViewPager)
}, },
) )

View File

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

View File

@ -4,7 +4,8 @@ import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patches.music.player.components.fingerprints.ShuffleClassReferenceFingerprint.indexOfImageViewInstruction import app.revanced.patches.music.player.components.fingerprints.ShuffleClassReferenceFingerprint.indexOfImageViewInstruction
import app.revanced.patches.music.player.components.fingerprints.ShuffleClassReferenceFingerprint.indexOfOrdinalInstruction import app.revanced.patches.music.player.components.fingerprints.ShuffleClassReferenceFingerprint.indexOfOrdinalInstruction
import app.revanced.util.containsWideLiteralInstructionIndex import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.YtFillArrowShuffle
import app.revanced.util.containsWideLiteralInstructionValue
import app.revanced.util.getReference import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction import app.revanced.util.indexOfFirstInstruction
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
@ -19,7 +20,7 @@ internal object ShuffleClassReferenceFingerprint : MethodFingerprint(
parameters = emptyList(), parameters = emptyList(),
strings = listOf("Unknown shuffle mode"), strings = listOf("Unknown shuffle mode"),
customFingerprint = { methodDef, _ -> customFingerprint = { methodDef, _ ->
methodDef.containsWideLiteralInstructionIndex(45468) && methodDef.containsWideLiteralInstructionValue(YtFillArrowShuffle) &&
indexOfOrdinalInstruction(methodDef) >= 0 && indexOfOrdinalInstruction(methodDef) >= 0 &&
indexOfImageViewInstruction(methodDef) >= 0 indexOfImageViewInstruction(methodDef) >= 0
} }

View File

@ -7,12 +7,11 @@ object Constants {
Patch.CompatiblePackage( Patch.CompatiblePackage(
"com.google.android.apps.youtube.music", "com.google.android.apps.youtube.music",
setOf( setOf(
"6.29.58", // This is the latest version that supports the 'Restore old player layout' setting. "6.20.51", // This is the latest version that supports Android 5.0
"6.33.52", // This is the latest version with the legacy code of YouTube Music. "6.29.59", // This is the latest version that supports the 'Restore old player layout' setting.
"6.42.55", // This is the latest version that supports Android 7.0 "6.42.55", // This is the latest version that supports Android 7.0
"6.51.53", // This is the latest version of YouTube Music 6.xx.xx "6.51.53", // This is the latest version of YouTube Music 6.xx.xx
"7.16.53", // This was the latest version that was supported by the previous patch. "7.16.53", // This is the latest version supported by the RVX patch.
"7.17.51", // This is the latest version supported by the RVX patch.
) )
) )
) )

View File

@ -1,60 +0,0 @@
package app.revanced.patches.music.utils.fix.accessibility
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patches.music.utils.fix.accessibility.fingerprints.TouchExplorationHoverEventFingerprint
import app.revanced.util.containsMethodReferenceNameInstructionIndex
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
object AccessibilityNodeInfoPatch : BytecodePatch(
setOf(TouchExplorationHoverEventFingerprint)
) {
override fun execute(context: BytecodeContext) {
/**
* The "getTouchDelegateInfo" method has been implemented in YT Music v6.44.52.
* For some reason this method sometimes returns null, which throws [IllegalArgumentException].
* This is considered unimplemented code, so remove all methods associated with it.
*/
TouchExplorationHoverEventFingerprint.result?.let {
it.mutableMethod.apply {
// Target instruction is invoke-static, but can also be invoke-virtual.
// Therefore, the opcode is not checked.
val touchExplorationHoverEventMethodIndex =
implementation!!.instructions.indexOfFirst { instruction ->
val reference =
((instruction as? ReferenceInstruction)?.reference as? MethodReference)
((instruction as? ReferenceInstruction)?.reference as? MethodReference)?.definingClass == definingClass
&& reference?.returnType == "Z"
}
// Doesn't raise an exception, even if the target instruction is not found in this method
val touchExplorationHoverEventMethodName =
if (touchExplorationHoverEventMethodIndex > -1)
(getInstruction<ReferenceInstruction>(touchExplorationHoverEventMethodIndex).reference as MethodReference).name
else
"UNDEFINED"
val methods = it.mutableClass.methods
methods.find { method ->
method.name == "getTouchDelegateInfo"
}?.apply {
if (!containsMethodReferenceNameInstructionIndex("isEmpty")) {
arrayOf(
"getTouchDelegateInfo",
name,
touchExplorationHoverEventMethodName
).forEach { methodName ->
methods.removeIf { method ->
method.name == methodName
}
}
}
}
}
} // If this method has not been added, there is no need to remove it, so it will not raise any exceptions.
}
}

View File

@ -1,8 +0,0 @@
package app.revanced.patches.music.utils.fix.accessibility.fingerprints
import app.revanced.patcher.fingerprint.MethodFingerprint
internal object TouchExplorationHoverEventFingerprint : MethodFingerprint(
returnType = "Z",
customFingerprint = { methodDef, _ -> methodDef.name == "onTouchExplorationHoverEvent" }
)

View File

@ -22,7 +22,7 @@ object FileProviderPatch : BytecodePatch(
* For some reason, if the app gets "android.support.FILE_PROVIDER_PATHS", * For some reason, if the app gets "android.support.FILE_PROVIDER_PATHS",
* the package name of YouTube is used, not the package name of the YT Music. * the package name of YouTube is used, not the package name of the YT Music.
* *
* There is no issue in the stock YT Music, but this is an issue in the MicroG Build. * There is no issue in the stock YT Music, but this is an issue in the GmsCore Build.
* https://github.com/inotia00/ReVanced_Extended/issues/1830 * https://github.com/inotia00/ReVanced_Extended/issues/1830
* *
* To solve this issue, replace the package name of YouTube with YT Music's package name. * To solve this issue, replace the package name of YouTube with YT Music's package name.
@ -31,10 +31,16 @@ object FileProviderPatch : BytecodePatch(
it.mutableMethod.apply { it.mutableMethod.apply {
addInstructionsWithLabels( addInstructionsWithLabels(
0, """ 0, """
const-string v0, "com.google.android.youtube.fileprovider"
invoke-static {p1, v0}, Ljava/util/Objects;->equals(Ljava/lang/Object;Ljava/lang/Object;)Z
move-result v0
if-nez v0, :fix
const-string v0, "$youtubePackageName.fileprovider" const-string v0, "$youtubePackageName.fileprovider"
invoke-static {p1, v0}, Ljava/util/Objects;->equals(Ljava/lang/Object;Ljava/lang/Object;)Z invoke-static {p1, v0}, Ljava/util/Objects;->equals(Ljava/lang/Object;Ljava/lang/Object;)Z
move-result v0 move-result v0
if-eqz v0, :ignore if-nez v0, :fix
goto :ignore
:fix
const-string p1, "$musicPackageName.fileprovider" const-string p1, "$musicPackageName.fileprovider"
""", ExternalLabel("ignore", getInstruction(0)) """, ExternalLabel("ignore", getInstruction(0))
) )

View File

@ -1,16 +1,11 @@
package app.revanced.patches.music.utils.fix.header package app.revanced.patches.music.utils.fix.header
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.music.layout.header.ChangeHeaderPatch import app.revanced.patches.music.layout.header.ChangeHeaderPatch
import app.revanced.patches.music.utils.fix.header.fingerprints.HeaderSwitchConfigFingerprint import app.revanced.patches.music.utils.fix.header.fingerprints.HeaderSwitchConfigFingerprint
import app.revanced.util.getTargetIndexOrThrow import app.revanced.util.injectLiteralInstructionBooleanCall
import app.revanced.util.getWideLiteralInstructionIndex
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
@Patch( @Patch(
description = "Fix the issues where new headers are used." description = "Fix the issues where new headers are used."
@ -31,19 +26,10 @@ object RestoreOldHeaderPatch : BytecodePatch(
* TODO: Add a new header image file to [ChangeHeaderPatch] later. * TODO: Add a new header image file to [ChangeHeaderPatch] later.
*/ */
HeaderSwitchConfigFingerprint.result?.let { HeaderSwitchConfigFingerprint.result?.let {
it.mutableMethod.apply { HeaderSwitchConfigFingerprint.injectLiteralInstructionBooleanCall(
val targetIndex = 45617851,
getTargetIndexOrThrow( "0x0"
getWideLiteralInstructionIndex(45617851), )
Opcode.MOVE_RESULT
)
val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
addInstruction(
targetIndex + 1,
"const/4 v$targetRegister, 0x0"
)
}
} }
} }

View File

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

View File

@ -8,6 +8,7 @@ import app.revanced.patches.shared.mapping.ResourceMappingPatch.getId
import app.revanced.patches.shared.mapping.ResourceType.BOOL import app.revanced.patches.shared.mapping.ResourceType.BOOL
import app.revanced.patches.shared.mapping.ResourceType.COLOR import app.revanced.patches.shared.mapping.ResourceType.COLOR
import app.revanced.patches.shared.mapping.ResourceType.DIMEN import app.revanced.patches.shared.mapping.ResourceType.DIMEN
import app.revanced.patches.shared.mapping.ResourceType.DRAWABLE
import app.revanced.patches.shared.mapping.ResourceType.ID import app.revanced.patches.shared.mapping.ResourceType.ID
import app.revanced.patches.shared.mapping.ResourceType.LAYOUT import app.revanced.patches.shared.mapping.ResourceType.LAYOUT
import app.revanced.patches.shared.mapping.ResourceType.STRING import app.revanced.patches.shared.mapping.ResourceType.STRING
@ -32,6 +33,7 @@ object SharedResourceIdPatch : ResourcePatch() {
var InterstitialsContainer = -1L var InterstitialsContainer = -1L
var IsTablet = -1L var IsTablet = -1L
var LikeDislikeContainer = -1L var LikeDislikeContainer = -1L
var MainActivityLaunchAnimation = -1L
var MenuEntry = -1L var MenuEntry = -1L
var MiniPlayerDefaultText = -1L var MiniPlayerDefaultText = -1L
var MiniPlayerMdxPlaying = -1L var MiniPlayerMdxPlaying = -1L
@ -57,6 +59,7 @@ object SharedResourceIdPatch : ResourcePatch() {
var TouchOutside = -1L var TouchOutside = -1L
var TrimSilenceSwitch: Long = -1 var TrimSilenceSwitch: Long = -1
var VarispeedUnavailableTitle = -1L var VarispeedUnavailableTitle = -1L
var YtFillArrowShuffle = -1L
override fun execute(context: ResourceContext) { override fun execute(context: ResourceContext) {
@ -77,6 +80,7 @@ object SharedResourceIdPatch : ResourcePatch() {
InterstitialsContainer = getId(ID, "interstitials_container") InterstitialsContainer = getId(ID, "interstitials_container")
IsTablet = getId(BOOL, "is_tablet") IsTablet = getId(BOOL, "is_tablet")
LikeDislikeContainer = getId(ID, "like_dislike_container") LikeDislikeContainer = getId(ID, "like_dislike_container")
MainActivityLaunchAnimation = getId(LAYOUT, "main_activity_launch_animation")
MenuEntry = getId(LAYOUT, "menu_entry") MenuEntry = getId(LAYOUT, "menu_entry")
MiniPlayerDefaultText = getId(STRING, "mini_player_default_text") MiniPlayerDefaultText = getId(STRING, "mini_player_default_text")
MiniPlayerMdxPlaying = getId(STRING, "mini_player_mdx_playing") MiniPlayerMdxPlaying = getId(STRING, "mini_player_mdx_playing")
@ -102,6 +106,7 @@ object SharedResourceIdPatch : ResourcePatch() {
TouchOutside = getId(ID, "touch_outside") TouchOutside = getId(ID, "touch_outside")
TrimSilenceSwitch = getId(ID, "trim_silence_switch") TrimSilenceSwitch = getId(ID, "trim_silence_switch")
VarispeedUnavailableTitle = getId(STRING, "varispeed_unavailable_title") VarispeedUnavailableTitle = getId(STRING, "varispeed_unavailable_title")
YtFillArrowShuffle = getId(DRAWABLE, "yt_fill_arrow_shuffle_vd_theme_24")
} }
} }

View File

@ -12,7 +12,7 @@ import app.revanced.patches.music.utils.returnyoutubedislike.fingerprints.Dislik
import app.revanced.patches.music.utils.returnyoutubedislike.fingerprints.LikeFingerprint import app.revanced.patches.music.utils.returnyoutubedislike.fingerprints.LikeFingerprint
import app.revanced.patches.music.utils.returnyoutubedislike.fingerprints.RemoveLikeFingerprint import app.revanced.patches.music.utils.returnyoutubedislike.fingerprints.RemoveLikeFingerprint
import app.revanced.patches.music.utils.returnyoutubedislike.fingerprints.TextComponentFingerprint import app.revanced.patches.music.utils.returnyoutubedislike.fingerprints.TextComponentFingerprint
import app.revanced.patches.music.video.videoid.VideoIdPatch import app.revanced.patches.music.video.information.VideoInformationPatch
import app.revanced.util.indexOfFirstInstructionOrThrow import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
@ -22,7 +22,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
@Patch( @Patch(
dependencies = [ dependencies = [
SharedResourceIdPatch::class, SharedResourceIdPatch::class,
VideoIdPatch::class VideoInformationPatch::class
] ]
) )
object ReturnYouTubeDislikeBytecodePatch : BytecodePatch( object ReturnYouTubeDislikeBytecodePatch : BytecodePatch(
@ -70,7 +70,7 @@ object ReturnYouTubeDislikeBytecodePatch : BytecodePatch(
} }
} }
VideoIdPatch.hookVideoId("$INTEGRATIONS_RYD_CLASS_DESCRIPTOR->newVideoLoaded(Ljava/lang/String;)V") VideoInformationPatch.videoIdHook("$INTEGRATIONS_RYD_CLASS_DESCRIPTOR->newVideoLoaded(Ljava/lang/String;)V")
} }

View File

@ -104,6 +104,22 @@ object ResourceUtils {
} }
} }
fun ResourceContext.setPreferenceScreenIcon(
category: String
) {
this.xmlEditor[SETTINGS_HEADER_PATH].use { editor ->
editor.file.doRecursively loop@{
if (it !is Element) return@loop
it.getAttributeNode("android:key")?.let { attribute ->
if (attribute.textContent == "revanced_preference_screen_$category") {
it.cloneNodes(it.parentNode)
}
}
}
}
}
fun ResourceContext.sortPreferenceCategory( fun ResourceContext.sortPreferenceCategory(
category: String category: String
) { ) {

View File

@ -17,7 +17,7 @@ import app.revanced.patches.music.utils.settings.fingerprints.PreferenceFingerpr
import app.revanced.patches.music.utils.settings.fingerprints.SettingsHeadersFragmentFingerprint import app.revanced.patches.music.utils.settings.fingerprints.SettingsHeadersFragmentFingerprint
import app.revanced.patches.shared.fingerprints.SharedSettingFingerprint import app.revanced.patches.shared.fingerprints.SharedSettingFingerprint
import app.revanced.patches.shared.integrations.Constants.INTEGRATIONS_UTILS_CLASS_DESCRIPTOR import app.revanced.patches.shared.integrations.Constants.INTEGRATIONS_UTILS_CLASS_DESCRIPTOR
import app.revanced.util.getTargetIndexOrThrow import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
@ -52,7 +52,7 @@ object SettingsBytecodePatch : BytecodePatch(
*/ */
SharedSettingFingerprint.resultOrThrow().let { SharedSettingFingerprint.resultOrThrow().let {
it.mutableMethod.apply { it.mutableMethod.apply {
val stringIndex = getTargetIndexOrThrow(Opcode.CONST_STRING) val stringIndex = indexOfFirstInstructionOrThrow(Opcode.CONST_STRING)
val stringRegister = getInstruction<OneRegisterInstruction>(stringIndex).registerA val stringRegister = getInstruction<OneRegisterInstruction>(stringIndex).registerA
replaceInstruction( replaceInstruction(

View File

@ -3,7 +3,6 @@ package app.revanced.patches.music.utils.settings
import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption
import app.revanced.patches.music.utils.compatibility.Constants.COMPATIBLE_PACKAGE import app.revanced.patches.music.utils.compatibility.Constants.COMPATIBLE_PACKAGE
import app.revanced.patches.music.utils.fix.accessibility.AccessibilityNodeInfoPatch
import app.revanced.patches.music.utils.settings.ResourceUtils.addPreferenceCategory import app.revanced.patches.music.utils.settings.ResourceUtils.addPreferenceCategory
import app.revanced.patches.music.utils.settings.ResourceUtils.addPreferenceWithIntent import app.revanced.patches.music.utils.settings.ResourceUtils.addPreferenceWithIntent
import app.revanced.patches.music.utils.settings.ResourceUtils.addRVXSettingsPreference import app.revanced.patches.music.utils.settings.ResourceUtils.addRVXSettingsPreference
@ -22,10 +21,7 @@ import java.util.concurrent.TimeUnit
object SettingsPatch : BaseResourcePatch( object SettingsPatch : BaseResourcePatch(
name = "Settings for YouTube Music", name = "Settings for YouTube Music",
description = "Applies mandatory patches to implement ReVanced Extended settings into the application.", description = "Applies mandatory patches to implement ReVanced Extended settings into the application.",
dependencies = setOf( dependencies = setOf(SettingsBytecodePatch::class),
AccessibilityNodeInfoPatch::class,
SettingsBytecodePatch::class
),
compatiblePackages = COMPATIBLE_PACKAGE, compatiblePackages = COMPATIBLE_PACKAGE,
requiresIntegrations = true requiresIntegrations = true
), Closeable { ), Closeable {
@ -42,8 +38,12 @@ object SettingsPatch : BaseResourcePatch(
private lateinit var customName: String private lateinit var customName: String
lateinit var contexts: ResourceContext lateinit var contexts: ResourceContext
internal var upward0627 = false
internal var upward0636 = false internal var upward0636 = false
internal var upward0642 = false internal var upward0642 = false
internal var upward0706 = false
internal var upward0718 = false
internal var upward0720 = false
override fun execute(context: ResourceContext) { override fun execute(context: ResourceContext) {
@ -136,8 +136,12 @@ object SettingsPatch : BaseResourcePatch(
val playServicesVersion = node.textContent.toInt() val playServicesVersion = node.textContent.toInt()
upward0627 = 234412000 <= playServicesVersion
upward0636 = 240399000 <= playServicesVersion upward0636 = 240399000 <= playServicesVersion
upward0642 = 240999000 <= playServicesVersion upward0642 = 240999000 <= playServicesVersion
upward0706 = 242499000 <= playServicesVersion
upward0718 = 243699000 <= playServicesVersion
upward0720 = 243899000 <= playServicesVersion
break break
} }
@ -223,6 +227,14 @@ object SettingsPatch : BaseResourcePatch(
} }
} }
/**
* add open default app settings
*/
addPreferenceWithIntent(
CategoryType.MISC,
"revanced_default_app_settings"
)
/** /**
* add import export settings * add import export settings
*/ */

View File

@ -6,27 +6,30 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.music.utils.fingerprints.SeekBarConstructorFingerprint
import app.revanced.patches.music.utils.integrations.Constants.INTEGRATIONS_PATH import app.revanced.patches.music.utils.integrations.Constants.INTEGRATIONS_PATH
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch
import app.revanced.patches.music.utils.sponsorblock.fingerprints.MusicPlaybackControlsTimeBarDrawFingerprint import app.revanced.patches.music.utils.sponsorblock.fingerprints.MusicPlaybackControlsTimeBarDrawFingerprint
import app.revanced.patches.music.utils.sponsorblock.fingerprints.MusicPlaybackControlsTimeBarOnMeasureFingerprint import app.revanced.patches.music.utils.sponsorblock.fingerprints.MusicPlaybackControlsTimeBarOnMeasureFingerprint
import app.revanced.patches.music.utils.sponsorblock.fingerprints.RectangleFieldInvalidatorFingerprint
import app.revanced.patches.music.utils.sponsorblock.fingerprints.SeekBarConstructorFingerprint
import app.revanced.patches.music.utils.sponsorblock.fingerprints.SeekbarOnDrawFingerprint import app.revanced.patches.music.utils.sponsorblock.fingerprints.SeekbarOnDrawFingerprint
import app.revanced.patches.music.video.information.VideoInformationPatch import app.revanced.patches.music.video.information.VideoInformationPatch
import app.revanced.patches.music.video.videoid.VideoIdPatch import app.revanced.util.alsoResolve
import app.revanced.util.getTargetIndexWithMethodReferenceNameOrThrow import app.revanced.util.getReference
import app.revanced.util.getTargetIndexWithMethodReferenceNameReversedOrThrow import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.reference.FieldReference import com.android.tools.smali.dexlib2.iface.reference.FieldReference
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
@Patch( @Patch(
dependencies = [ dependencies = [
SharedResourceIdPatch::class, SharedResourceIdPatch::class,
VideoInformationPatch::class, VideoInformationPatch::class
VideoIdPatch::class
] ]
) )
object SponsorBlockBytecodePatch : BytecodePatch( object SponsorBlockBytecodePatch : BytecodePatch(
@ -39,7 +42,6 @@ object SponsorBlockBytecodePatch : BytecodePatch(
private const val INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR = private const val INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR =
"$INTEGRATIONS_PATH/sponsorblock/SegmentPlaybackController;" "$INTEGRATIONS_PATH/sponsorblock/SegmentPlaybackController;"
private lateinit var rectangleFieldName: String
override fun execute(context: BytecodeContext) { override fun execute(context: BytecodeContext) {
/** /**
@ -55,22 +57,41 @@ object SponsorBlockBytecodePatch : BytecodePatch(
/** /**
* Responsible for seekbar in fullscreen * Responsible for seekbar in fullscreen
*/ */
val seekBarClass = SeekBarConstructorFingerprint.resultOrThrow().mutableClass var rectangleFieldName =
SeekbarOnDrawFingerprint.resolve(context, seekBarClass) RectangleFieldInvalidatorFingerprint.alsoResolve(
context, SeekBarConstructorFingerprint
).let {
with(it.mutableMethod) {
val invalidateIndex =
RectangleFieldInvalidatorFingerprint.indexOfInvalidateInstruction(this)
val rectangleIndex =
indexOfFirstInstructionReversedOrThrow(invalidateIndex + 1) {
getReference<FieldReference>()?.type == "Landroid/graphics/Rect;"
}
val rectangleReference =
getInstruction<ReferenceInstruction>(rectangleIndex).reference
SeekbarOnDrawFingerprint.resultOrThrow().let { (rectangleReference as FieldReference).name
}
}
SeekbarOnDrawFingerprint.alsoResolve(
context, SeekBarConstructorFingerprint
).let {
it.mutableMethod.apply { it.mutableMethod.apply {
// Initialize seekbar method // Initialize seekbar method
addInstructions( addInstructions(
0, """ 0, """
move-object/from16 v0, p0 move-object/from16 v0, p0
const-string v1, "${VideoInformationPatch.rectangleFieldName}" const-string v1, "$rectangleFieldName"
invoke-static {v0, v1}, $INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setSponsorBarRect(Ljava/lang/Object;Ljava/lang/String;)V invoke-static {v0, v1}, $INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setSponsorBarRect(Ljava/lang/Object;Ljava/lang/String;)V
""" """
) )
// Set seekbar thickness // Set seekbar thickness
val roundIndex = getTargetIndexWithMethodReferenceNameOrThrow("round") + 1 val roundIndex = indexOfFirstInstructionOrThrow {
getReference<MethodReference>()?.name == "round"
} + 1
val roundRegister = getInstruction<OneRegisterInstruction>(roundIndex).registerA val roundRegister = getInstruction<OneRegisterInstruction>(roundIndex).registerA
addInstruction( addInstruction(
roundIndex + 1, roundIndex + 1,
@ -79,8 +100,9 @@ object SponsorBlockBytecodePatch : BytecodePatch(
) )
// Draw segment // Draw segment
val drawCircleIndex = val drawCircleIndex = indexOfFirstInstructionReversedOrThrow {
getTargetIndexWithMethodReferenceNameReversedOrThrow("drawCircle") getReference<MethodReference>()?.name == "drawCircle"
}
val drawCircleInstruction = getInstruction<FiveRegisterInstruction>(drawCircleIndex) val drawCircleInstruction = getInstruction<FiveRegisterInstruction>(drawCircleIndex)
addInstruction( addInstruction(
drawCircleIndex, drawCircleIndex,
@ -94,14 +116,15 @@ object SponsorBlockBytecodePatch : BytecodePatch(
/** /**
* Responsible for seekbar in player * Responsible for seekbar in player
*/ */
MusicPlaybackControlsTimeBarOnMeasureFingerprint.resultOrThrow().let { rectangleFieldName =
it.mutableMethod.apply { MusicPlaybackControlsTimeBarOnMeasureFingerprint.resultOrThrow().let {
val rectangleIndex = it.scanResult.patternScanResult!!.startIndex with(it.mutableMethod) {
val rectangleReference = val rectangleIndex = it.scanResult.patternScanResult!!.startIndex
getInstruction<ReferenceInstruction>(rectangleIndex).reference val rectangleReference =
rectangleFieldName = (rectangleReference as FieldReference).name getInstruction<ReferenceInstruction>(rectangleIndex).reference
(rectangleReference as FieldReference).name
}
} }
}
MusicPlaybackControlsTimeBarDrawFingerprint.resultOrThrow().let { MusicPlaybackControlsTimeBarDrawFingerprint.resultOrThrow().let {
it.mutableMethod.apply { it.mutableMethod.apply {
@ -115,7 +138,10 @@ object SponsorBlockBytecodePatch : BytecodePatch(
) )
// Draw segment // Draw segment
val drawCircleIndex = getTargetIndexWithMethodReferenceNameOrThrow("drawCircle") val drawCircleIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.INVOKE_VIRTUAL
&& getReference<MethodReference>()?.name == "drawCircle"
}
val drawCircleInstruction = getInstruction<FiveRegisterInstruction>(drawCircleIndex) val drawCircleInstruction = getInstruction<FiveRegisterInstruction>(drawCircleIndex)
addInstruction( addInstruction(
drawCircleIndex, drawCircleIndex,
@ -128,6 +154,6 @@ object SponsorBlockBytecodePatch : BytecodePatch(
/** /**
* Set current video id * Set current video id
*/ */
VideoIdPatch.hookVideoId("$INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setVideoId(Ljava/lang/String;)V") VideoInformationPatch.videoIdHook("$INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setVideoId(Ljava/lang/String;)V")
} }
} }

View File

@ -0,0 +1,28 @@
package app.revanced.patches.music.utils.sponsorblock.fingerprints
import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patches.music.utils.sponsorblock.fingerprints.RectangleFieldInvalidatorFingerprint.indexOfInvalidateInstruction
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionReversed
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
internal object RectangleFieldInvalidatorFingerprint : MethodFingerprint(
opcodes = listOf(
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_WIDE,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_WIDE,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_WIDE
),
customFingerprint = { methodDef, _ ->
indexOfInvalidateInstruction(methodDef) >= 0
}
) {
fun indexOfInvalidateInstruction(methodDef: Method) =
methodDef.indexOfFirstInstructionReversed {
getReference<MethodReference>()?.name == "invalidate"
}
}

View File

@ -1,4 +1,4 @@
package app.revanced.patches.music.utils.fingerprints package app.revanced.patches.music.utils.sponsorblock.fingerprints
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.InlineTimeBarAdBreakMarkerColor import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.InlineTimeBarAdBreakMarkerColor
import app.revanced.util.fingerprint.LiteralValueFingerprint import app.revanced.util.fingerprint.LiteralValueFingerprint

View File

@ -4,40 +4,36 @@ import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.or import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patcher.fingerprint.MethodFingerprintResult import app.revanced.patcher.fingerprint.MethodFingerprintResult
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patcher.util.proxy.mutableTypes.MutableClass
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
import app.revanced.patcher.util.smali.toInstructions import app.revanced.patcher.util.smali.toInstructions
import app.revanced.patches.music.utils.fingerprints.SeekBarConstructorFingerprint
import app.revanced.patches.music.utils.integrations.Constants.SHARED_PATH import app.revanced.patches.music.utils.integrations.Constants.SHARED_PATH
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch
import app.revanced.patches.music.video.information.fingerprints.PlaybackSpeedFingerprint import app.revanced.patches.music.video.information.fingerprints.PlaybackSpeedFingerprint
import app.revanced.patches.music.video.information.fingerprints.PlaybackSpeedParentFingerprint import app.revanced.patches.music.video.information.fingerprints.PlaybackSpeedParentFingerprint
import app.revanced.patches.music.video.information.fingerprints.PlayerControllerSetTimeReferenceFingerprint import app.revanced.patches.music.video.information.fingerprints.PlayerControllerSetTimeReferenceFingerprint
import app.revanced.patches.music.video.information.fingerprints.VideoEndFingerprint import app.revanced.patches.music.video.information.fingerprints.VideoEndFingerprint
import app.revanced.patches.music.video.information.fingerprints.VideoLengthFingerprint import app.revanced.patches.music.video.information.fingerprints.VideoIdFingerprint
import app.revanced.patches.music.video.information.fingerprints.VideoQualityListFingerprint import app.revanced.patches.music.video.information.fingerprints.VideoQualityListFingerprint
import app.revanced.patches.music.video.information.fingerprints.VideoQualityTextFingerprint import app.revanced.patches.music.video.information.fingerprints.VideoQualityTextFingerprint
import app.revanced.patches.music.video.videoid.VideoIdPatch
import app.revanced.patches.shared.fingerprints.MdxPlayerDirectorSetVideoStageFingerprint import app.revanced.patches.shared.fingerprints.MdxPlayerDirectorSetVideoStageFingerprint
import app.revanced.util.addFieldAndInstructions import app.revanced.patches.shared.fingerprints.VideoLengthFingerprint
import app.revanced.util.addStaticFieldToIntegration
import app.revanced.util.alsoResolve
import app.revanced.util.getReference import app.revanced.util.getReference
import app.revanced.util.getTargetIndexWithFieldReferenceTypeReversedOrThrow
import app.revanced.util.getTargetIndexWithMethodReferenceNameReversedOrThrow
import app.revanced.util.getWalkerMethod import app.revanced.util.getWalkerMethod
import app.revanced.util.indexOfFirstInstructionOrThrow import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
import com.android.tools.smali.dexlib2.iface.reference.MethodReference import com.android.tools.smali.dexlib2.iface.reference.MethodReference
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodImplementation import com.android.tools.smali.dexlib2.immutable.ImmutableMethodImplementation
@ -45,10 +41,7 @@ import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
import com.android.tools.smali.dexlib2.util.MethodUtil import com.android.tools.smali.dexlib2.util.MethodUtil
@Patch( @Patch(
dependencies = [ dependencies = [SharedResourceIdPatch::class]
SharedResourceIdPatch::class,
VideoIdPatch::class
]
) )
@Suppress("MemberVisibilityCanBePrivate") @Suppress("MemberVisibilityCanBePrivate")
object VideoInformationPatch : BytecodePatch( object VideoInformationPatch : BytecodePatch(
@ -56,8 +49,9 @@ object VideoInformationPatch : BytecodePatch(
MdxPlayerDirectorSetVideoStageFingerprint, MdxPlayerDirectorSetVideoStageFingerprint,
PlayerControllerSetTimeReferenceFingerprint, PlayerControllerSetTimeReferenceFingerprint,
PlaybackSpeedParentFingerprint, PlaybackSpeedParentFingerprint,
SeekBarConstructorFingerprint,
VideoEndFingerprint, VideoEndFingerprint,
VideoIdFingerprint,
VideoLengthFingerprint,
VideoQualityListFingerprint, VideoQualityListFingerprint,
VideoQualityTextFingerprint VideoQualityTextFingerprint
) )
@ -65,6 +59,20 @@ object VideoInformationPatch : BytecodePatch(
private const val INTEGRATIONS_CLASS_DESCRIPTOR = private const val INTEGRATIONS_CLASS_DESCRIPTOR =
"$SHARED_PATH/VideoInformation;" "$SHARED_PATH/VideoInformation;"
private const val REGISTER_PLAYER_RESPONSE_MODEL = 4
private const val REGISTER_VIDEO_ID = 0
private const val REGISTER_VIDEO_LENGTH = 1
@Suppress("unused")
private const val REGISTER_VIDEO_LENGTH_DUMMY = 2
private lateinit var PLAYER_RESPONSE_MODEL_CLASS_DESCRIPTOR: String
private lateinit var videoIdMethodCall: String
private lateinit var videoLengthMethodCall: String
private lateinit var videoInformationMethod: MutableMethod
/** /**
* Used in [VideoEndFingerprint] and [MdxPlayerDirectorSetVideoStageFingerprint]. * Used in [VideoEndFingerprint] and [MdxPlayerDirectorSetVideoStageFingerprint].
* Since both classes are inherited from the same class, * Since both classes are inherited from the same class,
@ -73,7 +81,6 @@ object VideoInformationPatch : BytecodePatch(
private var seekSourceEnumType = "" private var seekSourceEnumType = ""
private var seekSourceMethodName = "" private var seekSourceMethodName = ""
private lateinit var videoInformationMutableClass: MutableClass
private lateinit var context: BytecodeContext private lateinit var context: BytecodeContext
private lateinit var playerConstructorMethod: MutableMethod private lateinit var playerConstructorMethod: MutableMethod
@ -86,7 +93,6 @@ object VideoInformationPatch : BytecodePatch(
private var videoTimeConstructorInsertIndex = 2 private var videoTimeConstructorInsertIndex = 2
// Used by other patches. // Used by other patches.
lateinit var rectangleFieldName: String
internal lateinit var playbackSpeedResult: MethodFingerprintResult internal lateinit var playbackSpeedResult: MethodFingerprintResult
private fun addSeekInterfaceMethods( private fun addSeekInterfaceMethods(
@ -109,7 +115,7 @@ object VideoInformationPatch : BytecodePatch(
4, """ 4, """
# first enum (field a) is SEEK_SOURCE_UNKNOWN # first enum (field a) is SEEK_SOURCE_UNKNOWN
sget-object v0, $seekSourceEnumType->a:$seekSourceEnumType sget-object v0, $seekSourceEnumType->a:$seekSourceEnumType
invoke-virtual {p0, p1, p2, v0}, ${definingClass}->$seekMethodName(J$seekSourceEnumType)Z invoke-virtual {p0, p1, p2, v0}, $definingClass->$seekMethodName(J$seekSourceEnumType)Z
move-result p1 move-result p1
return p1 return p1
""".toInstructions(), """.toInstructions(),
@ -130,21 +136,18 @@ object VideoInformationPatch : BytecodePatch(
return v0 return v0
""" """
videoInformationMutableClass.addFieldAndInstructions( context.addStaticFieldToIntegration(
context, INTEGRATIONS_CLASS_DESCRIPTOR,
methodName, methodName,
fieldName, fieldName,
definingClass, definingClass,
smaliInstructions, smaliInstructions
true
) )
} }
} }
override fun execute(context: BytecodeContext) { override fun execute(context: BytecodeContext) {
this.context = context this.context = context
videoInformationMutableClass =
context.findClass(INTEGRATIONS_CLASS_DESCRIPTOR)!!.mutableClass
VideoEndFingerprint.resultOrThrow().let { VideoEndFingerprint.resultOrThrow().let {
it.mutableMethod.apply { it.mutableMethod.apply {
@ -194,6 +197,34 @@ object VideoInformationPatch : BytecodePatch(
} }
} }
/**
* Set current video information
*/
VideoIdFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val playerResponseModelIndex = it.scanResult.patternScanResult!!.startIndex
PLAYER_RESPONSE_MODEL_CLASS_DESCRIPTOR =
getInstruction(playerResponseModelIndex)
.getReference<MethodReference>()
?.definingClass
?: throw PatchException("Could not find Player Response Model class")
videoIdMethodCall =
VideoIdFingerprint.getPlayerResponseInstruction("Ljava/lang/String;")
videoLengthMethodCall =
VideoLengthFingerprint.getPlayerResponseInstruction("J")
videoInformationMethod = getVideoInformationMethod()
it.mutableClass.methods.add(videoInformationMethod)
addInstruction(
playerResponseModelIndex + 2,
"invoke-direct/range {p0 .. p1}, $definingClass->setVideoInformation($PLAYER_RESPONSE_MODEL_CLASS_DESCRIPTOR)V"
)
}
}
/** /**
* Set the video time method * Set the video time method
*/ */
@ -210,47 +241,19 @@ object VideoInformationPatch : BytecodePatch(
/** /**
* Set current video length * Set current video length
*/ */
VideoLengthFingerprint.resolve( videoLengthHook("$INTEGRATIONS_CLASS_DESCRIPTOR->setVideoLength(J)V")
context,
SeekBarConstructorFingerprint.resultOrThrow().classDef
)
VideoLengthFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val invalidateIndex =
getTargetIndexWithMethodReferenceNameReversedOrThrow("invalidate")
val rectangleIndex = getTargetIndexWithFieldReferenceTypeReversedOrThrow(
invalidateIndex + 1,
"Landroid/graphics/Rect;"
)
rectangleFieldName =
(getInstruction<ReferenceInstruction>(rectangleIndex).reference as FieldReference).name
val videoLengthRegisterIndex = it.scanResult.patternScanResult!!.startIndex + 1
val videoLengthRegister =
getInstruction<OneRegisterInstruction>(videoLengthRegisterIndex).registerA
val dummyRegisterForLong =
videoLengthRegister + 1 // required for long values since they are wide
addInstruction(
videoLengthRegisterIndex + 1,
"invoke-static {v$videoLengthRegister, v$dummyRegisterForLong}, $INTEGRATIONS_CLASS_DESCRIPTOR->setVideoLength(J)V"
)
}
}
/** /**
* Set current video id * Set current video id
*/ */
VideoIdPatch.hookVideoId("$INTEGRATIONS_CLASS_DESCRIPTOR->setVideoId(Ljava/lang/String;)V") videoIdHook("$INTEGRATIONS_CLASS_DESCRIPTOR->setVideoId(Ljava/lang/String;)V")
/** /**
* Hook current playback speed * Hook current playback speed
*/ */
PlaybackSpeedFingerprint.resolve( PlaybackSpeedFingerprint.alsoResolve(
context, context, PlaybackSpeedParentFingerprint
PlaybackSpeedParentFingerprint.resultOrThrow().classDef ).let {
)
PlaybackSpeedFingerprint.resultOrThrow().let {
it.mutableMethod.apply { it.mutableMethod.apply {
playbackSpeedResult = it playbackSpeedResult = it
val endIndex = it.scanResult.patternScanResult!!.endIndex val endIndex = it.scanResult.patternScanResult!!.endIndex
@ -294,13 +297,12 @@ object VideoInformationPatch : BytecodePatch(
return-void return-void
""" """
videoInformationMutableClass.addFieldAndInstructions( VideoInformationPatch.context.addStaticFieldToIntegration(
context, INTEGRATIONS_CLASS_DESCRIPTOR,
"overrideVideoQuality", "overrideVideoQuality",
"videoQualityClass", "videoQualityClass",
videoQualityClass, videoQualityClass,
smaliInstructions, smaliInstructions
true
) )
} }
@ -318,6 +320,49 @@ object VideoInformationPatch : BytecodePatch(
} }
} }
private fun MethodFingerprint.getPlayerResponseInstruction(returnType: String): String {
resultOrThrow().mutableMethod.apply {
val targetReference = getInstruction<ReferenceInstruction>(
indexOfFirstInstructionOrThrow {
val reference = getReference<MethodReference>()
(opcode == Opcode.INVOKE_INTERFACE_RANGE || opcode == Opcode.INVOKE_INTERFACE) &&
reference?.definingClass == PLAYER_RESPONSE_MODEL_CLASS_DESCRIPTOR &&
reference.returnType == returnType
}
).reference
return "invoke-interface/range {v$REGISTER_PLAYER_RESPONSE_MODEL .. v$REGISTER_PLAYER_RESPONSE_MODEL}, $targetReference"
}
}
private fun MutableMethod.getVideoInformationMethod(): MutableMethod =
ImmutableMethod(
definingClass,
"setVideoInformation",
listOf(
ImmutableMethodParameter(
PLAYER_RESPONSE_MODEL_CLASS_DESCRIPTOR,
annotations,
null
)
),
"V",
AccessFlags.PRIVATE or AccessFlags.FINAL,
annotations,
null,
ImmutableMethodImplementation(
REGISTER_PLAYER_RESPONSE_MODEL + 1, """
$videoIdMethodCall
move-result-object v$REGISTER_VIDEO_ID
$videoLengthMethodCall
move-result-wide v$REGISTER_VIDEO_LENGTH
return-void
""".toInstructions(),
null,
null
)
).toMutable()
private fun MutableMethod.insert(insertIndex: Int, register: String, descriptor: String) = private fun MutableMethod.insert(insertIndex: Int, register: String, descriptor: String) =
addInstruction(insertIndex, "invoke-static { $register }, $descriptor") addInstruction(insertIndex, "invoke-static { $register }, $descriptor")
@ -351,6 +396,24 @@ object VideoInformationPatch : BytecodePatch(
"invoke-static { }, $targetMethodClass->$targetMethodName()V" "invoke-static { }, $targetMethodClass->$targetMethodName()V"
) )
internal fun videoIdHook(
descriptor: String
) = videoInformationMethod.apply {
addInstruction(
implementation!!.instructions.lastIndex,
"invoke-static {v$REGISTER_VIDEO_ID}, $descriptor"
)
}
internal fun videoLengthHook(
descriptor: String
) = videoInformationMethod.apply {
addInstruction(
implementation!!.instructions.lastIndex,
"invoke-static {v$REGISTER_VIDEO_LENGTH, v$REGISTER_VIDEO_LENGTH_DUMMY}, $descriptor"
)
}
/** /**
* Hook the video time. * Hook the video time.
* The hook is usually called once per second. * The hook is usually called once per second.

View File

@ -1,4 +1,4 @@
package app.revanced.patches.music.video.videoid.fingerprints package app.revanced.patches.music.video.information.fingerprints
import app.revanced.patcher.extensions.or import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.fingerprint.MethodFingerprint

View File

@ -1,16 +0,0 @@
package app.revanced.patches.music.video.information.fingerprints
import app.revanced.util.fingerprint.MethodReferenceNameFingerprint
import com.android.tools.smali.dexlib2.Opcode
internal object VideoLengthFingerprint : MethodReferenceNameFingerprint(
opcodes = listOf(
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_WIDE,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_WIDE,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_WIDE
),
reference = { "invalidate" }
)

View File

@ -12,13 +12,13 @@ import app.revanced.patches.music.utils.settings.SettingsPatch
import app.revanced.patches.music.video.information.VideoInformationPatch import app.revanced.patches.music.video.information.VideoInformationPatch
import app.revanced.patches.music.video.playback.fingerprints.PlaybackSpeedBottomSheetFingerprint import app.revanced.patches.music.video.playback.fingerprints.PlaybackSpeedBottomSheetFingerprint
import app.revanced.patches.music.video.playback.fingerprints.UserQualityChangeFingerprint import app.revanced.patches.music.video.playback.fingerprints.UserQualityChangeFingerprint
import app.revanced.patches.music.video.videoid.VideoIdPatch import app.revanced.util.findMethodOrThrow
import app.revanced.util.getTargetIndexOrThrow import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.patch.BaseBytecodePatch import app.revanced.util.patch.BaseBytecodePatch
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction21c
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
@Suppress("unused") @Suppress("unused")
@ -29,7 +29,6 @@ object VideoPlaybackPatch : BaseBytecodePatch(
dependencies = setOf( dependencies = setOf(
CustomPlaybackSpeedPatch::class, CustomPlaybackSpeedPatch::class,
SettingsPatch::class, SettingsPatch::class,
VideoIdPatch::class,
VideoInformationPatch::class VideoInformationPatch::class
), ),
compatiblePackages = COMPATIBLE_PACKAGE, compatiblePackages = COMPATIBLE_PACKAGE,
@ -52,7 +51,7 @@ object VideoPlaybackPatch : BaseBytecodePatch(
it.mutableClass.methods.find { method -> method.name == "onItemClick" } it.mutableClass.methods.find { method -> method.name == "onItemClick" }
onItemClickMethod?.apply { onItemClickMethod?.apply {
val targetIndex = getTargetIndexOrThrow(Opcode.IGET) val targetIndex = indexOfFirstInstructionOrThrow(Opcode.IGET)
val targetRegister = val targetRegister =
getInstruction<TwoRegisterInstruction>(targetIndex).registerA getInstruction<TwoRegisterInstruction>(targetIndex).registerA
@ -86,23 +85,18 @@ object VideoPlaybackPatch : BaseBytecodePatch(
it.mutableMethod.apply { it.mutableMethod.apply {
val endIndex = it.scanResult.patternScanResult!!.endIndex val endIndex = it.scanResult.patternScanResult!!.endIndex
val qualityChangedClass = val qualityChangedClass =
context.findClass( getInstruction<ReferenceInstruction>(endIndex).reference.toString()
(getInstruction<BuilderInstruction21c>(endIndex))
.reference.toString()
)!!
.mutableClass
val onItemClickMethod = context.findMethodOrThrow(qualityChangedClass) {
qualityChangedClass.methods.find { method -> method.name == "onItemClick" } name == "onItemClick"
}.addInstruction(
onItemClickMethod?.addInstruction(
0, 0,
"invoke-static {}, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->userSelectedVideoQuality()V" "invoke-static {}, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->userSelectedVideoQuality()V"
) ?: throw PatchException("Failed to find onItemClick method") )
} }
} }
VideoIdPatch.hookVideoId("$INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;)V") VideoInformationPatch.videoIdHook("$INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;)V")
// endregion // endregion

View File

@ -1,38 +0,0 @@
package app.revanced.patches.music.video.videoid
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patches.music.video.videoid.fingerprints.VideoIdFingerprint
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
object VideoIdPatch : BytecodePatch(
setOf(VideoIdFingerprint)
) {
private var videoIdRegister = 0
private var videoIdInsertIndex = 0
private lateinit var videoIdMethod: MutableMethod
override fun execute(context: BytecodeContext) {
VideoIdFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
videoIdMethod = this
videoIdInsertIndex = it.scanResult.patternScanResult!!.startIndex + 2
videoIdRegister =
getInstruction<OneRegisterInstruction>(videoIdInsertIndex - 1).registerA
}
}
}
fun hookVideoId(
methodDescriptor: String
) = videoIdMethod.addInstruction(
videoIdInsertIndex++,
"invoke-static {v$videoIdRegister}, $methodDescriptor"
)
}

View File

@ -12,12 +12,15 @@ import app.revanced.patches.reddit.utils.compatibility.Constants.COMPATIBLE_PACK
import app.revanced.patches.reddit.utils.integrations.Constants.PATCHES_PATH import app.revanced.patches.reddit.utils.integrations.Constants.PATCHES_PATH
import app.revanced.patches.reddit.utils.settings.SettingsBytecodePatch.updateSettingsStatus import app.revanced.patches.reddit.utils.settings.SettingsBytecodePatch.updateSettingsStatus
import app.revanced.patches.reddit.utils.settings.SettingsPatch import app.revanced.patches.reddit.utils.settings.SettingsPatch
import app.revanced.util.getTargetIndexWithFieldReferenceNameOrThrow import app.revanced.util.getReference
import app.revanced.util.getTargetIndexWithMethodReferenceNameOrThrow import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.patch.BaseBytecodePatch import app.revanced.util.patch.BaseBytecodePatch
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
@Suppress("unused") @Suppress("unused")
object AdsPatch : BaseBytecodePatch( object AdsPatch : BaseBytecodePatch(
@ -42,7 +45,9 @@ object AdsPatch : BaseBytecodePatch(
// region Filter promoted ads (does not work in popular or latest feed) // region Filter promoted ads (does not work in popular or latest feed)
AdPostFingerprint.resultOrThrow().let { AdPostFingerprint.resultOrThrow().let {
it.mutableMethod.apply { it.mutableMethod.apply {
val targetIndex = getTargetIndexWithFieldReferenceNameOrThrow("children") val targetIndex = indexOfFirstInstructionOrThrow {
getReference<FieldReference>()?.name == "children"
}
val targetRegister = getInstruction<TwoRegisterInstruction>(targetIndex).registerA val targetRegister = getInstruction<TwoRegisterInstruction>(targetIndex).registerA
addInstructions( addInstructions(
@ -59,7 +64,10 @@ object AdsPatch : BaseBytecodePatch(
// By removing the appending instruction no ad posts gets appended to the feed. // By removing the appending instruction no ad posts gets appended to the feed.
NewAdPostFingerprint.resultOrThrow().let { NewAdPostFingerprint.resultOrThrow().let {
it.mutableMethod.apply { it.mutableMethod.apply {
val targetIndex = getTargetIndexWithMethodReferenceNameOrThrow("add") val targetIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.INVOKE_VIRTUAL
&& getReference<MethodReference>()?.toString() == "Ljava/util/ArrayList;->add(Ljava/lang/Object;)Z"
}
val targetInstruction = getInstruction<FiveRegisterInstruction>(targetIndex) val targetInstruction = getInstruction<FiveRegisterInstruction>(targetIndex)
replaceInstruction( replaceInstruction(

View File

@ -9,15 +9,15 @@ import app.revanced.patches.reddit.utils.compatibility.Constants.COMPATIBLE_PACK
import app.revanced.patches.reddit.utils.integrations.Constants.PATCHES_PATH import app.revanced.patches.reddit.utils.integrations.Constants.PATCHES_PATH
import app.revanced.patches.reddit.utils.settings.SettingsBytecodePatch.updateSettingsStatus import app.revanced.patches.reddit.utils.settings.SettingsBytecodePatch.updateSettingsStatus
import app.revanced.patches.reddit.utils.settings.SettingsPatch import app.revanced.patches.reddit.utils.settings.SettingsPatch
import app.revanced.util.getTargetIndexOrThrow import app.revanced.util.getReference
import app.revanced.util.getTargetIndexReversedOrThrow import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.getTargetIndexWithFieldReferenceNameOrThrow import app.revanced.util.indexOfFirstInstructionReversedOrThrow
import app.revanced.util.getTargetIndexWithReferenceOrThrow
import app.revanced.util.patch.BaseBytecodePatch import app.revanced.util.patch.BaseBytecodePatch
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
import com.android.tools.smali.dexlib2.iface.reference.Reference import com.android.tools.smali.dexlib2.iface.reference.Reference
@Suppress("unused") @Suppress("unused")
@ -40,20 +40,31 @@ object RecentlyVisitedShelfPatch : BaseBytecodePatch(
it.mutableClass.methods.find { method -> method.name == "<init>" } it.mutableClass.methods.find { method -> method.name == "<init>" }
?.apply { ?.apply {
val recentlyVisitedFieldIndex = val recentlyVisitedFieldIndex = indexOfFirstInstructionOrThrow {
getTargetIndexWithFieldReferenceNameOrThrow("RECENTLY_VISITED") getReference<FieldReference>()?.name == "RECENTLY_VISITED"
}
val recentlyVisitedObjectIndex = val recentlyVisitedObjectIndex =
getTargetIndexOrThrow(recentlyVisitedFieldIndex, Opcode.IPUT_OBJECT) indexOfFirstInstructionOrThrow(
recentlyVisitedFieldIndex,
Opcode.IPUT_OBJECT
)
recentlyVisitedReference = recentlyVisitedReference =
getInstruction<ReferenceInstruction>(recentlyVisitedObjectIndex).reference getInstruction<ReferenceInstruction>(recentlyVisitedObjectIndex).reference
} ?: throw PatchException("Constructor method not found!") } ?: throw PatchException("Constructor method not found!")
it.mutableMethod.apply { it.mutableMethod.apply {
val recentlyVisitedObjectIndex = val recentlyVisitedObjectIndex = indexOfFirstInstructionOrThrow {
getTargetIndexWithReferenceOrThrow(recentlyVisitedReference.toString()) getReference<FieldReference>()?.toString() == recentlyVisitedReference.toString()
}
arrayOf( arrayOf(
getTargetIndexOrThrow(recentlyVisitedObjectIndex, Opcode.INVOKE_STATIC), indexOfFirstInstructionOrThrow(
getTargetIndexReversedOrThrow(recentlyVisitedObjectIndex, Opcode.INVOKE_STATIC) recentlyVisitedObjectIndex,
Opcode.INVOKE_STATIC
),
indexOfFirstInstructionReversedOrThrow(
recentlyVisitedObjectIndex,
Opcode.INVOKE_STATIC
)
).forEach { staticIndex -> ).forEach { staticIndex ->
val insertRegister = val insertRegister =
getInstruction<OneRegisterInstruction>(staticIndex + 1).registerA getInstruction<OneRegisterInstruction>(staticIndex + 1).registerA

View File

@ -3,14 +3,14 @@ package app.revanced.patches.reddit.layout.screenshotpopup.fingerprints
import app.revanced.patcher.extensions.or import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patches.reddit.utils.resourceid.SharedResourceIdPatch.ScreenShotShareBanner import app.revanced.patches.reddit.utils.resourceid.SharedResourceIdPatch.ScreenShotShareBanner
import app.revanced.util.containsWideLiteralInstructionIndex import app.revanced.util.containsWideLiteralInstructionValue
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
internal object ScreenshotTakenBannerFingerprint : MethodFingerprint( internal object ScreenshotTakenBannerFingerprint : MethodFingerprint(
returnType = "V", returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
customFingerprint = { methodDef, classDef -> customFingerprint = { methodDef, classDef ->
methodDef.containsWideLiteralInstructionIndex(ScreenShotShareBanner) methodDef.containsWideLiteralInstructionValue(ScreenShotShareBanner)
&& classDef.sourceFile == "ScreenshotTakenBanner.kt" && classDef.sourceFile == "ScreenshotTakenBanner.kt"
} }
) )

View File

@ -12,7 +12,7 @@ import app.revanced.patches.reddit.utils.resourceid.SharedResourceIdPatch.Cancel
import app.revanced.patches.reddit.utils.resourceid.SharedResourceIdPatch.TextAppearanceRedditBaseOldButtonColored import app.revanced.patches.reddit.utils.resourceid.SharedResourceIdPatch.TextAppearanceRedditBaseOldButtonColored
import app.revanced.patches.reddit.utils.settings.SettingsBytecodePatch.updateSettingsStatus import app.revanced.patches.reddit.utils.settings.SettingsBytecodePatch.updateSettingsStatus
import app.revanced.patches.reddit.utils.settings.SettingsPatch import app.revanced.patches.reddit.utils.settings.SettingsPatch
import app.revanced.util.getWideLiteralInstructionIndex import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow
import app.revanced.util.patch.BaseBytecodePatch import app.revanced.util.patch.BaseBytecodePatch
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
@ -39,7 +39,8 @@ object SubRedditDialogPatch : BaseBytecodePatch(
FrequentUpdatesSheetScreenFingerprint.resultOrThrow().let { FrequentUpdatesSheetScreenFingerprint.resultOrThrow().let {
it.mutableMethod.apply { it.mutableMethod.apply {
val cancelButtonViewIndex = getWideLiteralInstructionIndex(CancelButton) + 2 val cancelButtonViewIndex =
indexOfFirstWideLiteralInstructionValueOrThrow(CancelButton) + 2
val cancelButtonViewRegister = val cancelButtonViewRegister =
getInstruction<OneRegisterInstruction>(cancelButtonViewIndex).registerA getInstruction<OneRegisterInstruction>(cancelButtonViewIndex).registerA
@ -53,7 +54,9 @@ object SubRedditDialogPatch : BaseBytecodePatch(
RedditAlertDialogsFingerprint.resultOrThrow().let { RedditAlertDialogsFingerprint.resultOrThrow().let {
it.mutableMethod.apply { it.mutableMethod.apply {
val insertIndex = val insertIndex =
getWideLiteralInstructionIndex(TextAppearanceRedditBaseOldButtonColored) + 1 indexOfFirstWideLiteralInstructionValueOrThrow(
TextAppearanceRedditBaseOldButtonColored
) + 1
val insertRegister = getInstruction<FiveRegisterInstruction>(insertIndex).registerC val insertRegister = getInstruction<FiveRegisterInstruction>(insertIndex).registerC
addInstruction( addInstruction(

View File

@ -3,14 +3,14 @@ package app.revanced.patches.reddit.layout.subredditdialog.fingerprints
import app.revanced.patcher.extensions.or import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patches.reddit.utils.resourceid.SharedResourceIdPatch.CancelButton import app.revanced.patches.reddit.utils.resourceid.SharedResourceIdPatch.CancelButton
import app.revanced.util.containsWideLiteralInstructionIndex import app.revanced.util.containsWideLiteralInstructionValue
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
internal object FrequentUpdatesSheetScreenFingerprint : MethodFingerprint( internal object FrequentUpdatesSheetScreenFingerprint : MethodFingerprint(
returnType = "Landroid/view/View;", returnType = "Landroid/view/View;",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
customFingerprint = { methodDef, classDef -> customFingerprint = { methodDef, classDef ->
methodDef.containsWideLiteralInstructionIndex(CancelButton) methodDef.containsWideLiteralInstructionValue(CancelButton)
&& classDef.sourceFile == "FrequentUpdatesSheetScreen.kt" && classDef.sourceFile == "FrequentUpdatesSheetScreen.kt"
} }
) )

View File

@ -3,14 +3,14 @@ package app.revanced.patches.reddit.layout.subredditdialog.fingerprints
import app.revanced.patcher.extensions.or import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patches.reddit.utils.resourceid.SharedResourceIdPatch.TextAppearanceRedditBaseOldButtonColored import app.revanced.patches.reddit.utils.resourceid.SharedResourceIdPatch.TextAppearanceRedditBaseOldButtonColored
import app.revanced.util.containsWideLiteralInstructionIndex import app.revanced.util.containsWideLiteralInstructionValue
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
internal object RedditAlertDialogsFingerprint : MethodFingerprint( internal object RedditAlertDialogsFingerprint : MethodFingerprint(
returnType = "V", returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
customFingerprint = { methodDef, classDef -> customFingerprint = { methodDef, classDef ->
methodDef.containsWideLiteralInstructionIndex(TextAppearanceRedditBaseOldButtonColored) methodDef.containsWideLiteralInstructionValue(TextAppearanceRedditBaseOldButtonColored)
&& classDef.sourceFile == "RedditAlertDialogs.kt" && classDef.sourceFile == "RedditAlertDialogs.kt"
} }
) )

View File

@ -10,7 +10,7 @@ import app.revanced.patches.reddit.utils.resourceid.SharedResourceIdPatch
import app.revanced.patches.reddit.utils.resourceid.SharedResourceIdPatch.ToolBarNavSearchCtaContainer import app.revanced.patches.reddit.utils.resourceid.SharedResourceIdPatch.ToolBarNavSearchCtaContainer
import app.revanced.patches.reddit.utils.settings.SettingsBytecodePatch.updateSettingsStatus import app.revanced.patches.reddit.utils.settings.SettingsBytecodePatch.updateSettingsStatus
import app.revanced.patches.reddit.utils.settings.SettingsPatch import app.revanced.patches.reddit.utils.settings.SettingsPatch
import app.revanced.util.getWideLiteralInstructionIndex import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow
import app.revanced.util.patch.BaseBytecodePatch import app.revanced.util.patch.BaseBytecodePatch
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
@ -35,7 +35,7 @@ object ToolBarButtonPatch : BaseBytecodePatch(
HomePagerScreenFingerprint.resultOrThrow().let { HomePagerScreenFingerprint.resultOrThrow().let {
it.mutableMethod.apply { it.mutableMethod.apply {
val targetIndex = val targetIndex =
getWideLiteralInstructionIndex(ToolBarNavSearchCtaContainer) + 3 indexOfFirstWideLiteralInstructionValueOrThrow(ToolBarNavSearchCtaContainer) + 3
val targetRegister = val targetRegister =
getInstruction<OneRegisterInstruction>(targetIndex - 1).registerA getInstruction<OneRegisterInstruction>(targetIndex - 1).registerA

View File

@ -3,7 +3,7 @@ package app.revanced.patches.reddit.layout.toolbar.fingerprints
import app.revanced.patcher.extensions.or import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patches.reddit.utils.resourceid.SharedResourceIdPatch.ToolBarNavSearchCtaContainer import app.revanced.patches.reddit.utils.resourceid.SharedResourceIdPatch.ToolBarNavSearchCtaContainer
import app.revanced.util.containsWideLiteralInstructionIndex import app.revanced.util.containsWideLiteralInstructionValue
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
internal object HomePagerScreenFingerprint : MethodFingerprint( internal object HomePagerScreenFingerprint : MethodFingerprint(
@ -12,6 +12,6 @@ internal object HomePagerScreenFingerprint : MethodFingerprint(
parameters = listOf("Landroid/view/LayoutInflater;", "Landroid/view/ViewGroup;"), parameters = listOf("Landroid/view/LayoutInflater;", "Landroid/view/ViewGroup;"),
customFingerprint = { methodDef, _ -> customFingerprint = { methodDef, _ ->
methodDef.definingClass.endsWith("/HomePagerScreen;") methodDef.definingClass.endsWith("/HomePagerScreen;")
&& methodDef.containsWideLiteralInstructionIndex(ToolBarNavSearchCtaContainer) && methodDef.containsWideLiteralInstructionValue(ToolBarNavSearchCtaContainer)
} }
) )

View File

@ -9,7 +9,7 @@ import app.revanced.patches.reddit.utils.compatibility.Constants.COMPATIBLE_PACK
import app.revanced.patches.reddit.utils.integrations.Constants.PATCHES_PATH import app.revanced.patches.reddit.utils.integrations.Constants.PATCHES_PATH
import app.revanced.patches.reddit.utils.settings.SettingsBytecodePatch.updateSettingsStatus import app.revanced.patches.reddit.utils.settings.SettingsBytecodePatch.updateSettingsStatus
import app.revanced.patches.reddit.utils.settings.SettingsPatch import app.revanced.patches.reddit.utils.settings.SettingsPatch
import app.revanced.util.getStringInstructionIndex import app.revanced.util.indexOfFirstStringInstructionOrThrow
import app.revanced.util.patch.BaseBytecodePatch import app.revanced.util.patch.BaseBytecodePatch
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
@ -27,7 +27,7 @@ object OpenLinksExternallyPatch : BaseBytecodePatch(
override fun execute(context: BytecodeContext) { override fun execute(context: BytecodeContext) {
ScreenNavigatorFingerprint.resultOrThrow().let { ScreenNavigatorFingerprint.resultOrThrow().let {
it.mutableMethod.apply { it.mutableMethod.apply {
val insertIndex = getStringInstructionIndex("uri") + 2 val insertIndex = indexOfFirstStringInstructionOrThrow("uri") + 2
addInstructionsWithLabels( addInstructionsWithLabels(
insertIndex, """ insertIndex, """

View File

@ -15,8 +15,8 @@ import app.revanced.patches.reddit.utils.settings.fingerprints.AcknowledgementsL
import app.revanced.patches.reddit.utils.settings.fingerprints.OssLicensesMenuActivityOnCreateFingerprint import app.revanced.patches.reddit.utils.settings.fingerprints.OssLicensesMenuActivityOnCreateFingerprint
import app.revanced.patches.reddit.utils.settings.fingerprints.SettingsStatusLoadFingerprint import app.revanced.patches.reddit.utils.settings.fingerprints.SettingsStatusLoadFingerprint
import app.revanced.patches.shared.fingerprints.SharedSettingFingerprint import app.revanced.patches.shared.fingerprints.SharedSettingFingerprint
import app.revanced.util.getTargetIndexOrThrow import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.getWideLiteralInstructionIndex import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
@ -39,7 +39,7 @@ object SettingsBytecodePatch : BytecodePatch(
internal fun updateSettingsLabel(label: String) = internal fun updateSettingsLabel(label: String) =
acknowledgementsLabelBuilderMethod.apply { acknowledgementsLabelBuilderMethod.apply {
val insertIndex = val insertIndex =
getWideLiteralInstructionIndex(LabelAcknowledgements) + 3 indexOfFirstWideLiteralInstructionValueOrThrow(LabelAcknowledgements) + 3
val insertRegister = val insertRegister =
getInstruction<OneRegisterInstruction>(insertIndex - 1).registerA getInstruction<OneRegisterInstruction>(insertIndex - 1).registerA
@ -62,7 +62,7 @@ object SettingsBytecodePatch : BytecodePatch(
*/ */
SharedSettingFingerprint.resultOrThrow().let { SharedSettingFingerprint.resultOrThrow().let {
it.mutableMethod.apply { it.mutableMethod.apply {
val stringIndex = getTargetIndexOrThrow(Opcode.CONST_STRING) val stringIndex = indexOfFirstInstructionOrThrow(Opcode.CONST_STRING)
val stringRegister = getInstruction<OneRegisterInstruction>(stringIndex).registerA val stringRegister = getInstruction<OneRegisterInstruction>(stringIndex).registerA
replaceInstruction( replaceInstruction(

View File

@ -3,7 +3,7 @@ package app.revanced.patches.reddit.utils.settings.fingerprints
import app.revanced.patcher.extensions.or import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patches.reddit.utils.resourceid.SharedResourceIdPatch.LabelAcknowledgements import app.revanced.patches.reddit.utils.resourceid.SharedResourceIdPatch.LabelAcknowledgements
import app.revanced.util.containsWideLiteralInstructionIndex import app.revanced.util.containsWideLiteralInstructionValue
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
internal object AcknowledgementsLabelBuilderFingerprint : MethodFingerprint( internal object AcknowledgementsLabelBuilderFingerprint : MethodFingerprint(
@ -12,6 +12,6 @@ internal object AcknowledgementsLabelBuilderFingerprint : MethodFingerprint(
parameters = listOf("Landroidx/preference/Preference;"), parameters = listOf("Landroidx/preference/Preference;"),
customFingerprint = { methodDef, _ -> customFingerprint = { methodDef, _ ->
methodDef.definingClass.startsWith("Lcom/reddit/screen/settings/preferences/") methodDef.definingClass.startsWith("Lcom/reddit/screen/settings/preferences/")
&& methodDef.containsWideLiteralInstructionIndex(LabelAcknowledgements) && methodDef.containsWideLiteralInstructionValue(LabelAcknowledgements)
} }
) )

View File

@ -12,14 +12,12 @@ import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.shared.ads.fingerprints.MusicAdsFingerprint import app.revanced.patches.shared.ads.fingerprints.MusicAdsFingerprint
import app.revanced.patches.shared.ads.fingerprints.VideoAdsFingerprint import app.revanced.patches.shared.ads.fingerprints.VideoAdsFingerprint
import app.revanced.patches.shared.integrations.Constants.PATCHES_PATH import app.revanced.patches.shared.integrations.Constants.PATCHES_PATH
import app.revanced.util.getTargetIndexOrThrow import app.revanced.util.getReference
import app.revanced.util.getTargetIndexWithMethodReferenceNameOrThrow
import app.revanced.util.getWalkerMethod import app.revanced.util.getWalkerMethod
import app.revanced.util.getWideLiteralInstructionIndex
import app.revanced.util.indexOfFirstInstructionOrThrow import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.reference.FieldReference import com.android.tools.smali.dexlib2.iface.reference.FieldReference
@ -34,12 +32,16 @@ abstract class BaseAdsPatch(
VideoAdsFingerprint VideoAdsFingerprint
) )
) { ) {
private companion object {
const val INTEGRATIONS_CLASS_DESCRIPTOR =
"$PATCHES_PATH/FullscreenAdsPatch;"
}
override fun execute(context: BytecodeContext) { override fun execute(context: BytecodeContext) {
MusicAdsFingerprint.resultOrThrow().let { MusicAdsFingerprint.resultOrThrow().let {
it.mutableMethod.apply { it.mutableMethod.apply {
val targetIndex = indexOfFirstInstructionOrThrow { val targetIndex = indexOfFirstInstructionOrThrow {
val reference = ((this as? ReferenceInstruction)?.reference as? MethodReference) val reference = getReference<MethodReference>()
opcode == Opcode.INVOKE_VIRTUAL opcode == Opcode.INVOKE_VIRTUAL
&& reference?.returnType == "V" && reference?.returnType == "V"
&& reference.parameterTypes.size == 1 && reference.parameterTypes.size == 1
@ -72,7 +74,7 @@ abstract class BaseAdsPatch(
internal fun MethodFingerprintResult.hookNonLithoFullscreenAds(literal: Long) { internal fun MethodFingerprintResult.hookNonLithoFullscreenAds(literal: Long) {
mutableMethod.apply { mutableMethod.apply {
val targetIndex = getWideLiteralInstructionIndex(literal) + 2 val targetIndex = indexOfFirstWideLiteralInstructionValueOrThrow(literal) + 2
val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
addInstruction( addInstruction(
@ -82,7 +84,7 @@ abstract class BaseAdsPatch(
} }
} }
internal fun MethodFingerprintResult.hookLithoFullscreenAds(context: BytecodeContext) { internal fun MethodFingerprintResult.hookLithoFullscreenAds() {
mutableMethod.apply { mutableMethod.apply {
val dialogCodeIndex = scanResult.patternScanResult!!.endIndex val dialogCodeIndex = scanResult.patternScanResult!!.endIndex
val dialogCodeField = val dialogCodeField =
@ -90,58 +92,35 @@ abstract class BaseAdsPatch(
if (dialogCodeField.type != "I") if (dialogCodeField.type != "I")
throw PatchException("Invalid dialogCodeField: $dialogCodeField") throw PatchException("Invalid dialogCodeField: $dialogCodeField")
var prependInstructions = """
move-object/from16 v0, p1
move-object/from16 v1, p2
"""
if (parameterTypes.firstOrNull() != "[B") {
val toByteArrayReference = getInstruction<ReferenceInstruction>(
indexOfFirstInstructionOrThrow {
getReference<MethodReference>()?.name == "toByteArray"
}
).reference
prependInstructions += """
invoke-virtual {v0}, $toByteArrayReference
move-result-object v0
"""
}
// Disable fullscreen ads // Disable fullscreen ads
addInstructionsWithLabels( addInstructionsWithLabels(
0, 0, prependInstructions + """
""" check-cast v1, ${dialogCodeField.definingClass}
move-object/from16 v0, p2 iget v1, v1, $dialogCodeField
invoke-static {v0, v1}, $INTEGRATIONS_CLASS_DESCRIPTOR->disableFullscreenAds([BI)Z
# In the latest version of YouTube and YouTube Music, it is used after being cast move-result v1
if-eqz v1, :show
check-cast v0, ${dialogCodeField.definingClass} return-void
iget v0, v0, $dialogCodeField """, ExternalLabel("show", getInstruction(0))
invoke-static {v0}, $INTEGRATIONS_CLASS_DESCRIPTOR->disableFullscreenAds(I)Z
move-result v0
if-eqz v0, :show
return-void
""", ExternalLabel("show", getInstruction(0))
)
// Close fullscreen ads
// Find the instruction whose name is "show" in [MethodReference] and click the 'AlertDialog.BUTTON_POSITIVE' button.
// In this case, an instruction for 'getButton' must be added to smali, not in integrations
// (This custom dialog cannot be cast to [AlertDialog] or [Dialog])
val dialogIndex = getTargetIndexWithMethodReferenceNameOrThrow("show")
val dialogReference = getInstruction<ReferenceInstruction>(dialogIndex).reference
val dialogDefiningClass = (dialogReference as MethodReference).definingClass
val getButtonMethod = context.findClass(dialogDefiningClass)!!
.mutableClass.methods.first { method ->
method.parameters == listOf("I")
&& method.returnType == "Landroid/widget/Button;"
}
val getButtonCall =
dialogDefiningClass + "->" + getButtonMethod.name + "(I)Landroid/widget/Button;"
val dialogRegister = getInstruction<FiveRegisterInstruction>(dialogIndex).registerC
val freeIndex = getTargetIndexOrThrow(dialogIndex, Opcode.IF_EQZ)
val freeRegister = getInstruction<OneRegisterInstruction>(freeIndex).registerA
addInstructions(
dialogIndex + 1, """
# Get the 'AlertDialog.BUTTON_POSITIVE' from custom dialog
# Since this custom dialog cannot be cast to AlertDialog or Dialog,
# It should come from smali, not integrations.
const/4 v$freeRegister, -0x1
invoke-virtual {v$dialogRegister, v$freeRegister}, $getButtonCall
move-result-object v$freeRegister
invoke-static {v$freeRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->setCloseButton(Landroid/widget/Button;)V
"""
) )
} }
} }
private companion object {
const val INTEGRATIONS_CLASS_DESCRIPTOR =
"$PATCHES_PATH/FullscreenAdsPatch;"
}
} }

View File

@ -0,0 +1,56 @@
package app.revanced.patches.shared.captions
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.shared.captions.fingerprints.StoryboardRendererDecoderRecommendedLevelFingerprint
import app.revanced.patches.shared.captions.fingerprints.SubtitleTrackFingerprint
import app.revanced.patches.shared.fingerprints.StartVideoInformerFingerprint
import app.revanced.patches.shared.integrations.Constants.PATCHES_PATH
import app.revanced.util.resultOrThrow
@Patch(
description = "Disable forced auto captions for YouTube or YouTube Music."
)
object BaseAutoCaptionsPatch : BytecodePatch(
setOf(
StartVideoInformerFingerprint,
StoryboardRendererDecoderRecommendedLevelFingerprint,
SubtitleTrackFingerprint,
)
) {
private const val INTEGRATIONS_CLASS_DESCRIPTOR =
"$PATCHES_PATH/AutoCaptionsPatch;"
override fun execute(context: BytecodeContext) {
SubtitleTrackFingerprint.resultOrThrow().mutableMethod.apply {
addInstructionsWithLabels(
0, """
invoke-static {}, $INTEGRATIONS_CLASS_DESCRIPTOR->disableAutoCaptions()Z
move-result v0
if-eqz v0, :disabled
const/4 v0, 0x1
return v0
""", ExternalLabel("disabled", getInstruction(0))
)
}
mapOf(
StartVideoInformerFingerprint to 0,
StoryboardRendererDecoderRecommendedLevelFingerprint to 1
).forEach { (fingerprint, enabled) ->
fingerprint.resultOrThrow().mutableMethod.addInstructions(
0, """
const/4 v0, 0x$enabled
invoke-static {v0}, $INTEGRATIONS_CLASS_DESCRIPTOR->setCaptionsButtonStatus(Z)V
"""
)
}
}
}

View File

@ -1,4 +1,4 @@
package app.revanced.patches.youtube.general.autocaptions.fingerprints package app.revanced.patches.shared.captions.fingerprints
import app.revanced.patcher.extensions.or import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.fingerprint.MethodFingerprint
@ -7,6 +7,6 @@ import com.android.tools.smali.dexlib2.AccessFlags
internal object StoryboardRendererDecoderRecommendedLevelFingerprint : MethodFingerprint( internal object StoryboardRendererDecoderRecommendedLevelFingerprint : MethodFingerprint(
returnType = "V", returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("Lcom/google/android/libraries/youtube/innertube/model/player/PlayerResponseModel;"), parameters = listOf("L"),
strings = listOf("#-1#") strings = listOf("#-1#")
) )

View File

@ -1,4 +1,4 @@
package app.revanced.patches.shared.fingerprints package app.revanced.patches.shared.captions.fingerprints
import app.revanced.patcher.extensions.or import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.fingerprint.MethodFingerprint

View File

@ -8,14 +8,14 @@ import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patches.shared.customspeed.fingerprints.SpeedArrayGeneratorFingerprint import app.revanced.patches.shared.customspeed.fingerprints.SpeedArrayGeneratorFingerprint
import app.revanced.patches.shared.customspeed.fingerprints.SpeedLimiterFallBackFingerprint import app.revanced.patches.shared.customspeed.fingerprints.SpeedLimiterFallBackFingerprint
import app.revanced.patches.shared.customspeed.fingerprints.SpeedLimiterFingerprint import app.revanced.patches.shared.customspeed.fingerprints.SpeedLimiterFingerprint
import app.revanced.util.getTargetIndexOrThrow import app.revanced.util.getReference
import app.revanced.util.getTargetIndexWithFieldReferenceTypeOrThrow
import app.revanced.util.getTargetIndexWithMethodReferenceNameOrThrow
import app.revanced.util.indexOfFirstInstructionOrThrow import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.NarrowLiteralInstruction import com.android.tools.smali.dexlib2.iface.instruction.NarrowLiteralInstruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
abstract class BaseCustomPlaybackSpeedPatch( abstract class BaseCustomPlaybackSpeedPatch(
private val descriptor: String, private val descriptor: String,
@ -39,7 +39,9 @@ abstract class BaseCustomPlaybackSpeedPatch(
""" """
) )
val sizeIndex = getTargetIndexWithMethodReferenceNameOrThrow("size") + 1 val sizeIndex = indexOfFirstInstructionOrThrow {
getReference<MethodReference>()?.name == "size"
} + 1
val sizeRegister = getInstruction<OneRegisterInstruction>(sizeIndex).registerA val sizeRegister = getInstruction<OneRegisterInstruction>(sizeIndex).registerA
addInstructions( addInstructions(
@ -49,7 +51,9 @@ abstract class BaseCustomPlaybackSpeedPatch(
""" """
) )
val arrayIndex = getTargetIndexWithFieldReferenceTypeOrThrow("[F") val arrayIndex = indexOfFirstInstructionOrThrow {
getReference<FieldReference>()?.type == "[F"
}
val arrayRegister = getInstruction<OneRegisterInstruction>(arrayIndex).registerA val arrayRegister = getInstruction<OneRegisterInstruction>(arrayIndex).registerA
addInstructions( addInstructions(
@ -73,7 +77,7 @@ abstract class BaseCustomPlaybackSpeedPatch(
val limiterMinConstIndex = val limiterMinConstIndex =
indexOfFirstInstructionOrThrow { (this as? NarrowLiteralInstruction)?.narrowLiteral == 0.25f.toRawBits() } indexOfFirstInstructionOrThrow { (this as? NarrowLiteralInstruction)?.narrowLiteral == 0.25f.toRawBits() }
val limiterMaxConstIndex = val limiterMaxConstIndex =
getTargetIndexOrThrow(limiterMinConstIndex + 1, Opcode.CONST_HIGH16) indexOfFirstInstructionOrThrow(limiterMinConstIndex + 1, Opcode.CONST_HIGH16)
val limiterMinConstDestination = val limiterMinConstDestination =
getInstruction<OneRegisterInstruction>(limiterMinConstIndex).registerA getInstruction<OneRegisterInstruction>(limiterMinConstIndex).registerA

View File

@ -7,10 +7,12 @@ import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patches.shared.dialog.fingerprints.CreateDialogFingerprint import app.revanced.patches.shared.dialog.fingerprints.CreateDialogFingerprint
import app.revanced.util.getTargetIndexWithMethodReferenceNameOrThrow import app.revanced.util.getReference
import app.revanced.util.getWalkerMethod import app.revanced.util.getWalkerMethod
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
abstract class BaseViewerDiscretionDialogPatch( abstract class BaseViewerDiscretionDialogPatch(
private val classDescriptor: String, private val classDescriptor: String,
@ -22,7 +24,9 @@ abstract class BaseViewerDiscretionDialogPatch(
} }
) { ) {
private fun MutableMethod.invoke(isAgeVerified: Boolean) { private fun MutableMethod.invoke(isAgeVerified: Boolean) {
val showDialogIndex = getTargetIndexWithMethodReferenceNameOrThrow("show") val showDialogIndex = indexOfFirstInstructionOrThrow {
getReference<MethodReference>()?.name == "show"
}
val dialogRegister = getInstruction<FiveRegisterInstruction>(showDialogIndex).registerC val dialogRegister = getInstruction<FiveRegisterInstruction>(showDialogIndex).registerC
val methodName = val methodName =

View File

@ -6,9 +6,11 @@ import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patches.shared.drawable.fingerprints.DrawableFingerprint import app.revanced.patches.shared.drawable.fingerprints.DrawableFingerprint
import app.revanced.util.getTargetIndexWithMethodReferenceNameReversedOrThrow import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
object DrawableColorPatch : BytecodePatch( object DrawableColorPatch : BytecodePatch(
setOf(DrawableFingerprint) setOf(DrawableFingerprint)
@ -17,26 +19,26 @@ object DrawableColorPatch : BytecodePatch(
DrawableFingerprint.resultOrThrow().mutableMethod.apply { DrawableFingerprint.resultOrThrow().mutableMethod.apply {
insertMethod = this insertMethod = this
insertIndex = getTargetIndexWithMethodReferenceNameReversedOrThrow("setColor") insertIndex = indexOfFirstInstructionReversedOrThrow {
getReference<MethodReference>()?.name == "setColor"
}
insertRegister = getInstruction<FiveRegisterInstruction>(insertIndex).registerD insertRegister = getInstruction<FiveRegisterInstruction>(insertIndex).registerD
} }
} }
private var offset = 0 private lateinit var insertMethod: MutableMethod
private var insertIndex: Int = 0 private var insertIndex: Int = 0
private var insertRegister: Int = 0 private var insertRegister: Int = 0
private lateinit var insertMethod: MutableMethod private var offset = 0
fun injectCall( fun injectCall(
methodDescriptor: String methodDescriptor: String
) { ) {
insertMethod.addInstructions( insertMethod.addInstructions(
insertIndex + offset, """ insertIndex + offset, """
invoke-static {v$insertRegister}, $methodDescriptor invoke-static {v$insertRegister}, $methodDescriptor
move-result v$insertRegister move-result v$insertRegister
""" """
) )
offset += 2 offset += 2
} }

View File

@ -0,0 +1,28 @@
package app.revanced.patches.shared.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
internal object StartVideoInformerFingerprint : MethodFingerprint(
returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
opcodes = listOf(
Opcode.INVOKE_INTERFACE,
Opcode.RETURN_VOID
),
strings = listOf("pc"),
customFingerprint = custom@{ methodDef, _ ->
if (methodDef.implementation == null)
return@custom false
methodDef.implementation!!.instructions
.withIndex()
.filter { (_, instruction) ->
instruction.opcode == Opcode.CONST_STRING
}
.map { (index, _) -> index }
.size == 1
}
)

View File

@ -1,4 +1,4 @@
package app.revanced.patches.youtube.video.information.fingerprints package app.revanced.patches.shared.fingerprints
import app.revanced.patcher.extensions.or import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.fingerprint.MethodFingerprint

View File

@ -18,14 +18,12 @@ import app.revanced.patches.shared.gms.fingerprints.CastContextFetchFingerprint
import app.revanced.patches.shared.gms.fingerprints.CastDynamiteModuleFingerprint import app.revanced.patches.shared.gms.fingerprints.CastDynamiteModuleFingerprint
import app.revanced.patches.shared.gms.fingerprints.CastDynamiteModuleV2Fingerprint import app.revanced.patches.shared.gms.fingerprints.CastDynamiteModuleV2Fingerprint
import app.revanced.patches.shared.gms.fingerprints.CertificateFingerprint import app.revanced.patches.shared.gms.fingerprints.CertificateFingerprint
import app.revanced.patches.shared.gms.fingerprints.CertificateFingerprint.GET_PACKAGE_NAME_METHOD_REFERENCE
import app.revanced.patches.shared.gms.fingerprints.GmsCoreSupportFingerprint import app.revanced.patches.shared.gms.fingerprints.GmsCoreSupportFingerprint
import app.revanced.patches.shared.gms.fingerprints.GooglePlayUtilityFingerprint import app.revanced.patches.shared.gms.fingerprints.GooglePlayUtilityFingerprint
import app.revanced.patches.shared.gms.fingerprints.PrimeMethodFingerprint import app.revanced.patches.shared.gms.fingerprints.PrimeMethodFingerprint
import app.revanced.patches.shared.gms.fingerprints.ServiceCheckFingerprint import app.revanced.patches.shared.gms.fingerprints.ServiceCheckFingerprint
import app.revanced.patches.shared.integrations.Constants.PATCHES_PATH import app.revanced.patches.shared.integrations.Constants.PATCHES_PATH
import app.revanced.util.getReference import app.revanced.util.getReference
import app.revanced.util.getTargetIndexWithReference
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
import app.revanced.util.returnEarly import app.revanced.util.returnEarly
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
@ -178,7 +176,7 @@ abstract class BaseGmsCoreSupportPatch(
CertificateFingerprint.result?.mutableClass?.methods?.forEach { mutableMethod -> CertificateFingerprint.result?.mutableClass?.methods?.forEach { mutableMethod ->
mutableMethod.apply { mutableMethod.apply {
val getPackageNameIndex = val getPackageNameIndex =
getTargetIndexWithReference(GET_PACKAGE_NAME_METHOD_REFERENCE) CertificateFingerprint.indexOfGetPackageNameInstruction(this)
if (getPackageNameIndex > -1) { if (getPackageNameIndex > -1) {
val targetRegister = val targetRegister =

View File

@ -1,20 +1,28 @@
package app.revanced.patches.shared.gms.fingerprints package app.revanced.patches.shared.gms.fingerprints
import app.revanced.patcher.extensions.or import app.revanced.patcher.extensions.or
import app.revanced.patches.shared.gms.fingerprints.CertificateFingerprint.GET_PACKAGE_NAME_METHOD_REFERENCE import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.util.fingerprint.ReferenceFingerprint import app.revanced.patches.shared.gms.fingerprints.CertificateFingerprint.indexOfGetPackageNameInstruction
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
/** /**
* Method which the package name is used to check the app signature. * Method which the package name is used to check the app signature.
*/ */
internal object CertificateFingerprint : ReferenceFingerprint( internal object CertificateFingerprint : MethodFingerprint(
returnType = "Ljava/lang/String;", returnType = "Ljava/lang/String;",
accessFlags = AccessFlags.PROTECTED or AccessFlags.FINAL, accessFlags = AccessFlags.PROTECTED or AccessFlags.FINAL,
parameters = emptyList(), parameters = emptyList(),
strings = listOf("X.509", "user", "S"), strings = listOf("X.509", "user", "S"),
reference = { GET_PACKAGE_NAME_METHOD_REFERENCE } customFingerprint = { methodDef, _ ->
indexOfGetPackageNameInstruction(methodDef) >= 0
}
) { ) {
const val GET_PACKAGE_NAME_METHOD_REFERENCE = fun indexOfGetPackageNameInstruction(methodDef: Method) =
"Landroid/content/Context;->getPackageName()Ljava/lang/String;" methodDef.indexOfFirstInstruction {
getReference<MethodReference>()?.toString() == "Landroid/content/Context;->getPackageName()Ljava/lang/String;"
}
} }

View File

@ -102,8 +102,8 @@ abstract class BaseCronetImageUrlHookPatch(
// Add a helper get method that returns the URL field. // Add a helper get method that returns the URL field.
RequestFingerprint.resultOrThrow().apply { RequestFingerprint.resultOrThrow().apply {
// The url is the only string field that is set inside the constructor. // The url is the only string field that is set inside the constructor.
val urlFieldInstruction = mutableMethod.getInstructions().single { val urlFieldInstruction = mutableMethod.getInstructions().first {
if (it.opcode != Opcode.IPUT_OBJECT) return@single false if (it.opcode != Opcode.IPUT_OBJECT) return@first false
val reference = (it as ReferenceInstruction).reference as FieldReference val reference = (it as ReferenceInstruction).reference as FieldReference
reference.type == "Ljava/lang/String;" reference.type == "Ljava/lang/String;"

View File

@ -4,10 +4,11 @@ import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchException
import app.revanced.patches.shared.integrations.BaseIntegrationsPatch.IntegrationsFingerprint.IRegisterResolver import app.revanced.patches.shared.integrations.BaseIntegrationsPatch.IntegrationsFingerprint.IRegisterResolver
import app.revanced.patches.shared.integrations.Constants.INTEGRATIONS_UTILS_CLASS_DESCRIPTOR import app.revanced.patches.shared.integrations.Constants.INTEGRATIONS_UTILS_CLASS_DESCRIPTOR
import app.revanced.util.resultOrThrow import app.revanced.util.exception
import app.revanced.util.findMethodOrThrow
import app.revanced.util.isDeprecated
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.ClassDef import com.android.tools.smali.dexlib2.iface.ClassDef
import com.android.tools.smali.dexlib2.iface.Method import com.android.tools.smali.dexlib2.iface.Method
@ -17,11 +18,7 @@ abstract class BaseIntegrationsPatch(
) : BytecodePatch(hooks) { ) : BytecodePatch(hooks) {
override fun execute(context: BytecodeContext) { override fun execute(context: BytecodeContext) {
if (context.findClass(INTEGRATIONS_UTILS_CLASS_DESCRIPTOR) == null) { context.findMethodOrThrow(INTEGRATIONS_UTILS_CLASS_DESCRIPTOR)
throw PatchException(
"Integrations have not been merged yet. This patch can not succeed without merging the integrations.",
)
}
hooks.forEach { hook -> hooks.forEach { hook ->
hook.invoke(INTEGRATIONS_UTILS_CLASS_DESCRIPTOR) hook.invoke(INTEGRATIONS_UTILS_CLASS_DESCRIPTOR)
@ -53,16 +50,21 @@ abstract class BaseIntegrationsPatch(
) { ) {
fun invoke(integrationsDescriptor: String) { fun invoke(integrationsDescriptor: String) {
resultOrThrow().mutableMethod.let { method -> val method = result?.mutableMethod
val insertIndex = insertIndexResolver(method) ?: if (!isDeprecated()) {
val contextRegister = contextRegisterResolver(method) throw exception
} else {
return
}
method.addInstruction( val insertIndex = insertIndexResolver(method)
insertIndex, val contextRegister = contextRegisterResolver(method)
"invoke-static/range { $contextRegister .. $contextRegister }, " +
"$integrationsDescriptor->setContext(Landroid/content/Context;)V", method.addInstruction(
) insertIndex,
} "invoke-static/range { $contextRegister .. $contextRegister }, " +
"$integrationsDescriptor->setContext(Landroid/content/Context;)V",
)
} }
interface IHookInsertIndexResolver : (Method) -> Int { interface IHookInsertIndexResolver : (Method) -> Int {

View File

@ -5,84 +5,112 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.removeInstructions import app.revanced.patcher.extensions.or
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
import app.revanced.patcher.util.smali.ExternalLabel import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.shared.integrations.Constants.COMPONENTS_PATH import app.revanced.patches.shared.integrations.Constants.COMPONENTS_PATH
import app.revanced.patches.shared.litho.fingerprints.ByteBufferFingerprint
import app.revanced.patches.shared.litho.fingerprints.EmptyComponentsFingerprint import app.revanced.patches.shared.litho.fingerprints.EmptyComponentsFingerprint
import app.revanced.patches.shared.litho.fingerprints.LithoFilterPatchConstructorFingerprint
import app.revanced.patches.shared.litho.fingerprints.PathBuilderFingerprint import app.revanced.patches.shared.litho.fingerprints.PathBuilderFingerprint
import app.revanced.patches.shared.litho.fingerprints.SetByteBufferFingerprint import app.revanced.util.findMethodsOrThrow
import app.revanced.util.getStringInstructionIndex import app.revanced.util.getReference
import app.revanced.util.getTargetIndexOrThrow import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.getTargetIndexReversedOrThrow import app.revanced.util.indexOfFirstInstructionReversedOrThrow
import app.revanced.util.getTargetIndexWithFieldReferenceTypeOrThrow import app.revanced.util.indexOfFirstStringInstructionOrThrow
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction35c import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
import com.android.tools.smali.dexlib2.util.MethodUtil
import java.io.Closeable import java.io.Closeable
@Suppress("SpellCheckingInspection", "unused") @Suppress("SpellCheckingInspection", "unused")
object LithoFilterPatch : BytecodePatch( object LithoFilterPatch : BytecodePatch(
setOf( setOf(
ByteBufferFingerprint,
EmptyComponentsFingerprint, EmptyComponentsFingerprint,
LithoFilterPatchConstructorFingerprint,
SetByteBufferFingerprint
) )
), Closeable { ), Closeable {
private const val INTEGRATIONS_LITHO_FILER_CLASS_DESCRIPTOR = private const val INTEGRATIONS_LITHO_FILER_CLASS_DESCRIPTOR =
"$COMPONENTS_PATH/LithoFilterPatch;" "$COMPONENTS_PATH/LithoFilterPatch;"
private const val INTEGRATIONS_FILER_CLASS_DESCRIPTOR = private const val INTEGRATIONS_FILER_ARRAY_DESCRIPTOR =
"$COMPONENTS_PATH/Filter;" "[$COMPONENTS_PATH/Filter;"
private lateinit var filterArrayMethod: MutableMethod
private var filterCount = 0
internal lateinit var addFilter: (String) -> Unit internal lateinit var addFilter: (String) -> Unit
private set private set
private lateinit var emptyComponentMethod: MutableMethod
private lateinit var emptyComponentLabel: String
private lateinit var emptyComponentMethodName: String
private lateinit var pathBuilderMethodCall: String
private var filterCount = 0
override fun execute(context: BytecodeContext) { override fun execute(context: BytecodeContext) {
SetByteBufferFingerprint.resultOrThrow().let { // region Pass the buffer into Integrations.
it.mutableMethod.apply {
val insertIndex = getTargetIndexOrThrow(Opcode.IF_EQZ) + 1
addInstruction( ByteBufferFingerprint.resultOrThrow().mutableMethod.addInstruction(
insertIndex, 0,
"invoke-static { p2 }, $INTEGRATIONS_LITHO_FILER_CLASS_DESCRIPTOR->setProtoBuffer(Ljava/nio/ByteBuffer;)V" "invoke-static { p2 }, $INTEGRATIONS_LITHO_FILER_CLASS_DESCRIPTOR->setProtoBuffer(Ljava/nio/ByteBuffer;)V"
) )
}
}
EmptyComponentsFingerprint.resultOrThrow().let { // endregion
it.mutableMethod.apply {
// resolves fingerprint. var (emptyComponentMethod, emptyComponentLabel) =
EmptyComponentsFingerprint.resultOrThrow().let {
PathBuilderFingerprint.resolve(context, it.classDef) PathBuilderFingerprint.resolve(context, it.classDef)
emptyComponentMethod = this with(it.mutableMethod) {
emptyComponentMethodName = name val emptyComponentMethodIndex = it.scanResult.patternScanResult!!.startIndex + 1
val emptyComponentMethodReference =
getInstruction<ReferenceInstruction>(emptyComponentMethodIndex).reference
val emptyComponentFieldReference =
getInstruction<ReferenceInstruction>(emptyComponentMethodIndex + 2).reference
val emptyComponentMethodIndex = it.scanResult.patternScanResult!!.startIndex + 1 val label = """
val emptyComponentMethodReference = move-object/from16 v0, p1
getInstruction<ReferenceInstruction>(emptyComponentMethodIndex).reference invoke-static {v0}, $emptyComponentMethodReference
val emptyComponentFieldReference = move-result-object v0
getInstruction<ReferenceInstruction>(emptyComponentMethodIndex + 2).reference iget-object v0, v0, $emptyComponentFieldReference
return-object v0
"""
Pair(this, label)
}
}
fun checkMethodSignatureMatch(pathBuilder: MutableMethod) = emptyComponentMethod.apply {
if (!MethodUtil.methodSignaturesMatch(pathBuilder, this)) {
implementation!!.instructions
.withIndex()
.filter { (_, instruction) ->
val reference = (instruction as? ReferenceInstruction)?.reference
reference is MethodReference &&
MethodUtil.methodSignaturesMatch(pathBuilder, reference)
}
.map { (index, _) -> index }
.reversed()
.forEach {
val insertRegister =
getInstruction<OneRegisterInstruction>(it + 1).registerA
val insertIndex = it + 2
addInstructionsWithLabels(
insertIndex, """
if-nez v$insertRegister, :ignore
""" + emptyComponentLabel,
ExternalLabel("ignore", getInstruction(insertIndex))
)
}
emptyComponentLabel = """ emptyComponentLabel = """
move-object/from16 v0, p1 const/4 v0, 0x0
invoke-static {v0}, $emptyComponentMethodReference
move-result-object v0
iget-object v0, v0, $emptyComponentFieldReference
return-object v0 return-object v0
""" """
} }
@ -90,65 +118,27 @@ object LithoFilterPatch : BytecodePatch(
PathBuilderFingerprint.resultOrThrow().let { PathBuilderFingerprint.resultOrThrow().let {
it.mutableMethod.apply { it.mutableMethod.apply {
// If the EmptyComponents Method and the PathBuilder Method are different, checkMethodSignatureMatch(this)
// new inject way is required.
// TODO: Refactor LithoFilter patch when support for YouTube 18.29.38 ~ 19.17.41 and YT Music 6.29.58 ~ 6.51.53 is dropped.
if (emptyComponentMethodName != name) {
// In this case, the access modifier of the method that handles PathBuilder is 'AccessFlags.PRIVATE or AccessFlags.FINAL.
// Methods that handle PathBuilder are invoked by methods that handle EmptyComponents.
// 'pathBuilderMethodCall' is a reference that invokes the PathBuilder Method.
pathBuilderMethodCall = "$definingClass->$name("
for (i in 0 until parameters.size) {
pathBuilderMethodCall += parameterTypes[i]
}
pathBuilderMethodCall += ")$returnType"
emptyComponentMethod.apply { val stringBuilderIndex = indexOfFirstInstructionOrThrow {
// If the return value of the PathBuilder Method is null, opcode == Opcode.IPUT_OBJECT &&
// it means that pathBuilder has been filtered by the LithoFilterPatch. getReference<FieldReference>()?.type == "Ljava/lang/StringBuilder;"
// (Refer comments below.)
// Returns emptyComponents.
for (index in implementation!!.instructions.size - 1 downTo 0) {
val instruction = getInstruction(index)
if ((instruction as? ReferenceInstruction)?.reference.toString() != pathBuilderMethodCall)
continue
val insertRegister =
getInstruction<OneRegisterInstruction>(index + 1).registerA
val insertIndex = index + 2
addInstructionsWithLabels(
insertIndex, """
if-nez v$insertRegister, :ignore
""" + emptyComponentLabel,
ExternalLabel("ignore", getInstruction(insertIndex))
)
}
}
// If the EmptyComponents Method and the PathBuilder Method are different,
// PathBuilder Method's returnType cannot cast emptyComponents.
// So just returns null value.
emptyComponentLabel = """
const/4 v0, 0x0
return-object v0
"""
} }
val stringBuilderIndex =
getTargetIndexWithFieldReferenceTypeOrThrow("Ljava/lang/StringBuilder;")
val stringBuilderRegister = val stringBuilderRegister =
getInstruction<TwoRegisterInstruction>(stringBuilderIndex).registerA getInstruction<TwoRegisterInstruction>(stringBuilderIndex).registerA
val emptyStringIndex = getStringInstructionIndex("") val emptyStringIndex = indexOfFirstStringInstructionOrThrow("")
val identifierRegister = getInstruction<TwoRegisterInstruction>(
val identifierIndex = indexOfFirstInstructionReversedOrThrow(emptyStringIndex) {
getTargetIndexReversedOrThrow(emptyStringIndex, Opcode.IPUT_OBJECT) opcode == Opcode.IPUT_OBJECT
val identifierRegister = && getReference<FieldReference>()?.type == "Ljava/lang/String;"
getInstruction<TwoRegisterInstruction>(identifierIndex).registerA }
).registerA
val objectIndex = getTargetIndexOrThrow(emptyStringIndex, Opcode.INVOKE_VIRTUAL) val objectRegister = getInstruction<FiveRegisterInstruction>(
val objectRegister = getInstruction<BuilderInstruction35c>(objectIndex).registerC indexOfFirstInstructionOrThrow(emptyStringIndex) {
opcode == Opcode.INVOKE_VIRTUAL
}
).registerC
val insertIndex = stringBuilderIndex + 1 val insertIndex = stringBuilderIndex + 1
@ -163,30 +153,67 @@ object LithoFilterPatch : BytecodePatch(
} }
} }
LithoFilterPatchConstructorFingerprint.resultOrThrow().let { // Create a new method to get the filter array to avoid register conflicts.
it.mutableMethod.apply { // This fixes an issue with Integrations compiled with Android Gradle Plugin 8.3.0+.
removeInstructions(0, 6) // https://github.com/ReVanced/revanced-patches/issues/2818
val lithoFilterMethods =
context.findMethodsOrThrow(INTEGRATIONS_LITHO_FILER_CLASS_DESCRIPTOR)
addFilter = { classDescriptor -> lithoFilterMethods
addInstructions( .first { it.name == "<clinit>" }
0, """ .apply {
new-instance v0, $classDescriptor val setArrayIndex = indexOfFirstInstructionOrThrow {
invoke-direct {v0}, $classDescriptor-><init>()V opcode == Opcode.SPUT_OBJECT &&
const/16 v3, ${filterCount++} getReference<FieldReference>()?.type == INTEGRATIONS_FILER_ARRAY_DESCRIPTOR
aput-object v0, v2, v3 }
""" val setArrayRegister =
getInstruction<OneRegisterInstruction>(setArrayIndex).registerA
val addedMethodName = "getFilterArray"
addInstructions(
setArrayIndex, """
invoke-static {}, $INTEGRATIONS_LITHO_FILER_CLASS_DESCRIPTOR->$addedMethodName()$INTEGRATIONS_FILER_ARRAY_DESCRIPTOR
move-result-object v$setArrayRegister
"""
)
filterArrayMethod = ImmutableMethod(
definingClass,
addedMethodName,
emptyList(),
INTEGRATIONS_FILER_ARRAY_DESCRIPTOR,
AccessFlags.PRIVATE or AccessFlags.STATIC,
null,
null,
MutableMethodImplementation(3),
).toMutable().apply {
addInstruction(
0,
"return-object v2"
) )
} }
lithoFilterMethods.add(filterArrayMethod)
} }
addFilter = { classDescriptor ->
filterArrayMethod.addInstructions(
0,
"""
new-instance v0, $classDescriptor
invoke-direct {v0}, $classDescriptor-><init>()V
const/16 v1, ${filterCount++}
aput-object v0, v2, v1
"""
)
} }
} }
override fun close() = LithoFilterPatchConstructorFingerprint.result!! override fun close() = filterArrayMethod.addInstructions(
.mutableMethod.addInstructions( 0,
0, """ """
const/16 v1, $filterCount const/16 v0, $filterCount
new-array v2, v1, [$INTEGRATIONS_FILER_CLASS_DESCRIPTOR new-array v2, v0, $INTEGRATIONS_FILER_ARRAY_DESCRIPTOR
const/4 v1, 0x1 """
""" )
)
} }

View File

@ -5,7 +5,7 @@ import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
internal object SetByteBufferFingerprint : MethodFingerprint( internal object ByteBufferFingerprint : MethodFingerprint(
returnType = "V", returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("I", "Ljava/nio/ByteBuffer;"), parameters = listOf("I", "Ljava/nio/ByteBuffer;"),

View File

@ -1,14 +0,0 @@
package app.revanced.patches.shared.litho.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patches.shared.integrations.Constants.COMPONENTS_PATH
import com.android.tools.smali.dexlib2.AccessFlags
internal object LithoFilterPatchConstructorFingerprint : MethodFingerprint(
returnType = "V",
accessFlags = AccessFlags.STATIC or AccessFlags.CONSTRUCTOR,
customFingerprint = { methodDef, _ ->
methodDef.definingClass == "$COMPONENTS_PATH/LithoFilterPatch;"
}
)

View File

@ -7,7 +7,7 @@ import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.util.proxy.mutableTypes.MutableClass import app.revanced.patcher.util.proxy.mutableTypes.MutableClass
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.util.getTargetIndexOrThrow import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
import kotlin.properties.Delegates import kotlin.properties.Delegates
@ -38,7 +38,8 @@ abstract class BaseMainActivityResolvePatch(
// set onBackPressed method // set onBackPressed method
onBackPressedMethod = getMethod("onBackPressed") onBackPressedMethod = getMethod("onBackPressed")
onBackPressedMethodIndex = onBackPressedMethod.getTargetIndexOrThrow(Opcode.RETURN_VOID) onBackPressedMethodIndex =
onBackPressedMethod.indexOfFirstInstructionOrThrow(Opcode.RETURN_VOID)
// set onConfigurationChanged method // set onConfigurationChanged method
onConfigurationChangedMethod = getMethod("onConfigurationChanged") onConfigurationChangedMethod = getMethod("onConfigurationChanged")

View File

@ -7,11 +7,13 @@ import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.util.smali.ExternalLabel import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.shared.opus.fingerprints.CodecReferenceFingerprint import app.revanced.patches.shared.opus.fingerprints.CodecReferenceFingerprint
import app.revanced.patches.shared.opus.fingerprints.CodecSelectorFingerprint import app.revanced.patches.shared.opus.fingerprints.CodecSelectorFingerprint
import app.revanced.util.getTargetIndexWithReferenceOrThrow import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.reference.Reference import com.android.tools.smali.dexlib2.iface.reference.MethodReference
/** /**
* This patch is generally not required for the latest versions of YouTube and YouTube Music. * This patch is generally not required for the latest versions of YouTube and YouTube Music.
@ -25,15 +27,14 @@ abstract class BaseOpusCodecsPatch(
CodecSelectorFingerprint CodecSelectorFingerprint
) )
) { ) {
private lateinit var opusCodecReference: Reference
override fun execute(context: BytecodeContext) { override fun execute(context: BytecodeContext) {
CodecReferenceFingerprint.resultOrThrow().let { val opusCodecReference = with(CodecReferenceFingerprint.resultOrThrow().mutableMethod) {
it.mutableMethod.apply { val codecIndex = indexOfFirstInstructionOrThrow {
val targetIndex = getTargetIndexWithReferenceOrThrow("Ljava/util/Set;") opcode == Opcode.INVOKE_STATIC &&
opusCodecReference = getInstruction<ReferenceInstruction>(targetIndex).reference getReference<MethodReference>()?.returnType == "Ljava/util/Set;"
} }
getInstruction<ReferenceInstruction>(codecIndex).reference
} }
CodecSelectorFingerprint.resultOrThrow().let { CodecSelectorFingerprint.resultOrThrow().let {

View File

@ -8,9 +8,11 @@ import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.shared.integrations.Constants.PATCHES_PATH import app.revanced.patches.shared.integrations.Constants.PATCHES_PATH
import app.revanced.patches.shared.settingmenu.fingerprints.SettingsMenuFingerprint import app.revanced.patches.shared.settingmenu.fingerprints.SettingsMenuFingerprint
import app.revanced.patches.shared.viewgroup.ViewGroupMarginLayoutParamsHookPatch import app.revanced.patches.shared.viewgroup.ViewGroupMarginLayoutParamsHookPatch
import app.revanced.util.getTargetIndexWithFieldReferenceTypeOrThrow import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
@Patch( @Patch(
description = "Hide the settings menu for YouTube or YouTube Music.", description = "Hide the settings menu for YouTube or YouTube Music.",
@ -25,8 +27,9 @@ object SettingsMenuPatch : BytecodePatch(
override fun execute(context: BytecodeContext) { override fun execute(context: BytecodeContext) {
SettingsMenuFingerprint.resultOrThrow().mutableMethod.apply { SettingsMenuFingerprint.resultOrThrow().mutableMethod.apply {
val insertIndex = val insertIndex = indexOfFirstInstructionOrThrow {
getTargetIndexWithFieldReferenceTypeOrThrow("Landroid/support/v7/widget/RecyclerView;") getReference<FieldReference>()?.type == "Landroid/support/v7/widget/RecyclerView;"
}
val insertRegister = getInstruction<TwoRegisterInstruction>(insertIndex).registerA val insertRegister = getInstruction<TwoRegisterInstruction>(insertIndex).registerA
addInstruction( addInstruction(

View File

@ -6,7 +6,7 @@ import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patches.shared.fingerprints.CreatePlayerRequestBodyWithModelFingerprint import app.revanced.patches.shared.fingerprints.CreatePlayerRequestBodyWithModelFingerprint
import app.revanced.patches.shared.fingerprints.CreatePlayerRequestBodyWithModelFingerprint.indexOfReleaseInstruction import app.revanced.patches.shared.fingerprints.CreatePlayerRequestBodyWithModelFingerprint.indexOfReleaseInstruction
import app.revanced.util.getTargetIndexReversedOrThrow import app.revanced.util.indexOfFirstInstructionReversedOrThrow
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
@ -20,7 +20,8 @@ abstract class BaseSpoofAppVersionPatch(
CreatePlayerRequestBodyWithModelFingerprint.resultOrThrow().mutableMethod.apply { CreatePlayerRequestBodyWithModelFingerprint.resultOrThrow().mutableMethod.apply {
val versionIndex = indexOfReleaseInstruction(this) + 1 val versionIndex = indexOfReleaseInstruction(this) + 1
val insertIndex = getTargetIndexReversedOrThrow(versionIndex, Opcode.IPUT_OBJECT) val insertIndex =
indexOfFirstInstructionReversedOrThrow(versionIndex, Opcode.IPUT_OBJECT)
val insertRegister = getInstruction<TwoRegisterInstruction>(insertIndex).registerA val insertRegister = getInstruction<TwoRegisterInstruction>(insertIndex).registerA
addInstructions( addInstructions(

View File

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

View File

@ -43,7 +43,7 @@ object AdsBytecodePatch : BytecodePatch(
// litho view, used in 'ShowDialogCommandOuterClass' in innertube // litho view, used in 'ShowDialogCommandOuterClass' in innertube
ShowDialogCommandFingerprint ShowDialogCommandFingerprint
.resultOrThrow() .resultOrThrow()
.hookLithoFullscreenAds(context) .hookLithoFullscreenAds()
// endregion // endregion

View File

@ -50,12 +50,8 @@ object AdsPatch : BaseResourcePatch(
private const val ADS_FILTER_CLASS_DESCRIPTOR = private const val ADS_FILTER_CLASS_DESCRIPTOR =
"$COMPONENTS_PATH/AdsFilter;" "$COMPONENTS_PATH/AdsFilter;"
private const val FULLSCREEN_ADS_FILTER_CLASS_DESCRIPTOR =
"${app.revanced.patches.shared.integrations.Constants.COMPONENTS_PATH}/FullscreenAdsFilter;"
override fun execute(context: ResourceContext) { override fun execute(context: ResourceContext) {
LithoFilterPatch.addFilter(ADS_FILTER_CLASS_DESCRIPTOR) LithoFilterPatch.addFilter(ADS_FILTER_CLASS_DESCRIPTOR)
LithoFilterPatch.addFilter(FULLSCREEN_ADS_FILTER_CLASS_DESCRIPTOR)
context.forEach { context.forEach {

View File

@ -2,7 +2,7 @@ package app.revanced.patches.youtube.ads.general.fingerprints
import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.SlidingDialogAnimation import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.SlidingDialogAnimation
import app.revanced.util.containsWideLiteralInstructionIndex import app.revanced.util.containsWideLiteralInstructionValue
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
internal object ShowDialogCommandFingerprint : MethodFingerprint( internal object ShowDialogCommandFingerprint : MethodFingerprint(
@ -16,7 +16,7 @@ internal object ShowDialogCommandFingerprint : MethodFingerprint(
// 18.43 and earlier has a different first parameter. // 18.43 and earlier has a different first parameter.
// Since this fingerprint is somewhat weak, work around by checking for both method parameter signatures. // Since this fingerprint is somewhat weak, work around by checking for both method parameter signatures.
customFingerprint = custom@{ methodDef, _ -> customFingerprint = custom@{ methodDef, _ ->
if (!methodDef.containsWideLiteralInstructionIndex(SlidingDialogAnimation)) { if (!methodDef.containsWideLiteralInstructionValue(SlidingDialogAnimation)) {
return@custom false return@custom false
} }
// 18.43 and earlier parameters are: "L", "L" // 18.43 and earlier parameters are: "L", "L"

View File

@ -7,6 +7,7 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWith
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patcher.util.smali.ExternalLabel import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.shared.litho.LithoFilterPatch import app.revanced.patches.shared.litho.LithoFilterPatch
import app.revanced.patches.youtube.feed.components.fingerprints.BreakingNewsFingerprint import app.revanced.patches.youtube.feed.components.fingerprints.BreakingNewsFingerprint
@ -19,33 +20,42 @@ import app.revanced.patches.youtube.feed.components.fingerprints.ChannelTabBuild
import app.revanced.patches.youtube.feed.components.fingerprints.ChannelTabRendererFingerprint import app.revanced.patches.youtube.feed.components.fingerprints.ChannelTabRendererFingerprint
import app.revanced.patches.youtube.feed.components.fingerprints.ElementParserFingerprint import app.revanced.patches.youtube.feed.components.fingerprints.ElementParserFingerprint
import app.revanced.patches.youtube.feed.components.fingerprints.ElementParserParentFingerprint import app.revanced.patches.youtube.feed.components.fingerprints.ElementParserParentFingerprint
import app.revanced.patches.youtube.feed.components.fingerprints.EngagementPanelUpdateFingerprint
import app.revanced.patches.youtube.feed.components.fingerprints.FilterBarHeightFingerprint import app.revanced.patches.youtube.feed.components.fingerprints.FilterBarHeightFingerprint
import app.revanced.patches.youtube.feed.components.fingerprints.LatestVideosButtonFingerprint import app.revanced.patches.youtube.feed.components.fingerprints.LatestVideosButtonFingerprint
import app.revanced.patches.youtube.feed.components.fingerprints.LinearLayoutManagerItemCountsFingerprint
import app.revanced.patches.youtube.feed.components.fingerprints.RelatedChipCloudFingerprint import app.revanced.patches.youtube.feed.components.fingerprints.RelatedChipCloudFingerprint
import app.revanced.patches.youtube.feed.components.fingerprints.SearchResultsChipBarFingerprint import app.revanced.patches.youtube.feed.components.fingerprints.SearchResultsChipBarFingerprint
import app.revanced.patches.youtube.feed.components.fingerprints.ShowMoreButtonFingerprint import app.revanced.patches.youtube.feed.components.fingerprints.ShowMoreButtonFingerprint
import app.revanced.patches.youtube.utils.bottomsheet.BottomSheetHookPatch
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
import app.revanced.patches.youtube.utils.fingerprints.EngagementPanelBuilderFingerprint
import app.revanced.patches.youtube.utils.fingerprints.ScrollTopParentFingerprint import app.revanced.patches.youtube.utils.fingerprints.ScrollTopParentFingerprint
import app.revanced.patches.youtube.utils.integrations.Constants.COMPONENTS_PATH import app.revanced.patches.youtube.utils.integrations.Constants.COMPONENTS_PATH
import app.revanced.patches.youtube.utils.integrations.Constants.FEED_CLASS_DESCRIPTOR import app.revanced.patches.youtube.utils.integrations.Constants.FEED_CLASS_DESCRIPTOR
import app.revanced.patches.youtube.utils.integrations.Constants.FEED_PATH
import app.revanced.patches.youtube.utils.navigation.NavigationBarHookPatch import app.revanced.patches.youtube.utils.navigation.NavigationBarHookPatch
import app.revanced.patches.youtube.utils.playertype.PlayerTypeHookPatch import app.revanced.patches.youtube.utils.playertype.PlayerTypeHookPatch
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.CaptionToggleContainer import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.CaptionToggleContainer
import app.revanced.patches.youtube.utils.settings.SettingsPatch import app.revanced.patches.youtube.utils.settings.SettingsPatch
import app.revanced.util.getTargetIndexOrThrow import app.revanced.util.alsoResolve
import app.revanced.util.getTargetIndexReversedOrThrow import app.revanced.util.getReference
import app.revanced.util.getTargetIndexWithMethodReferenceName import app.revanced.util.getWalkerMethod
import app.revanced.util.getWideLiteralInstructionIndex import app.revanced.util.indexOfFirstInstruction
import app.revanced.util.indexOfFirstInstructionOrThrow import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow
import app.revanced.util.patch.BaseBytecodePatch import app.revanced.util.patch.BaseBytecodePatch
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference import com.android.tools.smali.dexlib2.iface.reference.MethodReference
import com.android.tools.smali.dexlib2.util.MethodUtil
@Suppress("unused") @Suppress("unused")
object FeedComponentsPatch : BaseBytecodePatch( object FeedComponentsPatch : BaseBytecodePatch(
@ -56,7 +66,8 @@ object FeedComponentsPatch : BaseBytecodePatch(
NavigationBarHookPatch::class, NavigationBarHookPatch::class,
PlayerTypeHookPatch::class, PlayerTypeHookPatch::class,
SettingsPatch::class, SettingsPatch::class,
SharedResourceIdPatch::class SharedResourceIdPatch::class,
BottomSheetHookPatch::class,
), ),
compatiblePackages = COMPATIBLE_PACKAGE, compatiblePackages = COMPATIBLE_PACKAGE,
fingerprints = setOf( fingerprints = setOf(
@ -68,14 +79,18 @@ object FeedComponentsPatch : BaseBytecodePatch(
ChannelListSubMenuTabletSyntheticFingerprint, ChannelListSubMenuTabletSyntheticFingerprint,
ChannelTabRendererFingerprint, ChannelTabRendererFingerprint,
ElementParserParentFingerprint, ElementParserParentFingerprint,
EngagementPanelBuilderFingerprint,
FilterBarHeightFingerprint, FilterBarHeightFingerprint,
LatestVideosButtonFingerprint, LatestVideosButtonFingerprint,
LinearLayoutManagerItemCountsFingerprint,
RelatedChipCloudFingerprint, RelatedChipCloudFingerprint,
ScrollTopParentFingerprint, ScrollTopParentFingerprint,
SearchResultsChipBarFingerprint, SearchResultsChipBarFingerprint,
ShowMoreButtonFingerprint ShowMoreButtonFingerprint,
) )
) { ) {
private const val CAROUSEL_SHELF_FILTER_CLASS_DESCRIPTOR =
"$COMPONENTS_PATH/CarouselShelfFilter;"
private const val FEED_COMPONENTS_FILTER_CLASS_DESCRIPTOR = private const val FEED_COMPONENTS_FILTER_CLASS_DESCRIPTOR =
"$COMPONENTS_PATH/FeedComponentsFilter;" "$COMPONENTS_PATH/FeedComponentsFilter;"
private const val FEED_VIDEO_FILTER_CLASS_DESCRIPTOR = private const val FEED_VIDEO_FILTER_CLASS_DESCRIPTOR =
@ -84,6 +99,8 @@ object FeedComponentsPatch : BaseBytecodePatch(
"$COMPONENTS_PATH/FeedVideoViewsFilter;" "$COMPONENTS_PATH/FeedVideoViewsFilter;"
private const val KEYWORD_FILTER_CLASS_DESCRIPTOR = private const val KEYWORD_FILTER_CLASS_DESCRIPTOR =
"$COMPONENTS_PATH/KeywordContentFilter;" "$COMPONENTS_PATH/KeywordContentFilter;"
private const val RELATED_VIDEO_CLASS_DESCRIPTOR =
"$FEED_PATH/RelatedVideoPatch;"
override fun execute(context: BytecodeContext) { override fun execute(context: BytecodeContext) {
@ -113,8 +130,8 @@ object FeedComponentsPatch : BaseBytecodePatch(
// region patch for hide caption button // region patch for hide caption button
CaptionsButtonFingerprint.resultOrThrow().mutableMethod.apply { CaptionsButtonFingerprint.resultOrThrow().mutableMethod.apply {
val constIndex = getWideLiteralInstructionIndex(CaptionToggleContainer) val constIndex = indexOfFirstWideLiteralInstructionValueOrThrow(CaptionToggleContainer)
val insertIndex = getTargetIndexReversedOrThrow(constIndex, Opcode.IF_EQZ) val insertIndex = indexOfFirstInstructionReversedOrThrow(constIndex, Opcode.IF_EQZ)
val insertRegister = getInstruction<OneRegisterInstruction>(insertIndex).registerA val insertRegister = getInstruction<OneRegisterInstruction>(insertIndex).registerA
addInstructions( addInstructions(
@ -126,8 +143,8 @@ object FeedComponentsPatch : BaseBytecodePatch(
} }
CaptionsButtonSyntheticFingerprint.resultOrThrow().mutableMethod.apply { CaptionsButtonSyntheticFingerprint.resultOrThrow().mutableMethod.apply {
val constIndex = getWideLiteralInstructionIndex(CaptionToggleContainer) val constIndex = indexOfFirstWideLiteralInstructionValueOrThrow(CaptionToggleContainer)
val targetIndex = getTargetIndexOrThrow(constIndex, Opcode.MOVE_RESULT_OBJECT) val targetIndex = indexOfFirstInstructionOrThrow(constIndex, Opcode.MOVE_RESULT_OBJECT)
val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
addInstruction( addInstruction(
@ -138,6 +155,62 @@ object FeedComponentsPatch : BaseBytecodePatch(
// endregion // endregion
// region patch for hide relative video
fun Method.indexOfEngagementPanelBuilderInstruction(targetMethod: MutableMethod) =
indexOfFirstInstruction {
opcode == Opcode.INVOKE_DIRECT &&
MethodUtil.methodSignaturesMatch(
targetMethod,
getReference<MethodReference>()!!
)
}
EngagementPanelBuilderFingerprint.resultOrThrow().let {
it.mutableClass.methods.filter { method ->
method.indexOfEngagementPanelBuilderInstruction(it.mutableMethod) >= 0
}.forEach { method ->
method.apply {
val index = indexOfEngagementPanelBuilderInstruction(it.mutableMethod)
val register = getInstruction<OneRegisterInstruction>(index + 1).registerA
addInstruction(
index + 2,
"invoke-static {v$register}, " +
"$RELATED_VIDEO_CLASS_DESCRIPTOR->showEngagementPanel(Ljava/lang/Object;)V"
)
}
}
}
EngagementPanelUpdateFingerprint.alsoResolve(
context, EngagementPanelBuilderFingerprint
).mutableMethod.addInstruction(
0,
"invoke-static {}, $RELATED_VIDEO_CLASS_DESCRIPTOR->hideEngagementPanel()V"
)
// BytecodeUtils.getWalkerMethod must be used here
// Otherwise, MethodWalker finds the wrong class in YouTube 18.29.38:
// https://github.com/ReVanced/revanced-patcher/issues/309
LinearLayoutManagerItemCountsFingerprint.resultOrThrow().let {
val methodWalker =
it.getWalkerMethod(context, it.scanResult.patternScanResult!!.endIndex)
methodWalker.apply {
val index = indexOfFirstInstructionOrThrow(Opcode.MOVE_RESULT)
val register = getInstruction<OneRegisterInstruction>(index).registerA
addInstructions(
index + 1, """
invoke-static {v$register}, $RELATED_VIDEO_CLASS_DESCRIPTOR->overrideItemCounts(I)I
move-result v$register
"""
)
}
}
// endregion
// region patch for hide subscriptions channel section for tablet // region patch for hide subscriptions channel section for tablet
arrayOf( arrayOf(
@ -198,7 +271,7 @@ object FeedComponentsPatch : BaseBytecodePatch(
&& reference.returnType.startsWith("L") && reference.returnType.startsWith("L")
} }
val objectIndex = getTargetIndexOrThrow(Opcode.MOVE_OBJECT) val objectIndex = indexOfFirstInstructionOrThrow(Opcode.MOVE_OBJECT)
val objectRegister = getInstruction<TwoRegisterInstruction>(objectIndex).registerA val objectRegister = getInstruction<TwoRegisterInstruction>(objectIndex).registerA
val jumpIndex = it.scanResult.patternScanResult!!.startIndex val jumpIndex = it.scanResult.patternScanResult!!.startIndex
@ -253,7 +326,9 @@ object FeedComponentsPatch : BaseBytecodePatch(
ChannelTabRendererFingerprint.resultOrThrow().let { ChannelTabRendererFingerprint.resultOrThrow().let {
it.mutableMethod.apply { it.mutableMethod.apply {
val iteratorIndex = getTargetIndexWithMethodReferenceName("hasNext") val iteratorIndex = indexOfFirstInstructionOrThrow {
getReference<MethodReference>()?.name == "hasNext"
}
val iteratorRegister = val iteratorRegister =
getInstruction<FiveRegisterInstruction>(iteratorIndex).registerC getInstruction<FiveRegisterInstruction>(iteratorIndex).registerC
@ -265,7 +340,8 @@ object FeedComponentsPatch : BaseBytecodePatch(
&& reference.parameterTypes == channelTabBuilderMethod.parameterTypes && reference.parameterTypes == channelTabBuilderMethod.parameterTypes
} }
val objectIndex = getTargetIndexReversedOrThrow(targetIndex, Opcode.IGET_OBJECT) val objectIndex =
indexOfFirstInstructionReversedOrThrow(targetIndex, Opcode.IGET_OBJECT)
val objectInstruction = getInstruction<TwoRegisterInstruction>(objectIndex) val objectInstruction = getInstruction<TwoRegisterInstruction>(objectIndex)
val objectReference = getInstruction<ReferenceInstruction>(objectIndex).reference val objectReference = getInstruction<ReferenceInstruction>(objectIndex).reference
@ -285,6 +361,7 @@ object FeedComponentsPatch : BaseBytecodePatch(
// endregion // endregion
LithoFilterPatch.addFilter(CAROUSEL_SHELF_FILTER_CLASS_DESCRIPTOR)
LithoFilterPatch.addFilter(FEED_COMPONENTS_FILTER_CLASS_DESCRIPTOR) LithoFilterPatch.addFilter(FEED_COMPONENTS_FILTER_CLASS_DESCRIPTOR)
LithoFilterPatch.addFilter(FEED_VIDEO_FILTER_CLASS_DESCRIPTOR) LithoFilterPatch.addFilter(FEED_VIDEO_FILTER_CLASS_DESCRIPTOR)
LithoFilterPatch.addFilter(FEED_VIDEO_VIEWS_FILTER_CLASS_DESCRIPTOR) LithoFilterPatch.addFilter(FEED_VIDEO_VIEWS_FILTER_CLASS_DESCRIPTOR)

View File

@ -0,0 +1,21 @@
package app.revanced.patches.youtube.feed.components.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
internal object EngagementPanelUpdateFingerprint : MethodFingerprint(
returnType = "V",
accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL,
parameters = listOf("L", "Z"),
customFingerprint = { methodDef, _ ->
methodDef.indexOfFirstInstruction {
opcode == Opcode.INVOKE_VIRTUAL &&
getReference<MethodReference>().toString() == "Ljava/util/ArrayDeque;->pop()Ljava/lang/Object;"
} >= 0
}
)

View File

@ -0,0 +1,19 @@
package app.revanced.patches.youtube.feed.components.fingerprints
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
internal object LinearLayoutManagerItemCountsFingerprint : MethodFingerprint(
returnType = "I",
accessFlags = AccessFlags.FINAL.value,
parameters = listOf("L", "L", "L", "Z"),
opcodes = listOf(
Opcode.IF_NEZ,
Opcode.IF_LEZ,
Opcode.INVOKE_VIRTUAL,
),
customFingerprint = { methodDef, _ ->
methodDef.definingClass == "Landroid/support/v7/widget/LinearLayoutManager;"
}
)

View File

@ -7,7 +7,7 @@ import app.revanced.patches.youtube.general.audiotracks.fingerprints.StreamingMo
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
import app.revanced.patches.youtube.utils.integrations.Constants.GENERAL_CLASS_DESCRIPTOR import app.revanced.patches.youtube.utils.integrations.Constants.GENERAL_CLASS_DESCRIPTOR
import app.revanced.patches.youtube.utils.settings.SettingsPatch import app.revanced.patches.youtube.utils.settings.SettingsPatch
import app.revanced.util.getTargetIndexWithReferenceOrThrow import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.patch.BaseBytecodePatch import app.revanced.util.patch.BaseBytecodePatch
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
@ -15,6 +15,7 @@ import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
@Suppress("unused") @Suppress("unused")
object AudioTracksPatch : BaseBytecodePatch( object AudioTracksPatch : BaseBytecodePatch(
@ -32,15 +33,14 @@ object AudioTracksPatch : BaseBytecodePatch(
opcode == Opcode.CHECK_CAST opcode == Opcode.CHECK_CAST
&& (this as ReferenceInstruction).reference.toString() == "Lcom/google/android/libraries/youtube/innertube/model/media/FormatStreamModel;" && (this as ReferenceInstruction).reference.toString() == "Lcom/google/android/libraries/youtube/innertube/model/media/FormatStreamModel;"
} }
val arrayListIndex = getTargetIndexWithReferenceOrThrow( val arrayListIndex = indexOfFirstInstructionOrThrow(formatStreamModelIndex) {
formatStreamModelIndex, opcode == Opcode.INVOKE_INTERFACE &&
"Ljava/util/List;->add(Ljava/lang/Object;)Z" getReference<MethodReference>()?.toString() == "Ljava/util/List;->add(Ljava/lang/Object;)Z"
) }
val insertIndex = val insertIndex = indexOfFirstInstructionOrThrow(arrayListIndex) {
getTargetIndexWithReferenceOrThrow( opcode == Opcode.INVOKE_INTERFACE &&
arrayListIndex, getReference<MethodReference>()?.toString() == "Ljava/util/List;->isEmpty()Z"
"Ljava/util/List;->isEmpty()Z" } + 2
) + 2
val formatStreamModelRegister = val formatStreamModelRegister =
getInstruction<OneRegisterInstruction>(formatStreamModelIndex).registerA getInstruction<OneRegisterInstruction>(formatStreamModelIndex).registerA

View File

@ -1,57 +1,23 @@
package app.revanced.patches.youtube.general.autocaptions package app.revanced.patches.youtube.general.autocaptions
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patches.shared.captions.BaseAutoCaptionsPatch
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.shared.fingerprints.SubtitleTrackFingerprint
import app.revanced.patches.youtube.general.autocaptions.fingerprints.StoryboardRendererDecoderRecommendedLevelFingerprint
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
import app.revanced.patches.youtube.utils.fingerprints.StartVideoInformerFingerprint
import app.revanced.patches.youtube.utils.integrations.Constants.GENERAL_CLASS_DESCRIPTOR
import app.revanced.patches.youtube.utils.settings.SettingsPatch import app.revanced.patches.youtube.utils.settings.SettingsPatch
import app.revanced.util.patch.BaseBytecodePatch import app.revanced.util.patch.BaseBytecodePatch
import app.revanced.util.resultOrThrow
@Suppress("unused") @Suppress("unused")
object AutoCaptionsPatch : BaseBytecodePatch( object AutoCaptionsPatch : BaseBytecodePatch(
name = "Disable auto captions", name = "Disable auto captions",
description = "Adds an option to disable captions from being automatically enabled.", description = "Adds an option to disable captions from being automatically enabled.",
dependencies = setOf(SettingsPatch::class), dependencies = setOf(
compatiblePackages = COMPATIBLE_PACKAGE, BaseAutoCaptionsPatch::class,
fingerprints = setOf( SettingsPatch::class
SubtitleTrackFingerprint, ),
StartVideoInformerFingerprint, compatiblePackages = COMPATIBLE_PACKAGE
StoryboardRendererDecoderRecommendedLevelFingerprint,
)
) { ) {
override fun execute(context: BytecodeContext) { override fun execute(context: BytecodeContext) {
SubtitleTrackFingerprint.resultOrThrow().mutableMethod.apply {
addInstructionsWithLabels(
0, """
invoke-static {}, $GENERAL_CLASS_DESCRIPTOR->disableAutoCaptions()Z
move-result v0
if-eqz v0, :disabled
const/4 v0, 0x1
return v0
""", ExternalLabel("disabled", getInstruction(0))
)
}
mapOf(
StartVideoInformerFingerprint to 0,
StoryboardRendererDecoderRecommendedLevelFingerprint to 1
).forEach { (fingerprint, enabled) ->
fingerprint.resultOrThrow().mutableMethod.addInstructions(
0, """
const/4 v0, 0x$enabled
invoke-static {v0}, $GENERAL_CLASS_DESCRIPTOR->setCaptionsButtonStatus(Z)V
"""
)
}
/** /**
* Add settings * Add settings
*/ */

View File

@ -27,9 +27,9 @@ import app.revanced.patches.youtube.utils.integrations.Constants.GENERAL_CLASS_D
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.AccountSwitcherAccessibility import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.AccountSwitcherAccessibility
import app.revanced.patches.youtube.utils.settings.SettingsPatch import app.revanced.patches.youtube.utils.settings.SettingsPatch
import app.revanced.util.getTargetIndexOrThrow import app.revanced.util.getReference
import app.revanced.util.getTargetIndexWithMethodReferenceName import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.getWideLiteralInstructionIndex import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow
import app.revanced.util.patch.BaseBytecodePatch import app.revanced.util.patch.BaseBytecodePatch
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
@ -37,6 +37,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
import com.android.tools.smali.dexlib2.util.MethodUtil import com.android.tools.smali.dexlib2.util.MethodUtil
@Suppress("unused") @Suppress("unused")
@ -171,10 +172,13 @@ object LayoutComponentsPatch : BaseBytecodePatch(
AccountSwitcherAccessibilityLabelFingerprint.resultOrThrow().let { AccountSwitcherAccessibilityLabelFingerprint.resultOrThrow().let {
it.mutableMethod.apply { it.mutableMethod.apply {
val constIndex = getWideLiteralInstructionIndex(AccountSwitcherAccessibility) val constIndex =
val insertIndex = getTargetIndexOrThrow(constIndex, Opcode.IF_EQZ) indexOfFirstWideLiteralInstructionValueOrThrow(AccountSwitcherAccessibility)
val setVisibilityIndex = val insertIndex = indexOfFirstInstructionOrThrow(constIndex, Opcode.IF_EQZ)
getTargetIndexWithMethodReferenceName(insertIndex, "setVisibility") val setVisibilityIndex = indexOfFirstInstructionOrThrow(insertIndex) {
opcode == Opcode.INVOKE_VIRTUAL &&
getReference<MethodReference>()?.name == "setVisibility"
}
val visibilityRegister = val visibilityRegister =
getInstruction<FiveRegisterInstruction>(setVisibilityIndex).registerD getInstruction<FiveRegisterInstruction>(setVisibilityIndex).registerD
@ -209,8 +213,8 @@ object LayoutComponentsPatch : BaseBytecodePatch(
// region patch for hide tooltip content // region patch for hide tooltip content
TooltipContentFullscreenFingerprint.resultOrThrow().mutableMethod.apply { TooltipContentFullscreenFingerprint.resultOrThrow().mutableMethod.apply {
val literalIndex = getWideLiteralInstructionIndex(45384061) val literalIndex = indexOfFirstWideLiteralInstructionValueOrThrow(45384061)
val targetIndex = getTargetIndexOrThrow(literalIndex, Opcode.MOVE_RESULT) val targetIndex = indexOfFirstInstructionOrThrow(literalIndex, Opcode.MOVE_RESULT)
val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
addInstruction( addInstruction(

View File

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

View File

@ -10,8 +10,7 @@ import app.revanced.patches.youtube.general.layoutswitch.fingerprints.LayoutSwit
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
import app.revanced.patches.youtube.utils.integrations.Constants.GENERAL_CLASS_DESCRIPTOR import app.revanced.patches.youtube.utils.integrations.Constants.GENERAL_CLASS_DESCRIPTOR
import app.revanced.patches.youtube.utils.settings.SettingsPatch import app.revanced.patches.youtube.utils.settings.SettingsPatch
import app.revanced.util.getTargetIndexOrThrow import app.revanced.util.indexOfFirstInstructionReversedOrThrow
import app.revanced.util.getTargetIndexReversedOrThrow
import app.revanced.util.patch.BaseBytecodePatch import app.revanced.util.patch.BaseBytecodePatch
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
@ -34,7 +33,7 @@ object LayoutSwitchPatch : BaseBytecodePatch(
GetFormFactorFingerprint.resultOrThrow().let { GetFormFactorFingerprint.resultOrThrow().let {
it.mutableMethod.apply { it.mutableMethod.apply {
val jumpIndex = getTargetIndexReversedOrThrow(Opcode.SGET_OBJECT) val jumpIndex = indexOfFirstInstructionReversedOrThrow(Opcode.SGET_OBJECT)
addInstructionsWithLabels( addInstructionsWithLabels(
0, """ 0, """
@ -56,7 +55,7 @@ object LayoutSwitchPatch : BaseBytecodePatch(
LayoutSwitchFingerprint.resultOrThrow().let { LayoutSwitchFingerprint.resultOrThrow().let {
it.mutableMethod.apply { it.mutableMethod.apply {
val insertIndex = getTargetIndexOrThrow(Opcode.IF_NEZ) val insertIndex = indexOfFirstInstructionReversedOrThrow(Opcode.IF_NEZ)
val insertRegister = getInstruction<OneRegisterInstruction>(insertIndex).registerA val insertRegister = getInstruction<OneRegisterInstruction>(insertIndex).registerA
addInstructions( addInstructions(

View File

@ -6,7 +6,7 @@ import app.revanced.patches.youtube.general.loadingscreen.fingerprints.GradientL
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
import app.revanced.patches.youtube.utils.integrations.Constants.GENERAL_CLASS_DESCRIPTOR import app.revanced.patches.youtube.utils.integrations.Constants.GENERAL_CLASS_DESCRIPTOR
import app.revanced.patches.youtube.utils.settings.SettingsPatch import app.revanced.patches.youtube.utils.settings.SettingsPatch
import app.revanced.util.literalInstructionBooleanHook import app.revanced.util.injectLiteralInstructionBooleanCall
import app.revanced.util.patch.BaseBytecodePatch import app.revanced.util.patch.BaseBytecodePatch
@Suppress("unused") @Suppress("unused")
@ -29,7 +29,7 @@ object GradientLoadingScreenPatch : BaseBytecodePatch(
GradientLoadingScreenPrimaryFingerprint to 45412406, GradientLoadingScreenPrimaryFingerprint to 45412406,
GradientLoadingScreenSecondaryFingerprint to 45418917 GradientLoadingScreenSecondaryFingerprint to 45418917
).forEach { (fingerprint, literal) -> ).forEach { (fingerprint, literal) ->
fingerprint.literalInstructionBooleanHook( fingerprint.injectLiteralInstructionBooleanCall(
literal, literal,
"$GENERAL_CLASS_DESCRIPTOR->enableGradientLoadingScreen()Z" "$GENERAL_CLASS_DESCRIPTOR->enableGradientLoadingScreen()Z"
) )

View File

@ -44,8 +44,8 @@ import app.revanced.util.fingerprint.LiteralValueFingerprint
import app.revanced.util.getReference import app.revanced.util.getReference
import app.revanced.util.getWalkerMethod import app.revanced.util.getWalkerMethod
import app.revanced.util.indexOfFirstInstructionOrThrow import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfWideLiteralInstructionOrThrow import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow
import app.revanced.util.literalInstructionBooleanHook import app.revanced.util.injectLiteralInstructionBooleanCall
import app.revanced.util.patch.BaseBytecodePatch import app.revanced.util.patch.BaseBytecodePatch
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
@ -170,7 +170,7 @@ object MiniplayerPatch : BaseBytecodePatch(
} }
if (SettingsPatch.upward1925) { if (SettingsPatch.upward1925) {
MiniplayerModernEnabledFingerprint.literalInstructionBooleanHook( MiniplayerModernEnabledFingerprint.injectLiteralInstructionBooleanCall(
45622882, 45622882,
"$INTEGRATIONS_CLASS_DESCRIPTOR->getModernMiniplayerOverride(Z)Z" "$INTEGRATIONS_CLASS_DESCRIPTOR->getModernMiniplayerOverride(Z)Z"
) )
@ -181,11 +181,11 @@ object MiniplayerPatch : BaseBytecodePatch(
// region Enable double tap action. // region Enable double tap action.
if (SettingsPatch.upward1925) { if (SettingsPatch.upward1925) {
MiniplayerModernConstructorFingerprint.literalInstructionBooleanHook( MiniplayerModernConstructorFingerprint.injectLiteralInstructionBooleanCall(
45628823, 45628823,
"$INTEGRATIONS_CLASS_DESCRIPTOR->enableMiniplayerDoubleTapAction()Z" "$INTEGRATIONS_CLASS_DESCRIPTOR->enableMiniplayerDoubleTapAction()Z"
) )
MiniplayerModernConstructorFingerprint.literalInstructionBooleanHook( MiniplayerModernConstructorFingerprint.injectLiteralInstructionBooleanCall(
45630429, 45630429,
"$INTEGRATIONS_CLASS_DESCRIPTOR->getModernMiniplayerOverride(Z)Z" "$INTEGRATIONS_CLASS_DESCRIPTOR->getModernMiniplayerOverride(Z)Z"
) )
@ -211,7 +211,8 @@ object MiniplayerPatch : BaseBytecodePatch(
YtOutlinePictureInPictureWhite to YtOutlineXWhite, YtOutlinePictureInPictureWhite to YtOutlineXWhite,
YtOutlineXWhite to YtOutlinePictureInPictureWhite, YtOutlineXWhite to YtOutlinePictureInPictureWhite,
).forEach { (originalResource, replacementResource) -> ).forEach { (originalResource, replacementResource) ->
val imageResourceIndex = indexOfWideLiteralInstructionOrThrow(originalResource) val imageResourceIndex =
indexOfFirstWideLiteralInstructionValueOrThrow(originalResource)
val register = val register =
getInstruction<OneRegisterInstruction>(imageResourceIndex).registerA getInstruction<OneRegisterInstruction>(imageResourceIndex).registerA
@ -321,7 +322,7 @@ object MiniplayerPatch : BaseBytecodePatch(
// region Enable drag and drop. // region Enable drag and drop.
if (SettingsPatch.upward1923) { if (SettingsPatch.upward1923) {
MiniplayerModernDragAndDropFingerprint.literalInstructionBooleanHook( MiniplayerModernDragAndDropFingerprint.injectLiteralInstructionBooleanCall(
45628752, 45628752,
"$INTEGRATIONS_CLASS_DESCRIPTOR->enableMiniplayerDragAndDrop()Z" "$INTEGRATIONS_CLASS_DESCRIPTOR->enableMiniplayerDragAndDrop()Z"
) )
@ -388,7 +389,7 @@ object MiniplayerPatch : BaseBytecodePatch(
) { ) {
resultOrThrow().mutableMethod.apply { resultOrThrow().mutableMethod.apply {
val imageViewIndex = indexOfFirstInstructionOrThrow( val imageViewIndex = indexOfFirstInstructionOrThrow(
indexOfWideLiteralInstructionOrThrow(literalValue) indexOfFirstWideLiteralInstructionValueOrThrow(literalValue)
) { ) {
opcode == Opcode.CHECK_CAST && getReference<TypeReference>()?.type == hookedClassType opcode == Opcode.CHECK_CAST && getReference<TypeReference>()?.type == hookedClassType
} }

View File

@ -4,7 +4,7 @@ import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patches.youtube.general.miniplayer.fingerprints.MiniplayerModernConstructorFingerprint.constructorMethodCount import app.revanced.patches.youtube.general.miniplayer.fingerprints.MiniplayerModernConstructorFingerprint.constructorMethodCount
import app.revanced.patches.youtube.utils.settings.SettingsPatch import app.revanced.patches.youtube.utils.settings.SettingsPatch
import app.revanced.util.containsWideLiteralInstructionIndex import app.revanced.util.containsWideLiteralInstructionValue
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.util.MethodUtil import com.android.tools.smali.dexlib2.util.MethodUtil
@ -13,7 +13,7 @@ internal object MiniplayerModernConstructorFingerprint : MethodFingerprint(
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
parameters = listOf("L"), parameters = listOf("L"),
customFingerprint = custom@{ methodDef, classDef -> customFingerprint = custom@{ methodDef, classDef ->
if (!methodDef.containsWideLiteralInstructionIndex(45623000)) // Magic number found in the constructor. if (!methodDef.containsWideLiteralInstructionValue(45623000)) // Magic number found in the constructor.
return@custom false return@custom false
classDef.methods.forEach { classDef.methods.forEach {
@ -24,8 +24,8 @@ internal object MiniplayerModernConstructorFingerprint : MethodFingerprint(
return@custom true return@custom true
// Double tap action (Used in YouTube 19.25.39+). // Double tap action (Used in YouTube 19.25.39+).
methodDef.containsWideLiteralInstructionIndex(45628823) methodDef.containsWideLiteralInstructionValue(45628823)
&& methodDef.containsWideLiteralInstructionIndex(45630429) && methodDef.containsWideLiteralInstructionValue(45630429)
} }
) { ) {
private var constructorMethodCount = 0 private var constructorMethodCount = 0

View File

@ -0,0 +1,109 @@
package app.revanced.patches.youtube.general.music
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patches.youtube.general.music.fingerprints.AppDeepLinkFingerprint
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
import app.revanced.patches.youtube.utils.gms.GmsCoreSupportResourcePatch.PackageNameYouTubeMusic
import app.revanced.patches.youtube.utils.integrations.Constants.GENERAL_PATH
import app.revanced.patches.youtube.utils.settings.ResourceUtils.addEntryValues
import app.revanced.patches.youtube.utils.settings.SettingsBytecodePatch
import app.revanced.patches.youtube.utils.settings.SettingsPatch
import app.revanced.util.findMethodOrThrow
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.patch.BaseBytecodePatch
import app.revanced.util.resultOrThrow
import app.revanced.util.valueOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
import java.io.Closeable
@Suppress("unused")
object YouTubeMusicActionsPatch : BaseBytecodePatch(
name = "Hook YouTube Music actions",
description = "Adds support for opening music in RVX Music using the in-app YouTube Music button.",
dependencies = setOf(SettingsPatch::class),
compatiblePackages = COMPATIBLE_PACKAGE,
fingerprints = setOf(AppDeepLinkFingerprint)
), Closeable {
private const val INTEGRATIONS_CLASS_DESCRIPTOR =
"$GENERAL_PATH/YouTubeMusicActionsPatch;"
override fun execute(context: BytecodeContext) {
AppDeepLinkFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val packageNameIndex = it.scanResult.patternScanResult!!.startIndex
val packageNameField =
getInstruction<ReferenceInstruction>(packageNameIndex).reference.toString()
implementation!!.instructions
.withIndex()
.filter { (_, instruction) ->
instruction.opcode == Opcode.IGET_OBJECT &&
instruction.getReference<FieldReference>()
?.toString() == packageNameField
}
.map { (index, _) -> index }
.reversed()
.forEach { index ->
val register = getInstruction<TwoRegisterInstruction>(index).registerA
addInstructions(
index + 1, """
invoke-static {v$register}, $INTEGRATIONS_CLASS_DESCRIPTOR->overridePackageName(Ljava/lang/String;)Ljava/lang/String;
move-result-object v$register
"""
)
}
}
}
/**
* Add settings
*/
SettingsPatch.addPreference(
arrayOf(
"PREFERENCE_SCREEN: GENERAL",
"SETTINGS: HOOK_BUTTONS",
"SETTINGS: HOOK_YOUTUBE_MUSIC_ACTIONS"
)
)
SettingsPatch.updatePatchStatus(this)
}
override fun close() {
if (SettingsPatch.containsPatch("GmsCore support")) {
val musicPackageName = PackageNameYouTubeMusic.valueOrThrow()
SettingsPatch.contexts.addEntryValues(
"revanced_third_party_youtube_music_label",
"RVX Music"
)
SettingsPatch.contexts.addEntryValues(
"revanced_third_party_youtube_music_package_name",
musicPackageName
)
SettingsBytecodePatch.contexts.findMethodOrThrow(INTEGRATIONS_CLASS_DESCRIPTOR) {
name == "getRVXMusicPackageName"
}.apply {
val replaceIndex = indexOfFirstInstructionOrThrow(Opcode.CONST_STRING)
val replaceRegister =
getInstruction<OneRegisterInstruction>(replaceIndex).registerA
replaceInstruction(
replaceIndex,
"const-string v$replaceRegister, \"$musicPackageName\""
)
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More