mirror of
https://github.com/inotia00/revanced-patches.git
synced 2025-05-07 18:14:36 +02:00
Merge branch 'dev' into revanced-extended
This commit is contained in:
commit
b725e54aee
82
README.md
82
README.md
@ -44,6 +44,8 @@ ReVanced Extended Patches.
|
||||
| `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 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 |
|
||||
| `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 |
|
||||
@ -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 |
|
||||
| `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 |
|
||||
| `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 |
|
||||
</details>
|
||||
|
||||
@ -75,41 +77,42 @@ ReVanced Extended Patches.
|
||||
|
||||
| 💊 Patch | 📜 Description | 🏹 Target Version |
|
||||
|:--------:|:--------------:|:-----------------:|
|
||||
| `Amoled` | Applies a pure black theme to some components. | 6.29.58 ~ 7.17.51 |
|
||||
| `Bitrate default value` | Sets the audio quality to 'Always High' when you first install the app. | 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.29.58 ~ 7.17.51 |
|
||||
| `Certificate spoof` | Enables YouTube Music to work with Android Auto by spoofing the YouTube Music certificate. | 6.29.58 ~ 7.17.51 |
|
||||
| `Change share sheet` | Add option to change from in-app share sheet to system share sheet. | 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.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.29.58 ~ 7.17.51 |
|
||||
| `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 header for YouTube Music` | Applies a custom header in the top left corner within the app. | 6.29.58 ~ 7.17.51 |
|
||||
| `Disable Cairo splash animation` | Adds an option to disable Cairo splash animation. | 7.06.54 ~ 7.17.51 |
|
||||
| `Disable auto captions` | Adds an option to disable captions from being automatically enabled. | 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.29.58 ~ 7.17.51 |
|
||||
| `Enable OPUS codec` | Adds an options to enable the OPUS audio codec if the player response includes. | 6.29.58 ~ 7.17.51 |
|
||||
| `Enable debug logging` | Adds an option to enable debug logging. | 6.29.58 ~ 7.17.51 |
|
||||
| `Enable landscape mode` | Adds an option to enable landscape mode when rotating the screen on phones. | 6.29.58 ~ 7.17.51 |
|
||||
| `Flyout menu components` | Adds options to hide or change flyout menu components. | 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.29.58 ~ 7.17.51 |
|
||||
| `Hide account components` | Adds options to hide components related to the account menu. | 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.29.58 ~ 7.17.51 |
|
||||
| `Hide ads` | Adds options to hide ads. | 6.29.58 ~ 7.17.51 |
|
||||
| `Hide layout components` | Adds options to hide general layout components. | 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.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.29.58 ~ 7.17.51 |
|
||||
| `Navigation bar components` | Adds options to hide or change components related to the navigation bar. | 6.29.58 ~ 7.17.51 |
|
||||
| `Player components` | Adds options to hide or change components related to the player. | 6.29.58 ~ 7.17.51 |
|
||||
| `Remove background playback restrictions` | Removes restrictions on background playback, including for kids videos. | 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.29.58 ~ 7.17.51 |
|
||||
| `Restore old style library shelf` | Adds an option to return the Library tab to the old style. | 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.29.58 ~ 7.17.51 |
|
||||
| `Sanitize sharing links` | Adds an option to remove tracking query parameters from URLs when sharing links. | 6.29.58 ~ 7.17.51 |
|
||||
| `Settings for YouTube Music` | Applies mandatory patches to implement ReVanced Extended settings into the application. | 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.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.29.58 ~ 7.17.51 |
|
||||
| `Translations for YouTube Music` | Add translations or remove string resources. | 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.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.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.20.51 ~ 7.16.53 |
|
||||
| `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.20.51 ~ 7.16.53 |
|
||||
| `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.20.51 ~ 7.16.53 |
|
||||
| `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.20.51 ~ 7.16.53 |
|
||||
| `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.20.51 ~ 7.16.53 |
|
||||
| `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.20.51 ~ 7.16.53 |
|
||||
| `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.20.51 ~ 7.16.53 |
|
||||
| `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.20.51 ~ 7.16.53 |
|
||||
| `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.20.51 ~ 7.16.53 |
|
||||
| `Hide ads` | Adds options to hide ads. | 6.20.51 ~ 7.16.53 |
|
||||
| `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.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.20.51 ~ 7.16.53 |
|
||||
| `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.20.51 ~ 7.16.53 |
|
||||
| `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.20.51 ~ 7.16.53 |
|
||||
| `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.20.51 ~ 7.16.53 |
|
||||
| `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.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.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.20.51 ~ 7.16.53 |
|
||||
| `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.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>
|
||||
|
||||
### [📦 `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",
|
||||
"versions": [
|
||||
"6.29.58",
|
||||
"6.33.52",
|
||||
"6.20.51",
|
||||
"6.29.59",
|
||||
"6.42.55",
|
||||
"6.51.53",
|
||||
"7.16.53",
|
||||
"7.17.51"
|
||||
"7.16.53"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
@ -1,4 +1,4 @@
|
||||
org.gradle.parallel = true
|
||||
org.gradle.caching = true
|
||||
kotlin.code.style = official
|
||||
version = 4.13.1
|
||||
version = 4.14.1
|
||||
|
File diff suppressed because one or more lines are too long
@ -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.settings.CategoryType
|
||||
import app.revanced.patches.music.utils.settings.SettingsPatch
|
||||
import app.revanced.util.getTargetIndexWithMethodReferenceNameOrThrow
|
||||
import app.revanced.util.getTargetIndexWithReferenceOrThrow
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import app.revanced.util.patch.BaseBytecodePatch
|
||||
import app.revanced.util.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
|
||||
@Suppress("unused")
|
||||
object AccountComponentsPatch : BaseBytecodePatch(
|
||||
@ -43,8 +45,14 @@ object AccountComponentsPatch : BaseBytecodePatch(
|
||||
|
||||
MenuEntryFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val textIndex = getTargetIndexWithMethodReferenceNameOrThrow("setText")
|
||||
val viewIndex = getTargetIndexWithMethodReferenceNameOrThrow("addView")
|
||||
val textIndex = indexOfFirstInstructionOrThrow {
|
||||
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 viewRegister = getInstruction<FiveRegisterInstruction>(viewIndex).registerD
|
||||
@ -64,9 +72,14 @@ object AccountComponentsPatch : BaseBytecodePatch(
|
||||
AccountSwitcherAccessibilityLabelFingerprint.resultOrThrow().let { result ->
|
||||
result.mutableMethod.apply {
|
||||
|
||||
val textColorIndex = getTargetIndexWithMethodReferenceNameOrThrow("setTextColor")
|
||||
val setVisibilityIndex =
|
||||
getTargetIndexWithMethodReferenceNameOrThrow(textColorIndex, "setVisibility")
|
||||
val textColorIndex = indexOfFirstInstructionOrThrow {
|
||||
opcode == Opcode.INVOKE_VIRTUAL &&
|
||||
getReference<MethodReference>()?.name == "setTextColor"
|
||||
}
|
||||
val setVisibilityIndex = indexOfFirstInstructionOrThrow(textColorIndex) {
|
||||
opcode == Opcode.INVOKE_VIRTUAL &&
|
||||
getReference<MethodReference>()?.name == "setVisibility"
|
||||
}
|
||||
val textViewInstruction =
|
||||
getInstruction<FiveRegisterInstruction>(setVisibilityIndex)
|
||||
|
||||
@ -98,8 +111,12 @@ object AccountComponentsPatch : BaseBytecodePatch(
|
||||
|
||||
TermsOfServiceFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val insertIndex =
|
||||
getTargetIndexWithReferenceOrThrow("/PrivacyTosFooter;->setVisibility(I)V")
|
||||
val insertIndex = indexOfFirstInstructionOrThrow {
|
||||
val reference = getReference<MethodReference>()
|
||||
opcode == Opcode.INVOKE_VIRTUAL &&
|
||||
reference?.name == "setVisibility" &&
|
||||
reference.definingClass.endsWith("/PrivacyTosFooter;")
|
||||
}
|
||||
val visibilityRegister =
|
||||
getInstruction<FiveRegisterInstruction>(insertIndex).registerD
|
||||
|
||||
|
@ -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.SettingsPatch
|
||||
import app.revanced.patches.music.video.information.VideoInformationPatch
|
||||
import app.revanced.util.getTargetIndexWithMethodReferenceNameOrThrow
|
||||
import app.revanced.util.getTargetIndexWithReferenceOrThrow
|
||||
import app.revanced.util.getWideLiteralInstructionIndex
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow
|
||||
import app.revanced.util.patch.BaseBytecodePatch
|
||||
import app.revanced.util.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
@ -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.ReferenceInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
import kotlin.math.min
|
||||
|
||||
@Suppress("unused")
|
||||
@ -48,7 +48,10 @@ object ActionBarComponentsPatch : BaseBytecodePatch(
|
||||
it.mutableMethod.apply {
|
||||
|
||||
// hook download button
|
||||
val addViewIndex = getTargetIndexWithMethodReferenceNameOrThrow("addView")
|
||||
val addViewIndex = indexOfFirstInstructionOrThrow {
|
||||
opcode == Opcode.INVOKE_VIRTUAL &&
|
||||
getReference<MethodReference>()?.name == "addView"
|
||||
}
|
||||
val addViewRegister =
|
||||
getInstruction<FiveRegisterInstruction>(addViewIndex).registerD
|
||||
|
||||
@ -83,10 +86,15 @@ object ActionBarComponentsPatch : BaseBytecodePatch(
|
||||
removeInstruction(replaceIndex)
|
||||
|
||||
// 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 spannedIndex = getTargetIndexWithReferenceOrThrow(")Landroid/text/Spanned;")
|
||||
val spannedIndex = indexOfFirstInstructionOrThrow {
|
||||
getReference<MethodReference>()?.returnType == "Landroid/text/Spanned;"
|
||||
}
|
||||
val spannedRegister =
|
||||
getInstruction<FiveRegisterInstruction>(spannedIndex).registerC
|
||||
val spannedReference = getInstruction<ReferenceInstruction>(spannedIndex).reference
|
||||
@ -124,7 +132,8 @@ object ActionBarComponentsPatch : BaseBytecodePatch(
|
||||
|
||||
LikeDislikeContainerFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val insertIndex = getWideLiteralInstructionIndex(LikeDislikeContainer) + 2
|
||||
val insertIndex =
|
||||
indexOfFirstWideLiteralInstructionValueOrThrow(LikeDislikeContainer) + 2
|
||||
val insertRegister = getInstruction<OneRegisterInstruction>(insertIndex).registerA
|
||||
|
||||
addInstruction(
|
||||
|
@ -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.FloatingLayout
|
||||
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.SettingsPatch
|
||||
import app.revanced.patches.shared.litho.LithoFilterPatch
|
||||
import app.revanced.util.getTargetIndexOrThrow
|
||||
import app.revanced.util.getTargetIndexWithReferenceOrThrow
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.getWalkerMethod
|
||||
import app.revanced.util.getWideLiteralInstructionIndex
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow
|
||||
import app.revanced.util.patch.BaseBytecodePatch
|
||||
import app.revanced.util.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
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
|
||||
|
||||
@Suppress("unused")
|
||||
object AdsPatch : BaseBytecodePatch(
|
||||
@ -61,9 +63,6 @@ object AdsPatch : BaseBytecodePatch(
|
||||
private const val ADS_FILTER_CLASS_DESCRIPTOR =
|
||||
"$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 =
|
||||
"$ADS_PATH/PremiumPromotionPatch;"
|
||||
|
||||
@ -82,7 +81,7 @@ object AdsPatch : BaseBytecodePatch(
|
||||
// litho view, used in 'ShowDialogCommandOuterClass' in innertube
|
||||
ShowDialogCommandFingerprint
|
||||
.resultOrThrow()
|
||||
.hookLithoFullscreenAds(context)
|
||||
.hookLithoFullscreenAds()
|
||||
|
||||
// endregion
|
||||
|
||||
@ -90,7 +89,7 @@ object AdsPatch : BaseBytecodePatch(
|
||||
|
||||
FloatingLayoutFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val targetIndex = getWideLiteralInstructionIndex(FloatingLayout) + 2
|
||||
val targetIndex = indexOfFirstWideLiteralInstructionValueOrThrow(FloatingLayout) + 2
|
||||
val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
|
||||
|
||||
addInstruction(
|
||||
@ -106,7 +105,8 @@ object AdsPatch : BaseBytecodePatch(
|
||||
|
||||
NotifierShelfFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val linearLayoutIndex = getWideLiteralInstructionIndex(ButtonContainer) + 3
|
||||
val linearLayoutIndex =
|
||||
indexOfFirstWideLiteralInstructionValueOrThrow(ButtonContainer) + 3
|
||||
val linearLayoutRegister =
|
||||
getInstruction<OneRegisterInstruction>(linearLayoutIndex).registerA
|
||||
|
||||
@ -138,16 +138,20 @@ object AdsPatch : BaseBytecodePatch(
|
||||
AccountMenuFooterFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val constIndex =
|
||||
getWideLiteralInstructionIndex(SharedResourceIdPatch.PrivacyTosFooter)
|
||||
val walkerIndex = getTargetIndexOrThrow(constIndex + 2, Opcode.INVOKE_VIRTUAL)
|
||||
val viewIndex = getTargetIndexOrThrow(constIndex, Opcode.IGET_OBJECT)
|
||||
indexOfFirstWideLiteralInstructionValueOrThrow(PrivacyTosFooter)
|
||||
val walkerIndex =
|
||||
indexOfFirstInstructionOrThrow(constIndex + 2, Opcode.INVOKE_VIRTUAL)
|
||||
val viewIndex = indexOfFirstInstructionOrThrow(constIndex, Opcode.IGET_OBJECT)
|
||||
val viewReference =
|
||||
getInstruction<ReferenceInstruction>(viewIndex).reference.toString()
|
||||
|
||||
val walkerMethod = getWalkerMethod(context, walkerIndex)
|
||||
walkerMethod.apply {
|
||||
val insertIndex = getTargetIndexWithReferenceOrThrow(viewReference)
|
||||
val nullCheckIndex = getTargetIndexOrThrow(insertIndex - 1, Opcode.IF_NEZ)
|
||||
val insertIndex = indexOfFirstInstructionOrThrow {
|
||||
getReference<FieldReference>()?.toString() == viewReference
|
||||
}
|
||||
val nullCheckIndex =
|
||||
indexOfFirstInstructionOrThrow(insertIndex - 1, Opcode.IF_NEZ)
|
||||
val nullCheckRegister =
|
||||
getInstruction<OneRegisterInstruction>(nullCheckIndex).registerA
|
||||
|
||||
@ -174,19 +178,12 @@ object AdsPatch : BaseBytecodePatch(
|
||||
// endregion
|
||||
|
||||
LithoFilterPatch.addFilter(ADS_FILTER_CLASS_DESCRIPTOR)
|
||||
LithoFilterPatch.addFilter(FULLSCREEN_ADS_FILTER_CLASS_DESCRIPTOR)
|
||||
|
||||
SettingsPatch.addSwitchPreference(
|
||||
CategoryType.ADS,
|
||||
"revanced_hide_fullscreen_ads",
|
||||
"true"
|
||||
)
|
||||
SettingsPatch.addSwitchPreference(
|
||||
CategoryType.ADS,
|
||||
"revanced_hide_fullscreen_ads_type",
|
||||
"true",
|
||||
"revanced_hide_fullscreen_ads"
|
||||
)
|
||||
SettingsPatch.addSwitchPreference(
|
||||
CategoryType.ADS,
|
||||
"revanced_hide_general_ads",
|
||||
|
@ -4,14 +4,14 @@ import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.ButtonContainer
|
||||
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
|
||||
|
||||
internal object NotifierShelfFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
|
||||
customFingerprint = { methodDef, _ ->
|
||||
methodDef.containsWideLiteralInstructionIndex(MusicNotifierShelf)
|
||||
&& methodDef.containsWideLiteralInstructionIndex(ButtonContainer)
|
||||
methodDef.containsWideLiteralInstructionValue(MusicNotifierShelf)
|
||||
&& methodDef.containsWideLiteralInstructionValue(ButtonContainer)
|
||||
}
|
||||
)
|
@ -1,17 +1,28 @@
|
||||
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.util.fingerprint.LiteralValueFingerprint
|
||||
import app.revanced.util.containsWideLiteralInstructionValue
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal object ShowDialogCommandFingerprint : LiteralValueFingerprint(
|
||||
internal object ShowDialogCommandFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
parameters = listOf("[B", "L"),
|
||||
opcodes = listOf(
|
||||
Opcode.IF_EQ,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
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")
|
||||
},
|
||||
)
|
@ -5,7 +5,6 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.patch.PatchException
|
||||
import app.revanced.patcher.util.smali.ExternalLabel
|
||||
import app.revanced.patches.music.flyoutmenu.components.fingerprints.DialogSolidFingerprint
|
||||
import app.revanced.patches.music.flyoutmenu.components.fingerprints.EndButtonsContainerFingerprint
|
||||
@ -20,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.resourceid.SharedResourceIdPatch
|
||||
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.EndButtonsContainer
|
||||
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.TrimSilenceSwitch
|
||||
import app.revanced.patches.music.utils.settings.CategoryType
|
||||
import app.revanced.patches.music.utils.settings.SettingsPatch
|
||||
import app.revanced.patches.music.utils.videotype.VideoTypeHookPatch
|
||||
import app.revanced.patches.music.video.information.VideoInformationPatch
|
||||
import app.revanced.patches.shared.litho.LithoFilterPatch
|
||||
import app.revanced.util.getTargetIndexOrThrow
|
||||
import app.revanced.util.getTargetIndexWithMethodReferenceNameOrThrow
|
||||
import app.revanced.util.findMethodOrThrow
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.getWalkerMethod
|
||||
import app.revanced.util.getWideLiteralInstructionIndex
|
||||
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.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
@ -88,7 +88,7 @@ object FlyoutMenuComponentsPatch : BaseBytecodePatch(
|
||||
// region patch for enable trim silence
|
||||
|
||||
TrimSilenceConfigFingerprint.result?.let {
|
||||
TrimSilenceConfigFingerprint.literalInstructionBooleanHook(
|
||||
TrimSilenceConfigFingerprint.injectLiteralInstructionBooleanCall(
|
||||
45619123,
|
||||
"$FLYOUT_CLASS_DESCRIPTOR->enableTrimSilence(Z)Z"
|
||||
)
|
||||
@ -96,40 +96,39 @@ object FlyoutMenuComponentsPatch : BaseBytecodePatch(
|
||||
TrimSilenceSwitchFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val constIndex =
|
||||
getWideLiteralInstructionIndex(SharedResourceIdPatch.TrimSilenceSwitch)
|
||||
indexOfFirstWideLiteralInstructionValueOrThrow(TrimSilenceSwitch)
|
||||
val onCheckedChangedListenerIndex =
|
||||
getTargetIndexOrThrow(constIndex, Opcode.INVOKE_DIRECT)
|
||||
indexOfFirstInstructionOrThrow(constIndex, Opcode.INVOKE_DIRECT)
|
||||
val onCheckedChangedListenerReference =
|
||||
getInstruction<ReferenceInstruction>(onCheckedChangedListenerIndex).reference
|
||||
val onCheckedChangedListenerDefiningClass =
|
||||
(onCheckedChangedListenerReference as MethodReference).definingClass
|
||||
val onCheckedChangedListenerClass =
|
||||
context.findClass(onCheckedChangedListenerDefiningClass)!!.mutableClass
|
||||
|
||||
onCheckedChangedListenerClass.methods.find { method -> method.name == "onCheckedChanged" }
|
||||
?.apply {
|
||||
val walkerIndex = indexOfFirstInstructionOrThrow {
|
||||
val reference =
|
||||
((this as? ReferenceInstruction)?.reference as? MethodReference)
|
||||
|
||||
context.findMethodOrThrow(onCheckedChangedListenerDefiningClass) {
|
||||
name == "onCheckedChanged"
|
||||
}.apply {
|
||||
val onCheckedChangedWalkerIndex =
|
||||
indexOfFirstInstructionOrThrow {
|
||||
val reference = getReference<MethodReference>()
|
||||
opcode == Opcode.INVOKE_VIRTUAL
|
||||
&& reference?.returnType == "V"
|
||||
&& reference.parameterTypes.size == 1
|
||||
&& reference.parameterTypes[0] == "Z"
|
||||
}
|
||||
getWalkerMethod(context, walkerIndex).apply {
|
||||
val insertIndex = getTargetIndexOrThrow(Opcode.MOVE_RESULT)
|
||||
val insertRegister =
|
||||
getInstruction<OneRegisterInstruction>(insertIndex).registerA
|
||||
|
||||
addInstructions(
|
||||
insertIndex + 1, """
|
||||
getWalkerMethod(context, onCheckedChangedWalkerIndex).apply {
|
||||
val insertIndex = indexOfFirstInstructionOrThrow(Opcode.MOVE_RESULT)
|
||||
val insertRegister =
|
||||
getInstruction<OneRegisterInstruction>(insertIndex).registerA
|
||||
|
||||
addInstructions(
|
||||
insertIndex + 1, """
|
||||
invoke-static {v$insertRegister}, $FLYOUT_CLASS_DESCRIPTOR->enableTrimSilenceSwitch(Z)Z
|
||||
move-result v$insertRegister
|
||||
"""
|
||||
)
|
||||
}
|
||||
} ?: throw PatchException("onClickClass not found!")
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -142,7 +141,7 @@ object FlyoutMenuComponentsPatch : BaseBytecodePatch(
|
||||
|
||||
MenuItemFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val freeIndex = getTargetIndexOrThrow(Opcode.OR_INT_LIT16)
|
||||
val freeIndex = indexOfFirstInstructionOrThrow(Opcode.OR_INT_LIT16)
|
||||
val textViewIndex = it.scanResult.patternScanResult!!.startIndex
|
||||
val imageViewIndex = it.scanResult.patternScanResult!!.endIndex
|
||||
|
||||
@ -175,8 +174,10 @@ object FlyoutMenuComponentsPatch : BaseBytecodePatch(
|
||||
|
||||
TouchOutsideFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val setOnClickListenerIndex =
|
||||
getTargetIndexWithMethodReferenceNameOrThrow("setOnClickListener")
|
||||
val setOnClickListenerIndex = indexOfFirstInstructionOrThrow {
|
||||
opcode == Opcode.INVOKE_VIRTUAL &&
|
||||
getReference<MethodReference>()?.name == "setOnClickListener"
|
||||
}
|
||||
val setOnClickListenerRegister =
|
||||
getInstruction<FiveRegisterInstruction>(setOnClickListenerIndex).registerC
|
||||
|
||||
@ -189,8 +190,10 @@ object FlyoutMenuComponentsPatch : BaseBytecodePatch(
|
||||
|
||||
EndButtonsContainerFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val startIndex = getWideLiteralInstructionIndex(EndButtonsContainer)
|
||||
val targetIndex = getTargetIndexOrThrow(startIndex, Opcode.MOVE_RESULT_OBJECT)
|
||||
val startIndex =
|
||||
indexOfFirstWideLiteralInstructionValueOrThrow(EndButtonsContainer)
|
||||
val targetIndex =
|
||||
indexOfFirstInstructionOrThrow(startIndex, Opcode.MOVE_RESULT_OBJECT)
|
||||
val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
|
||||
|
||||
addInstruction(
|
||||
|
@ -1,39 +1,24 @@
|
||||
package app.revanced.patches.music.general.autocaptions
|
||||
|
||||
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.integrations.Constants.GENERAL_CLASS_DESCRIPTOR
|
||||
import app.revanced.patches.music.utils.settings.CategoryType
|
||||
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.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
|
||||
@Suppress("unused")
|
||||
object AutoCaptionsPatch : BaseBytecodePatch(
|
||||
name = "Disable auto captions",
|
||||
description = "Adds an option to disable captions from being automatically enabled.",
|
||||
dependencies = setOf(SettingsPatch::class),
|
||||
dependencies = setOf(
|
||||
BaseAutoCaptionsPatch::class,
|
||||
SettingsPatch::class
|
||||
),
|
||||
compatiblePackages = COMPATIBLE_PACKAGE,
|
||||
fingerprints = setOf(SubtitleTrackFingerprint),
|
||||
) {
|
||||
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(
|
||||
CategoryType.GENERAL,
|
||||
"revanced_disable_auto_captions",
|
||||
|
@ -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.GENERAL_CLASS_DESCRIPTOR
|
||||
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.settings.CategoryType
|
||||
import app.revanced.patches.music.utils.settings.SettingsPatch
|
||||
import app.revanced.patches.shared.litho.LithoFilterPatch
|
||||
import app.revanced.patches.shared.settingmenu.SettingsMenuPatch
|
||||
import app.revanced.util.getTargetIndexOrThrow
|
||||
import app.revanced.util.getTargetIndexWithMethodReferenceNameOrThrow
|
||||
import app.revanced.util.getWideLiteralInstructionIndex
|
||||
import app.revanced.util.literalInstructionBooleanHook
|
||||
import app.revanced.util.alsoResolve
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow
|
||||
import app.revanced.util.injectLiteralInstructionBooleanCall
|
||||
import app.revanced.util.patch.BaseBytecodePatch
|
||||
import app.revanced.util.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
@ -99,7 +101,7 @@ object LayoutComponentsPatch : BaseBytecodePatch(
|
||||
PlayerOverlayChipFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val targetIndex =
|
||||
getWideLiteralInstructionIndex(SharedResourceIdPatch.PlayerOverlayChip) + 2
|
||||
indexOfFirstWideLiteralInstructionValueOrThrow(PlayerOverlayChip) + 2
|
||||
val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
|
||||
|
||||
addInstruction(
|
||||
@ -176,8 +178,10 @@ object LayoutComponentsPatch : BaseBytecodePatch(
|
||||
|
||||
if (SettingsPatch.upward0642) {
|
||||
TopBarMenuItemImageViewFingerprint.resultOrThrow().mutableMethod.apply {
|
||||
val constIndex = getWideLiteralInstructionIndex(TopBarMenuItemImageView)
|
||||
val targetIndex = getTargetIndexOrThrow(constIndex, Opcode.MOVE_RESULT_OBJECT)
|
||||
val constIndex =
|
||||
indexOfFirstWideLiteralInstructionValueOrThrow(TopBarMenuItemImageView)
|
||||
val targetIndex =
|
||||
indexOfFirstInstructionOrThrow(constIndex, Opcode.MOVE_RESULT_OBJECT)
|
||||
val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
|
||||
|
||||
addInstruction(
|
||||
@ -193,7 +197,7 @@ object LayoutComponentsPatch : BaseBytecodePatch(
|
||||
// region patch for hide sound search button
|
||||
|
||||
SoundSearchFingerprint.result?.let {
|
||||
SoundSearchFingerprint.literalInstructionBooleanHook(
|
||||
SoundSearchFingerprint.injectLiteralInstructionBooleanCall(
|
||||
45625491,
|
||||
"$GENERAL_CLASS_DESCRIPTOR->hideSoundSearchButton(Z)Z"
|
||||
)
|
||||
@ -227,8 +231,9 @@ object LayoutComponentsPatch : BaseBytecodePatch(
|
||||
|
||||
parentResult.mutableMethod.apply {
|
||||
val constIndex =
|
||||
getWideLiteralInstructionIndex(SharedResourceIdPatch.MusicTasteBuilderShelf)
|
||||
val targetIndex = getTargetIndexOrThrow(constIndex, Opcode.MOVE_RESULT_OBJECT)
|
||||
indexOfFirstWideLiteralInstructionValueOrThrow(MusicTasteBuilderShelf)
|
||||
val targetIndex =
|
||||
indexOfFirstInstructionOrThrow(constIndex, Opcode.MOVE_RESULT_OBJECT)
|
||||
val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
|
||||
|
||||
addInstruction(
|
||||
@ -263,14 +268,11 @@ object LayoutComponentsPatch : BaseBytecodePatch(
|
||||
|
||||
// region patch for hide voice search button
|
||||
|
||||
SearchBarFingerprint.resolve(
|
||||
context,
|
||||
SearchBarParentFingerprint.resultOrThrow().classDef
|
||||
)
|
||||
SearchBarFingerprint.resultOrThrow().let {
|
||||
SearchBarFingerprint.alsoResolve(
|
||||
context, SearchBarParentFingerprint
|
||||
).let {
|
||||
it.mutableMethod.apply {
|
||||
val setVisibilityIndex =
|
||||
getTargetIndexWithMethodReferenceNameOrThrow("setVisibility")
|
||||
val setVisibilityIndex = SearchBarFingerprint.indexOfVisibilityInstruction(this)
|
||||
val setVisibilityInstruction =
|
||||
getInstruction<FiveRegisterInstruction>(setVisibilityIndex)
|
||||
|
||||
|
@ -3,7 +3,7 @@ package app.revanced.patches.music.general.components.fingerprints
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
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.Opcode
|
||||
|
||||
@ -16,7 +16,7 @@ internal object HistoryMenuItemFingerprint : MethodFingerprint(
|
||||
Opcode.RETURN_VOID
|
||||
),
|
||||
customFingerprint = { methodDef, classDef ->
|
||||
methodDef.containsWideLiteralInstructionIndex(HistoryMenuItem)
|
||||
methodDef.containsWideLiteralInstructionValue(HistoryMenuItem)
|
||||
&& classDef.methods.count() == 5
|
||||
}
|
||||
)
|
||||
|
@ -4,7 +4,7 @@ import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.HistoryMenuItem
|
||||
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.Opcode
|
||||
|
||||
@ -17,7 +17,7 @@ internal object HistoryMenuItemOfflineTabFingerprint : MethodFingerprint(
|
||||
Opcode.RETURN_VOID
|
||||
),
|
||||
customFingerprint = { methodDef, _ ->
|
||||
methodDef.containsWideLiteralInstructionIndex(HistoryMenuItem)
|
||||
&& methodDef.containsWideLiteralInstructionIndex(OfflineSettingsMenuItem)
|
||||
methodDef.containsWideLiteralInstructionValue(HistoryMenuItem)
|
||||
&& methodDef.containsWideLiteralInstructionValue(OfflineSettingsMenuItem)
|
||||
}
|
||||
)
|
||||
|
@ -1,8 +1,22 @@
|
||||
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",
|
||||
reference = { "setVisibility" }
|
||||
)
|
||||
customFingerprint = { methodDef, _ ->
|
||||
indexOfVisibilityInstruction(methodDef) >= 0
|
||||
}
|
||||
) {
|
||||
fun indexOfVisibilityInstruction(methodDef: Method) =
|
||||
methodDef.indexOfFirstInstructionReversed {
|
||||
opcode == Opcode.INVOKE_VIRTUAL &&
|
||||
getReference<MethodReference>()?.name == "setVisibility"
|
||||
}
|
||||
}
|
@ -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.settings.CategoryType
|
||||
import app.revanced.patches.music.utils.settings.SettingsPatch
|
||||
import app.revanced.util.getStringInstructionIndex
|
||||
import app.revanced.util.getTargetIndexReversedOrThrow
|
||||
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
|
||||
import app.revanced.util.indexOfFirstStringInstructionOrThrow
|
||||
import app.revanced.util.patch.BaseBytecodePatch
|
||||
import app.revanced.util.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
@ -27,8 +27,9 @@ object OldStyleLibraryShelfPatch : BaseBytecodePatch(
|
||||
|
||||
BrowseIdFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val stringIndex = getStringInstructionIndex("FEmusic_offline")
|
||||
val targetIndex = getTargetIndexReversedOrThrow(stringIndex, Opcode.IGET_OBJECT)
|
||||
val stringIndex = indexOfFirstStringInstructionOrThrow("FEmusic_offline")
|
||||
val targetIndex =
|
||||
indexOfFirstInstructionReversedOrThrow(stringIndex, Opcode.IGET_OBJECT)
|
||||
val targetRegister = getInstruction<TwoRegisterInstruction>(targetIndex).registerA
|
||||
|
||||
addInstructions(
|
||||
|
@ -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.settings.CategoryType
|
||||
import app.revanced.patches.music.utils.settings.SettingsPatch
|
||||
import app.revanced.util.getStringInstructionIndex
|
||||
import app.revanced.util.getTargetIndexReversedOrThrow
|
||||
import app.revanced.util.getTargetIndexWithReferenceOrThrow
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.getWalkerMethod
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
|
||||
import app.revanced.util.indexOfFirstStringInstructionOrThrow
|
||||
import app.revanced.util.patch.BaseBytecodePatch
|
||||
import app.revanced.util.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
@ -41,13 +41,14 @@ object DislikeRedirectionPatch : BaseBytecodePatch(
|
||||
|
||||
PendingIntentReceiverFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val startIndex = getStringInstructionIndex("YTM Dislike")
|
||||
val startIndex = indexOfFirstStringInstructionOrThrow("YTM Dislike")
|
||||
val onClickRelayIndex =
|
||||
getTargetIndexReversedOrThrow(startIndex, Opcode.INVOKE_VIRTUAL)
|
||||
indexOfFirstInstructionReversedOrThrow(startIndex, Opcode.INVOKE_VIRTUAL)
|
||||
val onClickRelayMethod = getWalkerMethod(context, onClickRelayIndex)
|
||||
|
||||
onClickRelayMethod.apply {
|
||||
val onClickMethodIndex = getTargetIndexReversedOrThrow(Opcode.INVOKE_DIRECT)
|
||||
val onClickMethodIndex =
|
||||
indexOfFirstInstructionReversedOrThrow(Opcode.INVOKE_DIRECT)
|
||||
val onClickMethod = getWalkerMethod(context, onClickMethodIndex)
|
||||
|
||||
onClickMethod.apply {
|
||||
@ -70,7 +71,9 @@ object DislikeRedirectionPatch : BaseBytecodePatch(
|
||||
|
||||
DislikeButtonOnClickListenerFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val onClickIndex = getTargetIndexWithReferenceOrThrow(onClickReference.toString())
|
||||
val onClickIndex = indexOfFirstInstructionOrThrow {
|
||||
getReference<MethodReference>()?.toString() == onClickReference.toString()
|
||||
}
|
||||
injectCall(onClickIndex)
|
||||
}
|
||||
}
|
||||
@ -84,7 +87,7 @@ object DislikeRedirectionPatch : BaseBytecodePatch(
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
addInstructionsWithLabels(
|
||||
|
@ -2,7 +2,7 @@ package app.revanced.patches.music.general.redirection.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import app.revanced.util.containsWideLiteralInstructionIndex
|
||||
import app.revanced.util.containsWideLiteralInstructionValue
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
internal object DislikeButtonOnClickListenerFingerprint : MethodFingerprint(
|
||||
@ -10,7 +10,7 @@ internal object DislikeButtonOnClickListenerFingerprint : MethodFingerprint(
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = listOf("Landroid/view/View;"),
|
||||
customFingerprint = handler@{ methodDef, _ ->
|
||||
if (!methodDef.containsWideLiteralInstructionIndex(53465))
|
||||
if (!methodDef.containsWideLiteralInstructionValue(53465))
|
||||
return@handler false
|
||||
|
||||
methodDef.name == "onClick"
|
||||
|
@ -79,7 +79,7 @@ object CustomBrandingIconPatch : BaseResourcePatch(
|
||||
private val splashIconResourceGroups =
|
||||
largeDrawableDirectories.getResourceGroup(splashIconResourceFileNames)
|
||||
|
||||
private val AppIcon = stringPatchOption(
|
||||
val AppIcon = stringPatchOption(
|
||||
key = "AppIcon",
|
||||
default = DEFAULT_ICON,
|
||||
values = availableIcon,
|
||||
@ -198,7 +198,11 @@ object CustomBrandingIconPatch : BaseResourcePatch(
|
||||
if (oldSplashIconNotExists) {
|
||||
splashIconResourceGroups.let { resourceGroups ->
|
||||
resourceGroups.forEach {
|
||||
context.copyResources("$youtubeMusicIconResourcePath/splash", it, createDirectoryIfNotExist = true)
|
||||
context.copyResources(
|
||||
"$youtubeMusicIconResourcePath/splash",
|
||||
it,
|
||||
createDirectoryIfNotExist = true
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
||||
}
|
@ -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.PodCastConfigFingerprint
|
||||
import app.revanced.patches.music.utils.compatibility.Constants.COMPATIBLE_PACKAGE
|
||||
import app.revanced.util.getStartsWithStringInstructionIndex
|
||||
import app.revanced.util.getStringInstructionIndex
|
||||
import app.revanced.util.getReference
|
||||
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.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.OneRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
|
||||
@Suppress("unused")
|
||||
object BackgroundPlaybackPatch : BaseBytecodePatch(
|
||||
@ -51,26 +52,20 @@ object BackgroundPlaybackPatch : BaseBytecodePatch(
|
||||
// don't play music video
|
||||
MusicBrowserServiceFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val targetIndex =
|
||||
getStartsWithStringInstructionIndex("MBS: Return empty root for client: %s")
|
||||
|
||||
for (index in targetIndex downTo 0) {
|
||||
if (getInstruction(index).opcode != Opcode.INVOKE_VIRTUAL) continue
|
||||
|
||||
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
|
||||
val stringIndex = MusicBrowserServiceFingerprint.indexOfMBSInstruction(this)
|
||||
val targetIndex = indexOfFirstInstructionReversedOrThrow(stringIndex) {
|
||||
val reference = getReference<MethodReference>()
|
||||
opcode == Opcode.INVOKE_VIRTUAL &&
|
||||
reference?.returnType == "Z" &&
|
||||
reference.parameterTypes.size == 0
|
||||
}
|
||||
|
||||
getWalkerMethod(context, targetIndex).addInstructions(
|
||||
0, """
|
||||
const/4 v0, 0x1
|
||||
return v0
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -97,7 +92,8 @@ object BackgroundPlaybackPatch : BaseBytecodePatch(
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
addInstruction(
|
||||
|
@ -2,8 +2,13 @@ package app.revanced.patches.music.misc.backgroundplayback.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
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.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.Method
|
||||
import com.android.tools.smali.dexlib2.iface.reference.StringReference
|
||||
|
||||
internal object MusicBrowserServiceFingerprint : MethodFingerprint(
|
||||
returnType = "L",
|
||||
@ -13,6 +18,12 @@ internal object MusicBrowserServiceFingerprint : MethodFingerprint(
|
||||
if (!methodDef.definingClass.endsWith("/MusicBrowserService;"))
|
||||
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
|
||||
}
|
||||
}
|
@ -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.SettingsPatch
|
||||
import app.revanced.patches.shared.litho.LithoFilterPatch
|
||||
import app.revanced.util.getTargetIndexOrThrow
|
||||
import app.revanced.util.getWideLiteralInstructionIndex
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow
|
||||
import app.revanced.util.patch.BaseBytecodePatch
|
||||
import app.revanced.util.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
@ -40,8 +40,8 @@ object ShareSheetPatch : BaseBytecodePatch(
|
||||
override fun execute(context: BytecodeContext) {
|
||||
|
||||
BottomSheetRecyclerViewFingerprint.resultOrThrow().mutableMethod.apply {
|
||||
val constIndex = getWideLiteralInstructionIndex(BottomSheetRecyclerView)
|
||||
val targetIndex = getTargetIndexOrThrow(constIndex, Opcode.CHECK_CAST)
|
||||
val constIndex = indexOfFirstWideLiteralInstructionValueOrThrow(BottomSheetRecyclerView)
|
||||
val targetIndex = indexOfFirstInstructionOrThrow(constIndex, Opcode.CHECK_CAST)
|
||||
val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
|
||||
|
||||
addInstruction(
|
||||
|
@ -1,25 +1,41 @@
|
||||
package app.revanced.patches.music.misc.splash
|
||||
|
||||
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.annotation.CompatiblePackage
|
||||
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.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.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(
|
||||
name = "Disable Cairo splash animation",
|
||||
description = "Adds an option to disable Cairo splash animation.",
|
||||
dependencies = [SettingsPatch::class],
|
||||
dependencies = [
|
||||
SettingsPatch::class,
|
||||
SharedResourceIdPatch::class
|
||||
],
|
||||
compatiblePackages = [
|
||||
CompatiblePackage(
|
||||
"com.google.android.apps.youtube.music",
|
||||
[
|
||||
"7.06.54",
|
||||
"7.17.51",
|
||||
"7.16.53",
|
||||
]
|
||||
)
|
||||
]
|
||||
@ -28,22 +44,57 @@ import app.revanced.util.literalInstructionBooleanHook
|
||||
object CairoSplashAnimationPatch : BytecodePatch(
|
||||
setOf(CairoSplashAnimationConfigFingerprint)
|
||||
) {
|
||||
private const val INTEGRATIONS_METHOD_DESCRIPTOR =
|
||||
"$MISC_PATH/CairoSplashAnimationPatch;->disableCairoSplashAnimation(Z)Z"
|
||||
|
||||
override fun execute(context: BytecodeContext) {
|
||||
|
||||
CairoSplashAnimationConfigFingerprint.result?.let {
|
||||
CairoSplashAnimationConfigFingerprint.literalInstructionBooleanHook(
|
||||
if (!SettingsPatch.upward0706) {
|
||||
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,
|
||||
"$MISC_PATH/CairoSplashAnimationPatch;->disableCairoSplashAnimation(Z)Z"
|
||||
)
|
||||
|
||||
SettingsPatch.addSwitchPreference(
|
||||
CategoryType.MISC,
|
||||
"revanced_disable_cairo_splash_animation",
|
||||
"false"
|
||||
INTEGRATIONS_METHOD_DESCRIPTOR
|
||||
)
|
||||
} 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"
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,25 @@
|
||||
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+
|
||||
*/
|
||||
internal object CairoSplashAnimationConfigFingerprint : LiteralValueFingerprint(
|
||||
literalSupplier = { 45635386 }
|
||||
internal object CairoSplashAnimationConfigFingerprint : MethodFingerprint(
|
||||
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
|
||||
}
|
||||
}
|
||||
)
|
@ -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.resourceid.SharedResourceIdPatch
|
||||
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.SettingsPatch
|
||||
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.indexOfFirstWideLiteralInstructionValueOrThrow
|
||||
import app.revanced.util.patch.BaseBytecodePatch
|
||||
import app.revanced.util.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
@ -50,7 +49,7 @@ object NavigationBarComponentsPatch : BaseBytecodePatch(
|
||||
* Enable black navigation bar
|
||||
*/
|
||||
TabLayoutFingerprint.resultOrThrow().mutableMethod.apply {
|
||||
val constIndex = getWideLiteralInstructionIndex(ColorGrey)
|
||||
val constIndex = indexOfFirstWideLiteralInstructionValueOrThrow(ColorGrey)
|
||||
val insertIndex = indexOfFirstInstructionOrThrow(constIndex) {
|
||||
opcode == Opcode.INVOKE_VIRTUAL
|
||||
&& getReference<MethodReference>()?.name == "setBackgroundColor"
|
||||
@ -70,8 +69,9 @@ object NavigationBarComponentsPatch : BaseBytecodePatch(
|
||||
*/
|
||||
TabLayoutTextFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val constIndex = getWideLiteralInstructionIndex(SharedResourceIdPatch.Text1)
|
||||
val targetIndex = getTargetIndexOrThrow(constIndex, Opcode.CHECK_CAST)
|
||||
val constIndex =
|
||||
indexOfFirstWideLiteralInstructionValueOrThrow(Text1)
|
||||
val targetIndex = indexOfFirstInstructionOrThrow(constIndex, Opcode.CHECK_CAST)
|
||||
val targetParameter = getInstruction<ReferenceInstruction>(targetIndex).reference
|
||||
val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
|
||||
|
||||
@ -105,9 +105,12 @@ object NavigationBarComponentsPatch : BaseBytecodePatch(
|
||||
it.mutableMethod.apply {
|
||||
val enumIndex = it.scanResult.patternScanResult!!.startIndex + 3
|
||||
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
|
||||
|
||||
addInstruction(
|
||||
|
@ -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.smali.ExternalLabel
|
||||
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.HandleSignInEventFingerprint
|
||||
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.shared.litho.LithoFilterPatch
|
||||
import app.revanced.util.REGISTER_TEMPLATE_REPLACEMENT
|
||||
import app.revanced.util.alsoResolve
|
||||
import app.revanced.util.findMethodOrThrow
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.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.getWideLiteralInstructionIndex
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import app.revanced.util.literalInstructionBooleanHook
|
||||
import app.revanced.util.literalInstructionViewHook
|
||||
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
|
||||
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.resultOrThrow
|
||||
import app.revanced.util.transformFields
|
||||
@ -105,6 +106,7 @@ object PlayerComponentsPatch : BaseBytecodePatch(
|
||||
compatiblePackages = COMPATIBLE_PACKAGE,
|
||||
fingerprints = setOf(
|
||||
AudioVideoSwitchToggleFingerprint,
|
||||
EngagementPanelHeightParentFingerprint,
|
||||
HandleSearchRenderedFingerprint,
|
||||
InteractionLoggingEnumFingerprint,
|
||||
MinimizedPlayerFingerprint,
|
||||
@ -145,8 +147,8 @@ object PlayerComponentsPatch : BaseBytecodePatch(
|
||||
PlayerViewPager to "disablePlayerGesture"
|
||||
).forEach { (literal, methodName) ->
|
||||
val viewPagerReference = playerViewPagerConstructorMethod.let {
|
||||
val constIndex = it.getWideLiteralInstructionIndex(literal)
|
||||
val targetIndex = it.getTargetIndexOrThrow(constIndex, Opcode.IPUT_OBJECT)
|
||||
val constIndex = it.indexOfFirstWideLiteralInstructionValueOrThrow(literal)
|
||||
val targetIndex = it.indexOfFirstInstructionOrThrow(constIndex, Opcode.IPUT_OBJECT)
|
||||
|
||||
it.getInstruction<ReferenceInstruction>(targetIndex).reference.toString()
|
||||
}
|
||||
@ -156,7 +158,8 @@ object PlayerComponentsPatch : BaseBytecodePatch(
|
||||
&& getReference<FieldReference>()?.toString() == viewPagerReference
|
||||
}
|
||||
val insertRegister = getInstruction<TwoRegisterInstruction>(insertIndex).registerA
|
||||
val jumpIndex = getTargetIndex(insertIndex, Opcode.INVOKE_VIRTUAL) + 1
|
||||
val jumpIndex =
|
||||
indexOfFirstInstructionOrThrow(insertIndex, Opcode.INVOKE_VIRTUAL) + 1
|
||||
|
||||
addInstructionsWithLabels(
|
||||
insertIndex, """
|
||||
@ -198,8 +201,8 @@ object PlayerComponentsPatch : BaseBytecodePatch(
|
||||
|
||||
val relativeIndex = it.scanResult.patternScanResult!!.endIndex + 1
|
||||
val invokeVirtualIndex =
|
||||
getTargetIndexOrThrow(relativeIndex, Opcode.INVOKE_VIRTUAL)
|
||||
val iGetIndex = getTargetIndexOrThrow(relativeIndex, Opcode.IGET)
|
||||
indexOfFirstInstructionOrThrow(relativeIndex, Opcode.INVOKE_VIRTUAL)
|
||||
val iGetIndex = indexOfFirstInstructionOrThrow(relativeIndex, Opcode.IGET)
|
||||
|
||||
colorMathPlayerInvokeVirtualReference =
|
||||
getInstruction<ReferenceInstruction>(invokeVirtualIndex).reference
|
||||
@ -207,11 +210,11 @@ object PlayerComponentsPatch : BaseBytecodePatch(
|
||||
getInstruction<ReferenceInstruction>(iGetIndex).reference
|
||||
|
||||
// black player background
|
||||
val invokeDirectIndex = getTargetIndexOrThrow(Opcode.INVOKE_DIRECT)
|
||||
val invokeDirectIndex = indexOfFirstInstructionOrThrow(Opcode.INVOKE_DIRECT)
|
||||
val targetMethod = getWalkerMethod(context, invokeDirectIndex)
|
||||
|
||||
targetMethod.apply {
|
||||
val insertIndex = getTargetIndexOrThrow(0, Opcode.IF_NE)
|
||||
val insertIndex = indexOfFirstInstructionOrThrow(Opcode.IF_NE)
|
||||
|
||||
addInstructions(
|
||||
insertIndex, """
|
||||
@ -225,8 +228,8 @@ object PlayerComponentsPatch : BaseBytecodePatch(
|
||||
}
|
||||
|
||||
parentResult.mutableMethod.apply {
|
||||
val colorGreyIndex = getWideLiteralInstructionIndex(ColorGrey)
|
||||
val iPutIndex = getTargetIndexOrThrow(colorGreyIndex, Opcode.IPUT)
|
||||
val colorGreyIndex = indexOfFirstWideLiteralInstructionValueOrThrow(ColorGrey)
|
||||
val iPutIndex = indexOfFirstInstructionOrThrow(colorGreyIndex, Opcode.IPUT)
|
||||
|
||||
colorMathPlayerIPutReference =
|
||||
getInstruction<ReferenceInstruction>(iPutIndex).reference
|
||||
@ -240,7 +243,8 @@ object PlayerComponentsPatch : BaseBytecodePatch(
|
||||
mutableMethod.apply {
|
||||
val freeRegister = implementation!!.registerCount - parameters.size - 3
|
||||
|
||||
val invokeDirectIndex = getTargetIndexReversedOrThrow(Opcode.INVOKE_DIRECT)
|
||||
val invokeDirectIndex =
|
||||
indexOfFirstInstructionReversedOrThrow(Opcode.INVOKE_DIRECT)
|
||||
val invokeDirectReference =
|
||||
getInstruction<ReferenceInstruction>(invokeDirectIndex).reference
|
||||
|
||||
@ -401,9 +405,9 @@ object PlayerComponentsPatch : BaseBytecodePatch(
|
||||
reversed: Boolean
|
||||
): Reference {
|
||||
val targetIndex = if (reversed)
|
||||
getTargetIndexReversedOrThrow(swipeToDismissWidgetIndex, opcode)
|
||||
indexOfFirstInstructionReversedOrThrow(swipeToDismissWidgetIndex, opcode)
|
||||
else
|
||||
getTargetIndexOrThrow(swipeToDismissWidgetIndex, opcode)
|
||||
indexOfFirstInstructionOrThrow(swipeToDismissWidgetIndex, opcode)
|
||||
|
||||
return getInstruction<ReferenceInstruction>(targetIndex).reference
|
||||
}
|
||||
@ -411,7 +415,7 @@ object PlayerComponentsPatch : BaseBytecodePatch(
|
||||
if (!SettingsPatch.upward0642) {
|
||||
SwipeToCloseFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val insertIndex = implementation!!.instructions.size - 1
|
||||
val insertIndex = implementation!!.instructions.lastIndex
|
||||
val targetRegister =
|
||||
getInstruction<OneRegisterInstruction>(insertIndex).registerA
|
||||
|
||||
@ -430,8 +434,9 @@ object PlayerComponentsPatch : BaseBytecodePatch(
|
||||
InteractionLoggingEnumFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val stringIndex =
|
||||
getStringInstructionIndex("INTERACTION_LOGGING_GESTURE_TYPE_SWIPE")
|
||||
val sPutObjectIndex = getTargetIndexOrThrow(stringIndex, Opcode.SPUT_OBJECT)
|
||||
indexOfFirstStringInstructionOrThrow("INTERACTION_LOGGING_GESTURE_TYPE_SWIPE")
|
||||
val sPutObjectIndex =
|
||||
indexOfFirstInstructionOrThrow(stringIndex, Opcode.SPUT_OBJECT)
|
||||
|
||||
swipeToDismissSGetObjectReference =
|
||||
getInstruction<ReferenceInstruction>(sPutObjectIndex).reference
|
||||
@ -440,7 +445,8 @@ object PlayerComponentsPatch : BaseBytecodePatch(
|
||||
|
||||
MusicActivityWidgetFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
swipeToDismissWidgetIndex = getWideLiteralInstructionIndex(79500)
|
||||
swipeToDismissWidgetIndex =
|
||||
indexOfFirstWideLiteralInstructionValueOrThrow(79500)
|
||||
|
||||
swipeToDismissIGetObjectReference =
|
||||
getSwipeToDismissReference(Opcode.IGET_OBJECT, true)
|
||||
@ -468,8 +474,9 @@ object PlayerComponentsPatch : BaseBytecodePatch(
|
||||
it.getWalkerMethod(context, it.scanResult.patternScanResult!!.startIndex)
|
||||
|
||||
dismissBehaviorMethod.apply {
|
||||
val insertIndex =
|
||||
getTargetIndexWithFieldReferenceTypeOrThrow("Ljava/util/concurrent/atomic/AtomicBoolean;")
|
||||
val insertIndex = indexOfFirstInstructionOrThrow {
|
||||
getReference<FieldReference>()?.type == "Ljava/util/concurrent/atomic/AtomicBoolean;"
|
||||
}
|
||||
val primaryRegister =
|
||||
getInstruction<TwoRegisterInstruction>(insertIndex).registerB
|
||||
val secondaryRegister = primaryRegister + 1
|
||||
@ -528,15 +535,12 @@ object PlayerComponentsPatch : BaseBytecodePatch(
|
||||
it.mutableClass.methods.find { method ->
|
||||
method.parameters == listOf("Landroid/view/View;", "I")
|
||||
}?.apply {
|
||||
val bottomSheetBehaviorIndex =
|
||||
implementation!!.instructions.indexOfFirst { instruction ->
|
||||
instruction.opcode == Opcode.INVOKE_VIRTUAL
|
||||
&& instruction.getReference<MethodReference>()?.definingClass == "Lcom/google/android/material/bottomsheet/BottomSheetBehavior;"
|
||||
&& instruction.getReference<MethodReference>()?.parameterTypes?.first() == "Z"
|
||||
}
|
||||
if (bottomSheetBehaviorIndex < 0)
|
||||
throw PatchException("Could not find bottomSheetBehaviorIndex")
|
||||
|
||||
val bottomSheetBehaviorIndex = indexOfFirstInstructionOrThrow {
|
||||
val reference = getReference<MethodReference>()
|
||||
opcode == Opcode.INVOKE_VIRTUAL
|
||||
&& reference?.definingClass == "Lcom/google/android/material/bottomsheet/BottomSheetBehavior;"
|
||||
&& reference.parameterTypes.first() == "Z"
|
||||
}
|
||||
val freeRegister =
|
||||
getInstruction<FiveRegisterInstruction>(bottomSheetBehaviorIndex).registerD
|
||||
|
||||
@ -592,7 +596,7 @@ object PlayerComponentsPatch : BaseBytecodePatch(
|
||||
|
||||
SwitchToggleColorFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val invokeDirectIndex = getTargetIndexOrThrow(Opcode.INVOKE_DIRECT)
|
||||
val invokeDirectIndex = indexOfFirstInstructionOrThrow(Opcode.INVOKE_DIRECT)
|
||||
val walkerMethod = getWalkerMethod(context, invokeDirectIndex)
|
||||
|
||||
walkerMethod.addInstructions(
|
||||
@ -624,8 +628,8 @@ object PlayerComponentsPatch : BaseBytecodePatch(
|
||||
// region patch for hide audio video switch toggle
|
||||
|
||||
AudioVideoSwitchToggleFingerprint.resultOrThrow().mutableMethod.apply {
|
||||
val constIndex = getWideLiteralInstructionIndex(AudioVideoSwitchToggle)
|
||||
val viewIndex = getTargetIndexOrThrow(constIndex, Opcode.MOVE_RESULT_OBJECT)
|
||||
val constIndex = indexOfFirstWideLiteralInstructionValueOrThrow(AudioVideoSwitchToggle)
|
||||
val viewIndex = indexOfFirstInstructionOrThrow(constIndex, Opcode.MOVE_RESULT_OBJECT)
|
||||
val viewRegister = getInstruction<OneRegisterInstruction>(viewIndex).registerA
|
||||
|
||||
addInstruction(
|
||||
@ -667,7 +671,7 @@ object PlayerComponentsPatch : BaseBytecodePatch(
|
||||
DarkBackground,
|
||||
TapBloomView
|
||||
).forEach { literal ->
|
||||
QuickSeekOverlayFingerprint.literalInstructionViewHook(
|
||||
QuickSeekOverlayFingerprint.injectLiteralInstructionViewCall(
|
||||
literal,
|
||||
smaliInstruction
|
||||
)
|
||||
@ -742,17 +746,20 @@ object PlayerComponentsPatch : BaseBytecodePatch(
|
||||
it.mutableMethod.apply {
|
||||
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 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 =
|
||||
getInstruction<ReferenceInstruction>(iGetObjectIndex).reference
|
||||
val invokeInterfaceReference =
|
||||
getInstruction<ReferenceInstruction>(iGetObjectIndex + 1).reference
|
||||
getInstruction<ReferenceInstruction>(invokeInterfaceIndex).reference
|
||||
val checkCastReference =
|
||||
getInstruction<ReferenceInstruction>(checkCastIndex).reference
|
||||
val getOrdinalClassReference =
|
||||
@ -771,7 +778,7 @@ object PlayerComponentsPatch : BaseBytecodePatch(
|
||||
"""
|
||||
|
||||
rememberShuffleStateShuffleStateLabel += if (getInstruction(checkCastIndex + 1).opcode == Opcode.INVOKE_VIRTUAL) {
|
||||
// YouTube Music 7.16.52+
|
||||
// YouTube Music 7.16.53+
|
||||
"""
|
||||
invoke-virtual {v1}, $getOrdinalClassReference
|
||||
move-result-object v1
|
||||
@ -887,12 +894,84 @@ object PlayerComponentsPatch : BaseBytecodePatch(
|
||||
|
||||
// region patch for restore old comments popup panels
|
||||
|
||||
OldEngagementPanelFingerprint.result?.let {
|
||||
OldEngagementPanelFingerprint.literalInstructionBooleanHook(
|
||||
var restoreOldCommentsPopupPanel = false
|
||||
|
||||
if (SettingsPatch.upward0627 && !SettingsPatch.upward0718) {
|
||||
OldEngagementPanelFingerprint.injectLiteralInstructionBooleanCall(
|
||||
45427672,
|
||||
"$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(
|
||||
CategoryType.PLAYER,
|
||||
"revanced_restore_old_comments_popup_panels",
|
||||
@ -905,7 +984,7 @@ object PlayerComponentsPatch : BaseBytecodePatch(
|
||||
// region patch for restore old player background
|
||||
|
||||
OldPlayerBackgroundFingerprint.result?.let {
|
||||
OldPlayerBackgroundFingerprint.literalInstructionBooleanHook(
|
||||
OldPlayerBackgroundFingerprint.injectLiteralInstructionBooleanCall(
|
||||
45415319,
|
||||
"$PLAYER_CLASS_DESCRIPTOR->restoreOldPlayerBackground(Z)Z"
|
||||
)
|
||||
@ -922,7 +1001,7 @@ object PlayerComponentsPatch : BaseBytecodePatch(
|
||||
// region patch for restore old player layout
|
||||
|
||||
OldPlayerLayoutFingerprint.result?.let {
|
||||
OldPlayerLayoutFingerprint.literalInstructionBooleanHook(
|
||||
OldPlayerLayoutFingerprint.injectLiteralInstructionBooleanCall(
|
||||
45399578,
|
||||
"$PLAYER_CLASS_DESCRIPTOR->restoreOldPlayerLayout(Z)Z"
|
||||
)
|
||||
@ -943,11 +1022,14 @@ object PlayerComponentsPatch : BaseBytecodePatch(
|
||||
viewId: Long
|
||||
) {
|
||||
val miniPlayerPlayPauseReplayButtonIndex =
|
||||
getWideLiteralInstructionIndex(MiniPlayerPlayPauseReplayButton)
|
||||
indexOfFirstWideLiteralInstructionValueOrThrow(MiniPlayerPlayPauseReplayButton)
|
||||
val miniPlayerPlayPauseReplayButtonRegister =
|
||||
getInstruction<OneRegisterInstruction>(miniPlayerPlayPauseReplayButtonIndex).registerA
|
||||
val findViewByIdIndex =
|
||||
getTargetIndexOrThrow(miniPlayerPlayPauseReplayButtonIndex, Opcode.INVOKE_VIRTUAL)
|
||||
indexOfFirstInstructionOrThrow(
|
||||
miniPlayerPlayPauseReplayButtonIndex,
|
||||
Opcode.INVOKE_VIRTUAL
|
||||
)
|
||||
val parentViewRegister =
|
||||
getInstruction<FiveRegisterInstruction>(findViewByIdIndex).registerC
|
||||
|
||||
@ -966,11 +1048,14 @@ object PlayerComponentsPatch : BaseBytecodePatch(
|
||||
viewId: Long
|
||||
) {
|
||||
val miniPlayerPlayPauseReplayButtonIndex =
|
||||
getWideLiteralInstructionIndex(MiniPlayerPlayPauseReplayButton)
|
||||
indexOfFirstWideLiteralInstructionValueOrThrow(MiniPlayerPlayPauseReplayButton)
|
||||
val constRegister =
|
||||
getInstruction<OneRegisterInstruction>(miniPlayerPlayPauseReplayButtonIndex).registerA
|
||||
val findViewByIdIndex =
|
||||
getTargetIndexOrThrow(miniPlayerPlayPauseReplayButtonIndex, Opcode.INVOKE_VIRTUAL)
|
||||
indexOfFirstInstructionOrThrow(
|
||||
miniPlayerPlayPauseReplayButtonIndex,
|
||||
Opcode.INVOKE_VIRTUAL
|
||||
)
|
||||
val findViewByIdRegister =
|
||||
getInstruction<FiveRegisterInstruction>(findViewByIdIndex).registerC
|
||||
|
||||
@ -986,9 +1071,12 @@ object PlayerComponentsPatch : BaseBytecodePatch(
|
||||
|
||||
private fun MutableMethod.setViewArray() {
|
||||
val miniPlayerPlayPauseReplayButtonIndex =
|
||||
getWideLiteralInstructionIndex(MiniPlayerPlayPauseReplayButton)
|
||||
indexOfFirstWideLiteralInstructionValueOrThrow(MiniPlayerPlayPauseReplayButton)
|
||||
val invokeStaticIndex =
|
||||
getTargetIndexOrThrow(miniPlayerPlayPauseReplayButtonIndex, Opcode.INVOKE_STATIC)
|
||||
indexOfFirstInstructionOrThrow(
|
||||
miniPlayerPlayPauseReplayButtonIndex,
|
||||
Opcode.INVOKE_STATIC
|
||||
)
|
||||
val viewArrayRegister = getInstruction<FiveRegisterInstruction>(invokeStaticIndex).registerC
|
||||
|
||||
addInstructions(
|
||||
@ -1005,21 +1093,18 @@ object PlayerComponentsPatch : BaseBytecodePatch(
|
||||
methodName: String,
|
||||
fieldName: String
|
||||
) {
|
||||
val startIndex = getStringInstructionIndex(intentString)
|
||||
val onClickIndex = getTargetIndexReversedOrThrow(startIndex, Opcode.INVOKE_VIRTUAL)
|
||||
val startIndex = indexOfFirstStringInstructionOrThrow(intentString)
|
||||
val onClickIndex = indexOfFirstInstructionReversedOrThrow(startIndex, Opcode.INVOKE_VIRTUAL)
|
||||
val onClickReference = getInstruction<ReferenceInstruction>(onClickIndex).reference
|
||||
val onClickReferenceDefiningClass = (onClickReference as MethodReference).definingClass
|
||||
|
||||
val onClickClass =
|
||||
context.findClass(onClickReferenceDefiningClass)!!.mutableClass
|
||||
|
||||
onClickClass.methods.find { method -> method.name == "<init>" }
|
||||
?.apply {
|
||||
context.findMethodOrThrow(onClickReferenceDefiningClass)
|
||||
.apply {
|
||||
addInstruction(
|
||||
implementation!!.instructions.size - 1,
|
||||
implementation!!.instructions.lastIndex,
|
||||
"sput-object p0, $PLAYER_CLASS_DESCRIPTOR->$fieldName:$onClickReferenceDefiningClass"
|
||||
)
|
||||
} ?: throw PatchException("onClickClass not found!")
|
||||
}
|
||||
|
||||
PlayerPatchConstructorFingerprint.resultOrThrow().let {
|
||||
val mutableClass = it.mutableClass
|
||||
|
@ -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
|
||||
}
|
||||
)
|
@ -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
|
||||
}
|
||||
)
|
@ -3,13 +3,13 @@ package app.revanced.patches.music.player.components.fingerprints
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.ColorGrey
|
||||
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.MiniPlayerPlayPauseReplayButton
|
||||
import app.revanced.util.containsWideLiteralInstructionIndex
|
||||
import app.revanced.util.containsWideLiteralInstructionValue
|
||||
|
||||
internal object MiniPlayerConstructorFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
strings = listOf("sharedToggleMenuItemMutations"),
|
||||
customFingerprint = { methodDef, _ ->
|
||||
methodDef.containsWideLiteralInstructionIndex(ColorGrey)
|
||||
&& methodDef.containsWideLiteralInstructionIndex(MiniPlayerPlayPauseReplayButton)
|
||||
methodDef.containsWideLiteralInstructionValue(ColorGrey)
|
||||
&& methodDef.containsWideLiteralInstructionValue(MiniPlayerPlayPauseReplayButton)
|
||||
}
|
||||
)
|
@ -1,16 +1,42 @@
|
||||
package app.revanced.patches.music.player.components.fingerprints
|
||||
|
||||
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.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.iface.Method
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
|
||||
internal object MppWatchWhileLayoutFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
opcodes = listOf(Opcode.NEW_ARRAY),
|
||||
customFingerprint = { methodDef, _ ->
|
||||
methodDef.definingClass.endsWith("/MppWatchWhileLayout;")
|
||||
&& methodDef.name == "onFinishInflate"
|
||||
&& methodDef.containsWideLiteralInstructionIndex(MiniPlayerPlayPauseReplayButton)
|
||||
customFingerprint = custom@{ methodDef, _ ->
|
||||
if (!methodDef.definingClass.endsWith("/MppWatchWhileLayout;")) {
|
||||
return@custom false
|
||||
}
|
||||
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;"
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
package app.revanced.patches.music.player.components.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import app.revanced.util.containsWideLiteralInstructionIndex
|
||||
import app.revanced.util.containsWideLiteralInstructionValue
|
||||
|
||||
internal object MusicActivityWidgetFingerprint : MethodFingerprint(
|
||||
customFingerprint = handler@{ methodDef, _ ->
|
||||
if (!methodDef.definingClass.endsWith("/MusicActivity;"))
|
||||
return@handler false
|
||||
|
||||
methodDef.containsWideLiteralInstructionIndex(79500)
|
||||
methodDef.containsWideLiteralInstructionValue(79500)
|
||||
}
|
||||
)
|
||||
|
@ -4,14 +4,14 @@ import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.MiniPlayerViewPager
|
||||
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
|
||||
|
||||
internal object PlayerViewPagerConstructorFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
|
||||
customFingerprint = { methodDef, _ ->
|
||||
methodDef.containsWideLiteralInstructionIndex(MiniPlayerViewPager)
|
||||
&& methodDef.containsWideLiteralInstructionIndex(PlayerViewPager)
|
||||
methodDef.containsWideLiteralInstructionValue(MiniPlayerViewPager)
|
||||
&& methodDef.containsWideLiteralInstructionValue(PlayerViewPager)
|
||||
},
|
||||
)
|
@ -3,13 +3,13 @@ package app.revanced.patches.music.player.components.fingerprints
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.DarkBackground
|
||||
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.TapBloomView
|
||||
import app.revanced.util.containsWideLiteralInstructionIndex
|
||||
import app.revanced.util.containsWideLiteralInstructionValue
|
||||
|
||||
internal object QuickSeekOverlayFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
parameters = emptyList(),
|
||||
customFingerprint = { methodDef, _ ->
|
||||
methodDef.containsWideLiteralInstructionIndex(DarkBackground)
|
||||
&& methodDef.containsWideLiteralInstructionIndex(TapBloomView)
|
||||
methodDef.containsWideLiteralInstructionValue(DarkBackground)
|
||||
&& methodDef.containsWideLiteralInstructionValue(TapBloomView)
|
||||
},
|
||||
)
|
@ -4,7 +4,8 @@ import app.revanced.patcher.extensions.or
|
||||
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.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.indexOfFirstInstruction
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
@ -19,7 +20,7 @@ internal object ShuffleClassReferenceFingerprint : MethodFingerprint(
|
||||
parameters = emptyList(),
|
||||
strings = listOf("Unknown shuffle mode"),
|
||||
customFingerprint = { methodDef, _ ->
|
||||
methodDef.containsWideLiteralInstructionIndex(45468) &&
|
||||
methodDef.containsWideLiteralInstructionValue(YtFillArrowShuffle) &&
|
||||
indexOfOrdinalInstruction(methodDef) >= 0 &&
|
||||
indexOfImageViewInstruction(methodDef) >= 0
|
||||
}
|
||||
|
@ -7,12 +7,11 @@ object Constants {
|
||||
Patch.CompatiblePackage(
|
||||
"com.google.android.apps.youtube.music",
|
||||
setOf(
|
||||
"6.29.58", // This is the latest version that supports the 'Restore old player layout' setting.
|
||||
"6.33.52", // This is the latest version with the legacy code of YouTube Music.
|
||||
"6.20.51", // This is the latest version that supports Android 5.0
|
||||
"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.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.17.51", // This is the latest version supported by the RVX patch.
|
||||
"7.16.53", // This is the latest version supported by the RVX patch.
|
||||
)
|
||||
)
|
||||
)
|
||||
|
@ -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.
|
||||
}
|
||||
}
|
@ -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" }
|
||||
)
|
@ -22,7 +22,7 @@ object FileProviderPatch : BytecodePatch(
|
||||
* 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.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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 {
|
||||
addInstructionsWithLabels(
|
||||
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"
|
||||
invoke-static {p1, v0}, Ljava/util/Objects;->equals(Ljava/lang/Object;Ljava/lang/Object;)Z
|
||||
move-result v0
|
||||
if-eqz v0, :ignore
|
||||
if-nez v0, :fix
|
||||
goto :ignore
|
||||
:fix
|
||||
const-string p1, "$musicPackageName.fileprovider"
|
||||
""", ExternalLabel("ignore", getInstruction(0))
|
||||
)
|
||||
|
@ -1,16 +1,11 @@
|
||||
package app.revanced.patches.music.utils.fix.header
|
||||
|
||||
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.annotation.Patch
|
||||
import app.revanced.patches.music.layout.header.ChangeHeaderPatch
|
||||
import app.revanced.patches.music.utils.fix.header.fingerprints.HeaderSwitchConfigFingerprint
|
||||
import app.revanced.util.getTargetIndexOrThrow
|
||||
import app.revanced.util.getWideLiteralInstructionIndex
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import app.revanced.util.injectLiteralInstructionBooleanCall
|
||||
|
||||
@Patch(
|
||||
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.
|
||||
*/
|
||||
HeaderSwitchConfigFingerprint.result?.let {
|
||||
it.mutableMethod.apply {
|
||||
val targetIndex =
|
||||
getTargetIndexOrThrow(
|
||||
getWideLiteralInstructionIndex(45617851),
|
||||
Opcode.MOVE_RESULT
|
||||
)
|
||||
val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
|
||||
|
||||
addInstruction(
|
||||
targetIndex + 1,
|
||||
"const/4 v$targetRegister, 0x0"
|
||||
)
|
||||
}
|
||||
HeaderSwitchConfigFingerprint.injectLiteralInstructionBooleanCall(
|
||||
45617851,
|
||||
"0x0"
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patches.music.utils.flyoutmenu.fingerprints.PlaybackRateBottomSheetClassFingerprint
|
||||
import app.revanced.patches.music.utils.integrations.Constants.INTEGRATIONS_PATH
|
||||
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch
|
||||
import app.revanced.util.addFieldAndInstructions
|
||||
import app.revanced.util.addStaticFieldToIntegration
|
||||
import app.revanced.util.resultOrThrow
|
||||
|
||||
@Patch(
|
||||
@ -31,15 +31,12 @@ object FlyoutMenuHookPatch : BytecodePatch(
|
||||
return-void
|
||||
"""
|
||||
|
||||
context.findClass(
|
||||
INTEGRATIONS_VIDEO_UTILS_CLASS_DESCRIPTOR
|
||||
)!!.mutableClass.addFieldAndInstructions(
|
||||
context,
|
||||
context.addStaticFieldToIntegration(
|
||||
INTEGRATIONS_VIDEO_UTILS_CLASS_DESCRIPTOR,
|
||||
"showPlaybackSpeedFlyoutMenu",
|
||||
"playbackRateBottomSheetClass",
|
||||
definingClass,
|
||||
smaliInstructions,
|
||||
true
|
||||
smaliInstructions
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -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.COLOR
|
||||
import app.revanced.patches.shared.mapping.ResourceType.DIMEN
|
||||
import app.revanced.patches.shared.mapping.ResourceType.DRAWABLE
|
||||
import app.revanced.patches.shared.mapping.ResourceType.ID
|
||||
import app.revanced.patches.shared.mapping.ResourceType.LAYOUT
|
||||
import app.revanced.patches.shared.mapping.ResourceType.STRING
|
||||
@ -32,6 +33,7 @@ object SharedResourceIdPatch : ResourcePatch() {
|
||||
var InterstitialsContainer = -1L
|
||||
var IsTablet = -1L
|
||||
var LikeDislikeContainer = -1L
|
||||
var MainActivityLaunchAnimation = -1L
|
||||
var MenuEntry = -1L
|
||||
var MiniPlayerDefaultText = -1L
|
||||
var MiniPlayerMdxPlaying = -1L
|
||||
@ -57,6 +59,7 @@ object SharedResourceIdPatch : ResourcePatch() {
|
||||
var TouchOutside = -1L
|
||||
var TrimSilenceSwitch: Long = -1
|
||||
var VarispeedUnavailableTitle = -1L
|
||||
var YtFillArrowShuffle = -1L
|
||||
|
||||
override fun execute(context: ResourceContext) {
|
||||
|
||||
@ -77,6 +80,7 @@ object SharedResourceIdPatch : ResourcePatch() {
|
||||
InterstitialsContainer = getId(ID, "interstitials_container")
|
||||
IsTablet = getId(BOOL, "is_tablet")
|
||||
LikeDislikeContainer = getId(ID, "like_dislike_container")
|
||||
MainActivityLaunchAnimation = getId(LAYOUT, "main_activity_launch_animation")
|
||||
MenuEntry = getId(LAYOUT, "menu_entry")
|
||||
MiniPlayerDefaultText = getId(STRING, "mini_player_default_text")
|
||||
MiniPlayerMdxPlaying = getId(STRING, "mini_player_mdx_playing")
|
||||
@ -102,6 +106,7 @@ object SharedResourceIdPatch : ResourcePatch() {
|
||||
TouchOutside = getId(ID, "touch_outside")
|
||||
TrimSilenceSwitch = getId(ID, "trim_silence_switch")
|
||||
VarispeedUnavailableTitle = getId(STRING, "varispeed_unavailable_title")
|
||||
YtFillArrowShuffle = getId(DRAWABLE, "yt_fill_arrow_shuffle_vd_theme_24")
|
||||
|
||||
}
|
||||
}
|
@ -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.RemoveLikeFingerprint
|
||||
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.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
@ -22,7 +22,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||
@Patch(
|
||||
dependencies = [
|
||||
SharedResourceIdPatch::class,
|
||||
VideoIdPatch::class
|
||||
VideoInformationPatch::class
|
||||
]
|
||||
)
|
||||
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")
|
||||
|
||||
}
|
||||
|
||||
|
@ -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(
|
||||
category: String
|
||||
) {
|
||||
|
@ -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.shared.fingerprints.SharedSettingFingerprint
|
||||
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 com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||
@ -52,7 +52,7 @@ object SettingsBytecodePatch : BytecodePatch(
|
||||
*/
|
||||
SharedSettingFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val stringIndex = getTargetIndexOrThrow(Opcode.CONST_STRING)
|
||||
val stringIndex = indexOfFirstInstructionOrThrow(Opcode.CONST_STRING)
|
||||
val stringRegister = getInstruction<OneRegisterInstruction>(stringIndex).registerA
|
||||
|
||||
replaceInstruction(
|
||||
|
@ -3,7 +3,6 @@ package app.revanced.patches.music.utils.settings
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
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.fix.accessibility.AccessibilityNodeInfoPatch
|
||||
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.addRVXSettingsPreference
|
||||
@ -22,10 +21,7 @@ import java.util.concurrent.TimeUnit
|
||||
object SettingsPatch : BaseResourcePatch(
|
||||
name = "Settings for YouTube Music",
|
||||
description = "Applies mandatory patches to implement ReVanced Extended settings into the application.",
|
||||
dependencies = setOf(
|
||||
AccessibilityNodeInfoPatch::class,
|
||||
SettingsBytecodePatch::class
|
||||
),
|
||||
dependencies = setOf(SettingsBytecodePatch::class),
|
||||
compatiblePackages = COMPATIBLE_PACKAGE,
|
||||
requiresIntegrations = true
|
||||
), Closeable {
|
||||
@ -42,8 +38,12 @@ object SettingsPatch : BaseResourcePatch(
|
||||
private lateinit var customName: String
|
||||
|
||||
lateinit var contexts: ResourceContext
|
||||
internal var upward0627 = false
|
||||
internal var upward0636 = false
|
||||
internal var upward0642 = false
|
||||
internal var upward0706 = false
|
||||
internal var upward0718 = false
|
||||
internal var upward0720 = false
|
||||
|
||||
override fun execute(context: ResourceContext) {
|
||||
|
||||
@ -136,8 +136,12 @@ object SettingsPatch : BaseResourcePatch(
|
||||
|
||||
val playServicesVersion = node.textContent.toInt()
|
||||
|
||||
upward0627 = 234412000 <= playServicesVersion
|
||||
upward0636 = 240399000 <= playServicesVersion
|
||||
upward0642 = 240999000 <= playServicesVersion
|
||||
upward0706 = 242499000 <= playServicesVersion
|
||||
upward0718 = 243699000 <= playServicesVersion
|
||||
upward0720 = 243899000 <= playServicesVersion
|
||||
|
||||
break
|
||||
}
|
||||
@ -223,6 +227,14 @@ object SettingsPatch : BaseResourcePatch(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* add open default app settings
|
||||
*/
|
||||
addPreferenceWithIntent(
|
||||
CategoryType.MISC,
|
||||
"revanced_default_app_settings"
|
||||
)
|
||||
|
||||
/**
|
||||
* add import export settings
|
||||
*/
|
||||
|
@ -6,27 +6,30 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
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.resourceid.SharedResourceIdPatch
|
||||
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.RectangleFieldInvalidatorFingerprint
|
||||
import app.revanced.patches.music.utils.sponsorblock.fingerprints.SeekBarConstructorFingerprint
|
||||
import app.revanced.patches.music.utils.sponsorblock.fingerprints.SeekbarOnDrawFingerprint
|
||||
import app.revanced.patches.music.video.information.VideoInformationPatch
|
||||
import app.revanced.patches.music.video.videoid.VideoIdPatch
|
||||
import app.revanced.util.getTargetIndexWithMethodReferenceNameOrThrow
|
||||
import app.revanced.util.getTargetIndexWithMethodReferenceNameReversedOrThrow
|
||||
import app.revanced.util.alsoResolve
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
|
||||
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.OneRegisterInstruction
|
||||
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.MethodReference
|
||||
|
||||
@Patch(
|
||||
dependencies = [
|
||||
SharedResourceIdPatch::class,
|
||||
VideoInformationPatch::class,
|
||||
VideoIdPatch::class
|
||||
VideoInformationPatch::class
|
||||
]
|
||||
)
|
||||
object SponsorBlockBytecodePatch : BytecodePatch(
|
||||
@ -39,7 +42,6 @@ object SponsorBlockBytecodePatch : BytecodePatch(
|
||||
private const val INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR =
|
||||
"$INTEGRATIONS_PATH/sponsorblock/SegmentPlaybackController;"
|
||||
|
||||
private lateinit var rectangleFieldName: String
|
||||
override fun execute(context: BytecodeContext) {
|
||||
|
||||
/**
|
||||
@ -55,22 +57,41 @@ object SponsorBlockBytecodePatch : BytecodePatch(
|
||||
/**
|
||||
* Responsible for seekbar in fullscreen
|
||||
*/
|
||||
val seekBarClass = SeekBarConstructorFingerprint.resultOrThrow().mutableClass
|
||||
SeekbarOnDrawFingerprint.resolve(context, seekBarClass)
|
||||
var rectangleFieldName =
|
||||
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 {
|
||||
// Initialize seekbar method
|
||||
addInstructions(
|
||||
0, """
|
||||
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
|
||||
"""
|
||||
)
|
||||
|
||||
// Set seekbar thickness
|
||||
val roundIndex = getTargetIndexWithMethodReferenceNameOrThrow("round") + 1
|
||||
val roundIndex = indexOfFirstInstructionOrThrow {
|
||||
getReference<MethodReference>()?.name == "round"
|
||||
} + 1
|
||||
val roundRegister = getInstruction<OneRegisterInstruction>(roundIndex).registerA
|
||||
addInstruction(
|
||||
roundIndex + 1,
|
||||
@ -79,8 +100,9 @@ object SponsorBlockBytecodePatch : BytecodePatch(
|
||||
)
|
||||
|
||||
// Draw segment
|
||||
val drawCircleIndex =
|
||||
getTargetIndexWithMethodReferenceNameReversedOrThrow("drawCircle")
|
||||
val drawCircleIndex = indexOfFirstInstructionReversedOrThrow {
|
||||
getReference<MethodReference>()?.name == "drawCircle"
|
||||
}
|
||||
val drawCircleInstruction = getInstruction<FiveRegisterInstruction>(drawCircleIndex)
|
||||
addInstruction(
|
||||
drawCircleIndex,
|
||||
@ -94,14 +116,15 @@ object SponsorBlockBytecodePatch : BytecodePatch(
|
||||
/**
|
||||
* Responsible for seekbar in player
|
||||
*/
|
||||
MusicPlaybackControlsTimeBarOnMeasureFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val rectangleIndex = it.scanResult.patternScanResult!!.startIndex
|
||||
val rectangleReference =
|
||||
getInstruction<ReferenceInstruction>(rectangleIndex).reference
|
||||
rectangleFieldName = (rectangleReference as FieldReference).name
|
||||
rectangleFieldName =
|
||||
MusicPlaybackControlsTimeBarOnMeasureFingerprint.resultOrThrow().let {
|
||||
with(it.mutableMethod) {
|
||||
val rectangleIndex = it.scanResult.patternScanResult!!.startIndex
|
||||
val rectangleReference =
|
||||
getInstruction<ReferenceInstruction>(rectangleIndex).reference
|
||||
(rectangleReference as FieldReference).name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MusicPlaybackControlsTimeBarDrawFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
@ -115,7 +138,10 @@ object SponsorBlockBytecodePatch : BytecodePatch(
|
||||
)
|
||||
|
||||
// Draw segment
|
||||
val drawCircleIndex = getTargetIndexWithMethodReferenceNameOrThrow("drawCircle")
|
||||
val drawCircleIndex = indexOfFirstInstructionOrThrow {
|
||||
opcode == Opcode.INVOKE_VIRTUAL
|
||||
&& getReference<MethodReference>()?.name == "drawCircle"
|
||||
}
|
||||
val drawCircleInstruction = getInstruction<FiveRegisterInstruction>(drawCircleIndex)
|
||||
addInstruction(
|
||||
drawCircleIndex,
|
||||
@ -128,6 +154,6 @@ object SponsorBlockBytecodePatch : BytecodePatch(
|
||||
/**
|
||||
* 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")
|
||||
}
|
||||
}
|
||||
|
@ -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"
|
||||
}
|
||||
}
|
@ -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.util.fingerprint.LiteralValueFingerprint
|
@ -4,40 +4,36 @@ import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprintResult
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchException
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableClass
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
|
||||
import app.revanced.patcher.util.smali.toInstructions
|
||||
import app.revanced.patches.music.utils.fingerprints.SeekBarConstructorFingerprint
|
||||
import app.revanced.patches.music.utils.integrations.Constants.SHARED_PATH
|
||||
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.PlaybackSpeedParentFingerprint
|
||||
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.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.VideoQualityTextFingerprint
|
||||
import app.revanced.patches.music.video.videoid.VideoIdPatch
|
||||
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.getTargetIndexWithFieldReferenceTypeReversedOrThrow
|
||||
import app.revanced.util.getTargetIndexWithMethodReferenceNameReversedOrThrow
|
||||
import app.revanced.util.getWalkerMethod
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
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.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.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.immutable.ImmutableMethodImplementation
|
||||
@ -45,10 +41,7 @@ import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
|
||||
import com.android.tools.smali.dexlib2.util.MethodUtil
|
||||
|
||||
@Patch(
|
||||
dependencies = [
|
||||
SharedResourceIdPatch::class,
|
||||
VideoIdPatch::class
|
||||
]
|
||||
dependencies = [SharedResourceIdPatch::class]
|
||||
)
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
object VideoInformationPatch : BytecodePatch(
|
||||
@ -56,8 +49,9 @@ object VideoInformationPatch : BytecodePatch(
|
||||
MdxPlayerDirectorSetVideoStageFingerprint,
|
||||
PlayerControllerSetTimeReferenceFingerprint,
|
||||
PlaybackSpeedParentFingerprint,
|
||||
SeekBarConstructorFingerprint,
|
||||
VideoEndFingerprint,
|
||||
VideoIdFingerprint,
|
||||
VideoLengthFingerprint,
|
||||
VideoQualityListFingerprint,
|
||||
VideoQualityTextFingerprint
|
||||
)
|
||||
@ -65,6 +59,20 @@ object VideoInformationPatch : BytecodePatch(
|
||||
private const val INTEGRATIONS_CLASS_DESCRIPTOR =
|
||||
"$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].
|
||||
* Since both classes are inherited from the same class,
|
||||
@ -73,7 +81,6 @@ object VideoInformationPatch : BytecodePatch(
|
||||
private var seekSourceEnumType = ""
|
||||
private var seekSourceMethodName = ""
|
||||
|
||||
private lateinit var videoInformationMutableClass: MutableClass
|
||||
private lateinit var context: BytecodeContext
|
||||
|
||||
private lateinit var playerConstructorMethod: MutableMethod
|
||||
@ -86,7 +93,6 @@ object VideoInformationPatch : BytecodePatch(
|
||||
private var videoTimeConstructorInsertIndex = 2
|
||||
|
||||
// Used by other patches.
|
||||
lateinit var rectangleFieldName: String
|
||||
internal lateinit var playbackSpeedResult: MethodFingerprintResult
|
||||
|
||||
private fun addSeekInterfaceMethods(
|
||||
@ -109,7 +115,7 @@ object VideoInformationPatch : BytecodePatch(
|
||||
4, """
|
||||
# first enum (field a) is SEEK_SOURCE_UNKNOWN
|
||||
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
|
||||
return p1
|
||||
""".toInstructions(),
|
||||
@ -130,21 +136,18 @@ object VideoInformationPatch : BytecodePatch(
|
||||
return v0
|
||||
"""
|
||||
|
||||
videoInformationMutableClass.addFieldAndInstructions(
|
||||
context,
|
||||
context.addStaticFieldToIntegration(
|
||||
INTEGRATIONS_CLASS_DESCRIPTOR,
|
||||
methodName,
|
||||
fieldName,
|
||||
definingClass,
|
||||
smaliInstructions,
|
||||
true
|
||||
smaliInstructions
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun execute(context: BytecodeContext) {
|
||||
this.context = context
|
||||
videoInformationMutableClass =
|
||||
context.findClass(INTEGRATIONS_CLASS_DESCRIPTOR)!!.mutableClass
|
||||
|
||||
VideoEndFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
@ -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
|
||||
*/
|
||||
@ -210,47 +241,19 @@ object VideoInformationPatch : BytecodePatch(
|
||||
/**
|
||||
* Set current video length
|
||||
*/
|
||||
VideoLengthFingerprint.resolve(
|
||||
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"
|
||||
)
|
||||
}
|
||||
}
|
||||
videoLengthHook("$INTEGRATIONS_CLASS_DESCRIPTOR->setVideoLength(J)V")
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
PlaybackSpeedFingerprint.resolve(
|
||||
context,
|
||||
PlaybackSpeedParentFingerprint.resultOrThrow().classDef
|
||||
)
|
||||
PlaybackSpeedFingerprint.resultOrThrow().let {
|
||||
PlaybackSpeedFingerprint.alsoResolve(
|
||||
context, PlaybackSpeedParentFingerprint
|
||||
).let {
|
||||
it.mutableMethod.apply {
|
||||
playbackSpeedResult = it
|
||||
val endIndex = it.scanResult.patternScanResult!!.endIndex
|
||||
@ -294,13 +297,12 @@ object VideoInformationPatch : BytecodePatch(
|
||||
return-void
|
||||
"""
|
||||
|
||||
videoInformationMutableClass.addFieldAndInstructions(
|
||||
context,
|
||||
VideoInformationPatch.context.addStaticFieldToIntegration(
|
||||
INTEGRATIONS_CLASS_DESCRIPTOR,
|
||||
"overrideVideoQuality",
|
||||
"videoQualityClass",
|
||||
videoQualityClass,
|
||||
smaliInstructions,
|
||||
true
|
||||
smaliInstructions
|
||||
)
|
||||
}
|
||||
|
||||
@ -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) =
|
||||
addInstruction(insertIndex, "invoke-static { $register }, $descriptor")
|
||||
|
||||
@ -351,6 +396,24 @@ object VideoInformationPatch : BytecodePatch(
|
||||
"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.
|
||||
* The hook is usually called once per second.
|
||||
|
@ -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.fingerprint.MethodFingerprint
|
@ -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" }
|
||||
)
|
@ -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.playback.fingerprints.PlaybackSpeedBottomSheetFingerprint
|
||||
import app.revanced.patches.music.video.playback.fingerprints.UserQualityChangeFingerprint
|
||||
import app.revanced.patches.music.video.videoid.VideoIdPatch
|
||||
import app.revanced.util.getTargetIndexOrThrow
|
||||
import app.revanced.util.findMethodOrThrow
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import app.revanced.util.patch.BaseBytecodePatch
|
||||
import app.revanced.util.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction21c
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||
|
||||
@Suppress("unused")
|
||||
@ -29,7 +29,6 @@ object VideoPlaybackPatch : BaseBytecodePatch(
|
||||
dependencies = setOf(
|
||||
CustomPlaybackSpeedPatch::class,
|
||||
SettingsPatch::class,
|
||||
VideoIdPatch::class,
|
||||
VideoInformationPatch::class
|
||||
),
|
||||
compatiblePackages = COMPATIBLE_PACKAGE,
|
||||
@ -52,7 +51,7 @@ object VideoPlaybackPatch : BaseBytecodePatch(
|
||||
it.mutableClass.methods.find { method -> method.name == "onItemClick" }
|
||||
|
||||
onItemClickMethod?.apply {
|
||||
val targetIndex = getTargetIndexOrThrow(Opcode.IGET)
|
||||
val targetIndex = indexOfFirstInstructionOrThrow(Opcode.IGET)
|
||||
val targetRegister =
|
||||
getInstruction<TwoRegisterInstruction>(targetIndex).registerA
|
||||
|
||||
@ -86,23 +85,18 @@ object VideoPlaybackPatch : BaseBytecodePatch(
|
||||
it.mutableMethod.apply {
|
||||
val endIndex = it.scanResult.patternScanResult!!.endIndex
|
||||
val qualityChangedClass =
|
||||
context.findClass(
|
||||
(getInstruction<BuilderInstruction21c>(endIndex))
|
||||
.reference.toString()
|
||||
)!!
|
||||
.mutableClass
|
||||
getInstruction<ReferenceInstruction>(endIndex).reference.toString()
|
||||
|
||||
val onItemClickMethod =
|
||||
qualityChangedClass.methods.find { method -> method.name == "onItemClick" }
|
||||
|
||||
onItemClickMethod?.addInstruction(
|
||||
context.findMethodOrThrow(qualityChangedClass) {
|
||||
name == "onItemClick"
|
||||
}.addInstruction(
|
||||
0,
|
||||
"invoke-static {}, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->userSelectedVideoQuality()V"
|
||||
) ?: throw PatchException("Failed to find onItemClick method")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
|
@ -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"
|
||||
)
|
||||
}
|
||||
|
@ -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.settings.SettingsBytecodePatch.updateSettingsStatus
|
||||
import app.revanced.patches.reddit.utils.settings.SettingsPatch
|
||||
import app.revanced.util.getTargetIndexWithFieldReferenceNameOrThrow
|
||||
import app.revanced.util.getTargetIndexWithMethodReferenceNameOrThrow
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import app.revanced.util.patch.BaseBytecodePatch
|
||||
import app.revanced.util.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
|
||||
@Suppress("unused")
|
||||
object AdsPatch : BaseBytecodePatch(
|
||||
@ -42,7 +45,9 @@ object AdsPatch : BaseBytecodePatch(
|
||||
// region Filter promoted ads (does not work in popular or latest feed)
|
||||
AdPostFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val targetIndex = getTargetIndexWithFieldReferenceNameOrThrow("children")
|
||||
val targetIndex = indexOfFirstInstructionOrThrow {
|
||||
getReference<FieldReference>()?.name == "children"
|
||||
}
|
||||
val targetRegister = getInstruction<TwoRegisterInstruction>(targetIndex).registerA
|
||||
|
||||
addInstructions(
|
||||
@ -59,7 +64,10 @@ object AdsPatch : BaseBytecodePatch(
|
||||
// By removing the appending instruction no ad posts gets appended to the feed.
|
||||
NewAdPostFingerprint.resultOrThrow().let {
|
||||
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)
|
||||
|
||||
replaceInstruction(
|
||||
|
@ -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.settings.SettingsBytecodePatch.updateSettingsStatus
|
||||
import app.revanced.patches.reddit.utils.settings.SettingsPatch
|
||||
import app.revanced.util.getTargetIndexOrThrow
|
||||
import app.revanced.util.getTargetIndexReversedOrThrow
|
||||
import app.revanced.util.getTargetIndexWithFieldReferenceNameOrThrow
|
||||
import app.revanced.util.getTargetIndexWithReferenceOrThrow
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
|
||||
import app.revanced.util.patch.BaseBytecodePatch
|
||||
import app.revanced.util.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
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
|
||||
|
||||
@Suppress("unused")
|
||||
@ -40,20 +40,31 @@ object RecentlyVisitedShelfPatch : BaseBytecodePatch(
|
||||
|
||||
it.mutableClass.methods.find { method -> method.name == "<init>" }
|
||||
?.apply {
|
||||
val recentlyVisitedFieldIndex =
|
||||
getTargetIndexWithFieldReferenceNameOrThrow("RECENTLY_VISITED")
|
||||
val recentlyVisitedFieldIndex = indexOfFirstInstructionOrThrow {
|
||||
getReference<FieldReference>()?.name == "RECENTLY_VISITED"
|
||||
}
|
||||
val recentlyVisitedObjectIndex =
|
||||
getTargetIndexOrThrow(recentlyVisitedFieldIndex, Opcode.IPUT_OBJECT)
|
||||
indexOfFirstInstructionOrThrow(
|
||||
recentlyVisitedFieldIndex,
|
||||
Opcode.IPUT_OBJECT
|
||||
)
|
||||
recentlyVisitedReference =
|
||||
getInstruction<ReferenceInstruction>(recentlyVisitedObjectIndex).reference
|
||||
} ?: throw PatchException("Constructor method not found!")
|
||||
|
||||
it.mutableMethod.apply {
|
||||
val recentlyVisitedObjectIndex =
|
||||
getTargetIndexWithReferenceOrThrow(recentlyVisitedReference.toString())
|
||||
val recentlyVisitedObjectIndex = indexOfFirstInstructionOrThrow {
|
||||
getReference<FieldReference>()?.toString() == recentlyVisitedReference.toString()
|
||||
}
|
||||
arrayOf(
|
||||
getTargetIndexOrThrow(recentlyVisitedObjectIndex, Opcode.INVOKE_STATIC),
|
||||
getTargetIndexReversedOrThrow(recentlyVisitedObjectIndex, Opcode.INVOKE_STATIC)
|
||||
indexOfFirstInstructionOrThrow(
|
||||
recentlyVisitedObjectIndex,
|
||||
Opcode.INVOKE_STATIC
|
||||
),
|
||||
indexOfFirstInstructionReversedOrThrow(
|
||||
recentlyVisitedObjectIndex,
|
||||
Opcode.INVOKE_STATIC
|
||||
)
|
||||
).forEach { staticIndex ->
|
||||
val insertRegister =
|
||||
getInstruction<OneRegisterInstruction>(staticIndex + 1).registerA
|
||||
|
@ -3,14 +3,14 @@ package app.revanced.patches.reddit.layout.screenshotpopup.fingerprints
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
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
|
||||
|
||||
internal object ScreenshotTakenBannerFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
customFingerprint = { methodDef, classDef ->
|
||||
methodDef.containsWideLiteralInstructionIndex(ScreenShotShareBanner)
|
||||
methodDef.containsWideLiteralInstructionValue(ScreenShotShareBanner)
|
||||
&& classDef.sourceFile == "ScreenshotTakenBanner.kt"
|
||||
}
|
||||
)
|
@ -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.settings.SettingsBytecodePatch.updateSettingsStatus
|
||||
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.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||
@ -39,7 +39,8 @@ object SubRedditDialogPatch : BaseBytecodePatch(
|
||||
|
||||
FrequentUpdatesSheetScreenFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val cancelButtonViewIndex = getWideLiteralInstructionIndex(CancelButton) + 2
|
||||
val cancelButtonViewIndex =
|
||||
indexOfFirstWideLiteralInstructionValueOrThrow(CancelButton) + 2
|
||||
val cancelButtonViewRegister =
|
||||
getInstruction<OneRegisterInstruction>(cancelButtonViewIndex).registerA
|
||||
|
||||
@ -53,7 +54,9 @@ object SubRedditDialogPatch : BaseBytecodePatch(
|
||||
RedditAlertDialogsFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val insertIndex =
|
||||
getWideLiteralInstructionIndex(TextAppearanceRedditBaseOldButtonColored) + 1
|
||||
indexOfFirstWideLiteralInstructionValueOrThrow(
|
||||
TextAppearanceRedditBaseOldButtonColored
|
||||
) + 1
|
||||
val insertRegister = getInstruction<FiveRegisterInstruction>(insertIndex).registerC
|
||||
|
||||
addInstruction(
|
||||
|
@ -3,14 +3,14 @@ package app.revanced.patches.reddit.layout.subredditdialog.fingerprints
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
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
|
||||
|
||||
internal object FrequentUpdatesSheetScreenFingerprint : MethodFingerprint(
|
||||
returnType = "Landroid/view/View;",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
customFingerprint = { methodDef, classDef ->
|
||||
methodDef.containsWideLiteralInstructionIndex(CancelButton)
|
||||
methodDef.containsWideLiteralInstructionValue(CancelButton)
|
||||
&& classDef.sourceFile == "FrequentUpdatesSheetScreen.kt"
|
||||
}
|
||||
)
|
@ -3,14 +3,14 @@ package app.revanced.patches.reddit.layout.subredditdialog.fingerprints
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
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
|
||||
|
||||
internal object RedditAlertDialogsFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
customFingerprint = { methodDef, classDef ->
|
||||
methodDef.containsWideLiteralInstructionIndex(TextAppearanceRedditBaseOldButtonColored)
|
||||
methodDef.containsWideLiteralInstructionValue(TextAppearanceRedditBaseOldButtonColored)
|
||||
&& classDef.sourceFile == "RedditAlertDialogs.kt"
|
||||
}
|
||||
)
|
@ -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.settings.SettingsBytecodePatch.updateSettingsStatus
|
||||
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.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
@ -35,7 +35,7 @@ object ToolBarButtonPatch : BaseBytecodePatch(
|
||||
HomePagerScreenFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val targetIndex =
|
||||
getWideLiteralInstructionIndex(ToolBarNavSearchCtaContainer) + 3
|
||||
indexOfFirstWideLiteralInstructionValueOrThrow(ToolBarNavSearchCtaContainer) + 3
|
||||
val targetRegister =
|
||||
getInstruction<OneRegisterInstruction>(targetIndex - 1).registerA
|
||||
|
||||
|
@ -3,7 +3,7 @@ package app.revanced.patches.reddit.layout.toolbar.fingerprints
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
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
|
||||
|
||||
internal object HomePagerScreenFingerprint : MethodFingerprint(
|
||||
@ -12,6 +12,6 @@ internal object HomePagerScreenFingerprint : MethodFingerprint(
|
||||
parameters = listOf("Landroid/view/LayoutInflater;", "Landroid/view/ViewGroup;"),
|
||||
customFingerprint = { methodDef, _ ->
|
||||
methodDef.definingClass.endsWith("/HomePagerScreen;")
|
||||
&& methodDef.containsWideLiteralInstructionIndex(ToolBarNavSearchCtaContainer)
|
||||
&& methodDef.containsWideLiteralInstructionValue(ToolBarNavSearchCtaContainer)
|
||||
}
|
||||
)
|
@ -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.settings.SettingsBytecodePatch.updateSettingsStatus
|
||||
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.resultOrThrow
|
||||
|
||||
@ -27,7 +27,7 @@ object OpenLinksExternallyPatch : BaseBytecodePatch(
|
||||
override fun execute(context: BytecodeContext) {
|
||||
ScreenNavigatorFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val insertIndex = getStringInstructionIndex("uri") + 2
|
||||
val insertIndex = indexOfFirstStringInstructionOrThrow("uri") + 2
|
||||
|
||||
addInstructionsWithLabels(
|
||||
insertIndex, """
|
||||
|
@ -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.SettingsStatusLoadFingerprint
|
||||
import app.revanced.patches.shared.fingerprints.SharedSettingFingerprint
|
||||
import app.revanced.util.getTargetIndexOrThrow
|
||||
import app.revanced.util.getWideLiteralInstructionIndex
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow
|
||||
import app.revanced.util.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
@ -39,7 +39,7 @@ object SettingsBytecodePatch : BytecodePatch(
|
||||
internal fun updateSettingsLabel(label: String) =
|
||||
acknowledgementsLabelBuilderMethod.apply {
|
||||
val insertIndex =
|
||||
getWideLiteralInstructionIndex(LabelAcknowledgements) + 3
|
||||
indexOfFirstWideLiteralInstructionValueOrThrow(LabelAcknowledgements) + 3
|
||||
val insertRegister =
|
||||
getInstruction<OneRegisterInstruction>(insertIndex - 1).registerA
|
||||
|
||||
@ -62,7 +62,7 @@ object SettingsBytecodePatch : BytecodePatch(
|
||||
*/
|
||||
SharedSettingFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val stringIndex = getTargetIndexOrThrow(Opcode.CONST_STRING)
|
||||
val stringIndex = indexOfFirstInstructionOrThrow(Opcode.CONST_STRING)
|
||||
val stringRegister = getInstruction<OneRegisterInstruction>(stringIndex).registerA
|
||||
|
||||
replaceInstruction(
|
||||
|
@ -3,7 +3,7 @@ package app.revanced.patches.reddit.utils.settings.fingerprints
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
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
|
||||
|
||||
internal object AcknowledgementsLabelBuilderFingerprint : MethodFingerprint(
|
||||
@ -12,6 +12,6 @@ internal object AcknowledgementsLabelBuilderFingerprint : MethodFingerprint(
|
||||
parameters = listOf("Landroidx/preference/Preference;"),
|
||||
customFingerprint = { methodDef, _ ->
|
||||
methodDef.definingClass.startsWith("Lcom/reddit/screen/settings/preferences/")
|
||||
&& methodDef.containsWideLiteralInstructionIndex(LabelAcknowledgements)
|
||||
&& methodDef.containsWideLiteralInstructionValue(LabelAcknowledgements)
|
||||
}
|
||||
)
|
@ -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.VideoAdsFingerprint
|
||||
import app.revanced.patches.shared.integrations.Constants.PATCHES_PATH
|
||||
import app.revanced.util.getTargetIndexOrThrow
|
||||
import app.revanced.util.getTargetIndexWithMethodReferenceNameOrThrow
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.getWalkerMethod
|
||||
import app.revanced.util.getWideLiteralInstructionIndex
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow
|
||||
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.OneRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||
@ -34,12 +32,16 @@ abstract class BaseAdsPatch(
|
||||
VideoAdsFingerprint
|
||||
)
|
||||
) {
|
||||
private companion object {
|
||||
const val INTEGRATIONS_CLASS_DESCRIPTOR =
|
||||
"$PATCHES_PATH/FullscreenAdsPatch;"
|
||||
}
|
||||
|
||||
override fun execute(context: BytecodeContext) {
|
||||
MusicAdsFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val targetIndex = indexOfFirstInstructionOrThrow {
|
||||
val reference = ((this as? ReferenceInstruction)?.reference as? MethodReference)
|
||||
|
||||
val reference = getReference<MethodReference>()
|
||||
opcode == Opcode.INVOKE_VIRTUAL
|
||||
&& reference?.returnType == "V"
|
||||
&& reference.parameterTypes.size == 1
|
||||
@ -72,7 +74,7 @@ abstract class BaseAdsPatch(
|
||||
|
||||
internal fun MethodFingerprintResult.hookNonLithoFullscreenAds(literal: Long) {
|
||||
mutableMethod.apply {
|
||||
val targetIndex = getWideLiteralInstructionIndex(literal) + 2
|
||||
val targetIndex = indexOfFirstWideLiteralInstructionValueOrThrow(literal) + 2
|
||||
val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
|
||||
|
||||
addInstruction(
|
||||
@ -82,7 +84,7 @@ abstract class BaseAdsPatch(
|
||||
}
|
||||
}
|
||||
|
||||
internal fun MethodFingerprintResult.hookLithoFullscreenAds(context: BytecodeContext) {
|
||||
internal fun MethodFingerprintResult.hookLithoFullscreenAds() {
|
||||
mutableMethod.apply {
|
||||
val dialogCodeIndex = scanResult.patternScanResult!!.endIndex
|
||||
val dialogCodeField =
|
||||
@ -90,58 +92,35 @@ abstract class BaseAdsPatch(
|
||||
if (dialogCodeField.type != "I")
|
||||
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
|
||||
addInstructionsWithLabels(
|
||||
0,
|
||||
"""
|
||||
move-object/from16 v0, p2
|
||||
|
||||
# In the latest version of YouTube and YouTube Music, it is used after being cast
|
||||
|
||||
check-cast v0, ${dialogCodeField.definingClass}
|
||||
iget v0, v0, $dialogCodeField
|
||||
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
|
||||
"""
|
||||
0, prependInstructions + """
|
||||
check-cast v1, ${dialogCodeField.definingClass}
|
||||
iget v1, v1, $dialogCodeField
|
||||
invoke-static {v0, v1}, $INTEGRATIONS_CLASS_DESCRIPTOR->disableFullscreenAds([BI)Z
|
||||
move-result v1
|
||||
if-eqz v1, :show
|
||||
return-void
|
||||
""", ExternalLabel("show", getInstruction(0))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val INTEGRATIONS_CLASS_DESCRIPTOR =
|
||||
"$PATCHES_PATH/FullscreenAdsPatch;"
|
||||
}
|
||||
}
|
@ -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
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -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.fingerprint.MethodFingerprint
|
||||
@ -7,6 +7,6 @@ import com.android.tools.smali.dexlib2.AccessFlags
|
||||
internal object StoryboardRendererDecoderRecommendedLevelFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = listOf("Lcom/google/android/libraries/youtube/innertube/model/player/PlayerResponseModel;"),
|
||||
parameters = listOf("L"),
|
||||
strings = listOf("#-1#")
|
||||
)
|
@ -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.fingerprint.MethodFingerprint
|
@ -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.SpeedLimiterFallBackFingerprint
|
||||
import app.revanced.patches.shared.customspeed.fingerprints.SpeedLimiterFingerprint
|
||||
import app.revanced.util.getTargetIndexOrThrow
|
||||
import app.revanced.util.getTargetIndexWithFieldReferenceTypeOrThrow
|
||||
import app.revanced.util.getTargetIndexWithMethodReferenceNameOrThrow
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import app.revanced.util.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
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.reference.FieldReference
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
|
||||
abstract class BaseCustomPlaybackSpeedPatch(
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
addInstructions(
|
||||
@ -73,7 +77,7 @@ abstract class BaseCustomPlaybackSpeedPatch(
|
||||
val limiterMinConstIndex =
|
||||
indexOfFirstInstructionOrThrow { (this as? NarrowLiteralInstruction)?.narrowLiteral == 0.25f.toRawBits() }
|
||||
val limiterMaxConstIndex =
|
||||
getTargetIndexOrThrow(limiterMinConstIndex + 1, Opcode.CONST_HIGH16)
|
||||
indexOfFirstInstructionOrThrow(limiterMinConstIndex + 1, Opcode.CONST_HIGH16)
|
||||
|
||||
val limiterMinConstDestination =
|
||||
getInstruction<OneRegisterInstruction>(limiterMinConstIndex).registerA
|
||||
|
@ -7,10 +7,12 @@ import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
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.indexOfFirstInstructionOrThrow
|
||||
import app.revanced.util.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
|
||||
abstract class BaseViewerDiscretionDialogPatch(
|
||||
private val classDescriptor: String,
|
||||
@ -22,7 +24,9 @@ abstract class BaseViewerDiscretionDialogPatch(
|
||||
}
|
||||
) {
|
||||
private fun MutableMethod.invoke(isAgeVerified: Boolean) {
|
||||
val showDialogIndex = getTargetIndexWithMethodReferenceNameOrThrow("show")
|
||||
val showDialogIndex = indexOfFirstInstructionOrThrow {
|
||||
getReference<MethodReference>()?.name == "show"
|
||||
}
|
||||
val dialogRegister = getInstruction<FiveRegisterInstruction>(showDialogIndex).registerC
|
||||
|
||||
val methodName =
|
||||
|
@ -6,9 +6,11 @@ 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.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 com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
|
||||
object DrawableColorPatch : BytecodePatch(
|
||||
setOf(DrawableFingerprint)
|
||||
@ -17,26 +19,26 @@ object DrawableColorPatch : BytecodePatch(
|
||||
|
||||
DrawableFingerprint.resultOrThrow().mutableMethod.apply {
|
||||
insertMethod = this
|
||||
insertIndex = getTargetIndexWithMethodReferenceNameReversedOrThrow("setColor")
|
||||
insertIndex = indexOfFirstInstructionReversedOrThrow {
|
||||
getReference<MethodReference>()?.name == "setColor"
|
||||
}
|
||||
insertRegister = getInstruction<FiveRegisterInstruction>(insertIndex).registerD
|
||||
}
|
||||
}
|
||||
|
||||
private var offset = 0
|
||||
|
||||
private lateinit var insertMethod: MutableMethod
|
||||
private var insertIndex: Int = 0
|
||||
private var insertRegister: Int = 0
|
||||
private lateinit var insertMethod: MutableMethod
|
||||
|
||||
private var offset = 0
|
||||
|
||||
fun injectCall(
|
||||
methodDescriptor: String
|
||||
) {
|
||||
insertMethod.addInstructions(
|
||||
insertIndex + offset, """
|
||||
invoke-static {v$insertRegister}, $methodDescriptor
|
||||
move-result v$insertRegister
|
||||
"""
|
||||
invoke-static {v$insertRegister}, $methodDescriptor
|
||||
move-result v$insertRegister
|
||||
"""
|
||||
)
|
||||
offset += 2
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
)
|
@ -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.fingerprint.MethodFingerprint
|
@ -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.CastDynamiteModuleV2Fingerprint
|
||||
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.GooglePlayUtilityFingerprint
|
||||
import app.revanced.patches.shared.gms.fingerprints.PrimeMethodFingerprint
|
||||
import app.revanced.patches.shared.gms.fingerprints.ServiceCheckFingerprint
|
||||
import app.revanced.patches.shared.integrations.Constants.PATCHES_PATH
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.getTargetIndexWithReference
|
||||
import app.revanced.util.resultOrThrow
|
||||
import app.revanced.util.returnEarly
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
@ -178,7 +176,7 @@ abstract class BaseGmsCoreSupportPatch(
|
||||
CertificateFingerprint.result?.mutableClass?.methods?.forEach { mutableMethod ->
|
||||
mutableMethod.apply {
|
||||
val getPackageNameIndex =
|
||||
getTargetIndexWithReference(GET_PACKAGE_NAME_METHOD_REFERENCE)
|
||||
CertificateFingerprint.indexOfGetPackageNameInstruction(this)
|
||||
|
||||
if (getPackageNameIndex > -1) {
|
||||
val targetRegister =
|
||||
|
@ -1,20 +1,28 @@
|
||||
package app.revanced.patches.shared.gms.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patches.shared.gms.fingerprints.CertificateFingerprint.GET_PACKAGE_NAME_METHOD_REFERENCE
|
||||
import app.revanced.util.fingerprint.ReferenceFingerprint
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
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.iface.Method
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
|
||||
/**
|
||||
* Method which the package name is used to check the app signature.
|
||||
*/
|
||||
internal object CertificateFingerprint : ReferenceFingerprint(
|
||||
internal object CertificateFingerprint : MethodFingerprint(
|
||||
returnType = "Ljava/lang/String;",
|
||||
accessFlags = AccessFlags.PROTECTED or AccessFlags.FINAL,
|
||||
parameters = emptyList(),
|
||||
strings = listOf("X.509", "user", "S"),
|
||||
reference = { GET_PACKAGE_NAME_METHOD_REFERENCE }
|
||||
customFingerprint = { methodDef, _ ->
|
||||
indexOfGetPackageNameInstruction(methodDef) >= 0
|
||||
}
|
||||
) {
|
||||
const val GET_PACKAGE_NAME_METHOD_REFERENCE =
|
||||
"Landroid/content/Context;->getPackageName()Ljava/lang/String;"
|
||||
fun indexOfGetPackageNameInstruction(methodDef: Method) =
|
||||
methodDef.indexOfFirstInstruction {
|
||||
getReference<MethodReference>()?.toString() == "Landroid/content/Context;->getPackageName()Ljava/lang/String;"
|
||||
}
|
||||
}
|
||||
|
@ -102,8 +102,8 @@ abstract class BaseCronetImageUrlHookPatch(
|
||||
// Add a helper get method that returns the URL field.
|
||||
RequestFingerprint.resultOrThrow().apply {
|
||||
// The url is the only string field that is set inside the constructor.
|
||||
val urlFieldInstruction = mutableMethod.getInstructions().single {
|
||||
if (it.opcode != Opcode.IPUT_OBJECT) return@single false
|
||||
val urlFieldInstruction = mutableMethod.getInstructions().first {
|
||||
if (it.opcode != Opcode.IPUT_OBJECT) return@first false
|
||||
|
||||
val reference = (it as ReferenceInstruction).reference as FieldReference
|
||||
reference.type == "Ljava/lang/String;"
|
||||
|
@ -4,10 +4,11 @@ import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchException
|
||||
import app.revanced.patches.shared.integrations.BaseIntegrationsPatch.IntegrationsFingerprint.IRegisterResolver
|
||||
import app.revanced.patches.shared.integrations.Constants.INTEGRATIONS_UTILS_CLASS_DESCRIPTOR
|
||||
import app.revanced.util.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.iface.ClassDef
|
||||
import com.android.tools.smali.dexlib2.iface.Method
|
||||
@ -17,11 +18,7 @@ abstract class BaseIntegrationsPatch(
|
||||
) : BytecodePatch(hooks) {
|
||||
|
||||
override fun execute(context: BytecodeContext) {
|
||||
if (context.findClass(INTEGRATIONS_UTILS_CLASS_DESCRIPTOR) == null) {
|
||||
throw PatchException(
|
||||
"Integrations have not been merged yet. This patch can not succeed without merging the integrations.",
|
||||
)
|
||||
}
|
||||
context.findMethodOrThrow(INTEGRATIONS_UTILS_CLASS_DESCRIPTOR)
|
||||
|
||||
hooks.forEach { hook ->
|
||||
hook.invoke(INTEGRATIONS_UTILS_CLASS_DESCRIPTOR)
|
||||
@ -53,16 +50,21 @@ abstract class BaseIntegrationsPatch(
|
||||
) {
|
||||
|
||||
fun invoke(integrationsDescriptor: String) {
|
||||
resultOrThrow().mutableMethod.let { method ->
|
||||
val insertIndex = insertIndexResolver(method)
|
||||
val contextRegister = contextRegisterResolver(method)
|
||||
val method = result?.mutableMethod
|
||||
?: if (!isDeprecated()) {
|
||||
throw exception
|
||||
} else {
|
||||
return
|
||||
}
|
||||
|
||||
method.addInstruction(
|
||||
insertIndex,
|
||||
"invoke-static/range { $contextRegister .. $contextRegister }, " +
|
||||
"$integrationsDescriptor->setContext(Landroid/content/Context;)V",
|
||||
)
|
||||
}
|
||||
val insertIndex = insertIndexResolver(method)
|
||||
val contextRegister = contextRegisterResolver(method)
|
||||
|
||||
method.addInstruction(
|
||||
insertIndex,
|
||||
"invoke-static/range { $contextRegister .. $contextRegister }, " +
|
||||
"$integrationsDescriptor->setContext(Landroid/content/Context;)V",
|
||||
)
|
||||
}
|
||||
|
||||
interface IHookInsertIndexResolver : (Method) -> Int {
|
||||
|
@ -5,84 +5,112 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.removeInstructions
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
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.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.LithoFilterPatchConstructorFingerprint
|
||||
import app.revanced.patches.shared.litho.fingerprints.PathBuilderFingerprint
|
||||
import app.revanced.patches.shared.litho.fingerprints.SetByteBufferFingerprint
|
||||
import app.revanced.util.getStringInstructionIndex
|
||||
import app.revanced.util.getTargetIndexOrThrow
|
||||
import app.revanced.util.getTargetIndexReversedOrThrow
|
||||
import app.revanced.util.getTargetIndexWithFieldReferenceTypeOrThrow
|
||||
import app.revanced.util.findMethodsOrThrow
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
|
||||
import app.revanced.util.indexOfFirstStringInstructionOrThrow
|
||||
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.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.ReferenceInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
|
||||
import com.android.tools.smali.dexlib2.util.MethodUtil
|
||||
import java.io.Closeable
|
||||
|
||||
@Suppress("SpellCheckingInspection", "unused")
|
||||
object LithoFilterPatch : BytecodePatch(
|
||||
setOf(
|
||||
ByteBufferFingerprint,
|
||||
EmptyComponentsFingerprint,
|
||||
LithoFilterPatchConstructorFingerprint,
|
||||
SetByteBufferFingerprint
|
||||
)
|
||||
), Closeable {
|
||||
private const val INTEGRATIONS_LITHO_FILER_CLASS_DESCRIPTOR =
|
||||
"$COMPONENTS_PATH/LithoFilterPatch;"
|
||||
|
||||
private const val INTEGRATIONS_FILER_CLASS_DESCRIPTOR =
|
||||
"$COMPONENTS_PATH/Filter;"
|
||||
private const val INTEGRATIONS_FILER_ARRAY_DESCRIPTOR =
|
||||
"[$COMPONENTS_PATH/Filter;"
|
||||
|
||||
private lateinit var filterArrayMethod: MutableMethod
|
||||
private var filterCount = 0
|
||||
|
||||
internal lateinit var addFilter: (String) -> Unit
|
||||
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) {
|
||||
|
||||
SetByteBufferFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val insertIndex = getTargetIndexOrThrow(Opcode.IF_EQZ) + 1
|
||||
// region Pass the buffer into Integrations.
|
||||
|
||||
addInstruction(
|
||||
insertIndex,
|
||||
"invoke-static { p2 }, $INTEGRATIONS_LITHO_FILER_CLASS_DESCRIPTOR->setProtoBuffer(Ljava/nio/ByteBuffer;)V"
|
||||
)
|
||||
}
|
||||
}
|
||||
ByteBufferFingerprint.resultOrThrow().mutableMethod.addInstruction(
|
||||
0,
|
||||
"invoke-static { p2 }, $INTEGRATIONS_LITHO_FILER_CLASS_DESCRIPTOR->setProtoBuffer(Ljava/nio/ByteBuffer;)V"
|
||||
)
|
||||
|
||||
EmptyComponentsFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
// resolves fingerprint.
|
||||
// endregion
|
||||
|
||||
var (emptyComponentMethod, emptyComponentLabel) =
|
||||
EmptyComponentsFingerprint.resultOrThrow().let {
|
||||
PathBuilderFingerprint.resolve(context, it.classDef)
|
||||
emptyComponentMethod = this
|
||||
emptyComponentMethodName = name
|
||||
with(it.mutableMethod) {
|
||||
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 emptyComponentMethodReference =
|
||||
getInstruction<ReferenceInstruction>(emptyComponentMethodIndex).reference
|
||||
val emptyComponentFieldReference =
|
||||
getInstruction<ReferenceInstruction>(emptyComponentMethodIndex + 2).reference
|
||||
val label = """
|
||||
move-object/from16 v0, p1
|
||||
invoke-static {v0}, $emptyComponentMethodReference
|
||||
move-result-object v0
|
||||
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 = """
|
||||
move-object/from16 v0, p1
|
||||
invoke-static {v0}, $emptyComponentMethodReference
|
||||
move-result-object v0
|
||||
iget-object v0, v0, $emptyComponentFieldReference
|
||||
const/4 v0, 0x0
|
||||
return-object v0
|
||||
"""
|
||||
}
|
||||
@ -90,65 +118,27 @@ object LithoFilterPatch : BytecodePatch(
|
||||
|
||||
PathBuilderFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
// If the EmptyComponents Method and the PathBuilder Method are different,
|
||||
// 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"
|
||||
checkMethodSignatureMatch(this)
|
||||
|
||||
emptyComponentMethod.apply {
|
||||
// If the return value of the PathBuilder Method is null,
|
||||
// it means that pathBuilder has been filtered by the LithoFilterPatch.
|
||||
// (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 = indexOfFirstInstructionOrThrow {
|
||||
opcode == Opcode.IPUT_OBJECT &&
|
||||
getReference<FieldReference>()?.type == "Ljava/lang/StringBuilder;"
|
||||
}
|
||||
|
||||
val stringBuilderIndex =
|
||||
getTargetIndexWithFieldReferenceTypeOrThrow("Ljava/lang/StringBuilder;")
|
||||
val stringBuilderRegister =
|
||||
getInstruction<TwoRegisterInstruction>(stringBuilderIndex).registerA
|
||||
|
||||
val emptyStringIndex = getStringInstructionIndex("")
|
||||
|
||||
val identifierIndex =
|
||||
getTargetIndexReversedOrThrow(emptyStringIndex, Opcode.IPUT_OBJECT)
|
||||
val identifierRegister =
|
||||
getInstruction<TwoRegisterInstruction>(identifierIndex).registerA
|
||||
|
||||
val objectIndex = getTargetIndexOrThrow(emptyStringIndex, Opcode.INVOKE_VIRTUAL)
|
||||
val objectRegister = getInstruction<BuilderInstruction35c>(objectIndex).registerC
|
||||
val emptyStringIndex = indexOfFirstStringInstructionOrThrow("")
|
||||
val identifierRegister = getInstruction<TwoRegisterInstruction>(
|
||||
indexOfFirstInstructionReversedOrThrow(emptyStringIndex) {
|
||||
opcode == Opcode.IPUT_OBJECT
|
||||
&& getReference<FieldReference>()?.type == "Ljava/lang/String;"
|
||||
}
|
||||
).registerA
|
||||
val objectRegister = getInstruction<FiveRegisterInstruction>(
|
||||
indexOfFirstInstructionOrThrow(emptyStringIndex) {
|
||||
opcode == Opcode.INVOKE_VIRTUAL
|
||||
}
|
||||
).registerC
|
||||
|
||||
val insertIndex = stringBuilderIndex + 1
|
||||
|
||||
@ -163,30 +153,67 @@ object LithoFilterPatch : BytecodePatch(
|
||||
}
|
||||
}
|
||||
|
||||
LithoFilterPatchConstructorFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
removeInstructions(0, 6)
|
||||
// Create a new method to get the filter array to avoid register conflicts.
|
||||
// This fixes an issue with Integrations compiled with Android Gradle Plugin 8.3.0+.
|
||||
// https://github.com/ReVanced/revanced-patches/issues/2818
|
||||
val lithoFilterMethods =
|
||||
context.findMethodsOrThrow(INTEGRATIONS_LITHO_FILER_CLASS_DESCRIPTOR)
|
||||
|
||||
addFilter = { classDescriptor ->
|
||||
addInstructions(
|
||||
0, """
|
||||
new-instance v0, $classDescriptor
|
||||
invoke-direct {v0}, $classDescriptor-><init>()V
|
||||
const/16 v3, ${filterCount++}
|
||||
aput-object v0, v2, v3
|
||||
"""
|
||||
lithoFilterMethods
|
||||
.first { it.name == "<clinit>" }
|
||||
.apply {
|
||||
val setArrayIndex = indexOfFirstInstructionOrThrow {
|
||||
opcode == Opcode.SPUT_OBJECT &&
|
||||
getReference<FieldReference>()?.type == INTEGRATIONS_FILER_ARRAY_DESCRIPTOR
|
||||
}
|
||||
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!!
|
||||
.mutableMethod.addInstructions(
|
||||
0, """
|
||||
const/16 v1, $filterCount
|
||||
new-array v2, v1, [$INTEGRATIONS_FILER_CLASS_DESCRIPTOR
|
||||
const/4 v1, 0x1
|
||||
"""
|
||||
)
|
||||
override fun close() = filterArrayMethod.addInstructions(
|
||||
0,
|
||||
"""
|
||||
const/16 v0, $filterCount
|
||||
new-array v2, v0, $INTEGRATIONS_FILER_ARRAY_DESCRIPTOR
|
||||
"""
|
||||
)
|
||||
}
|
@ -5,7 +5,7 @@ import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal object SetByteBufferFingerprint : MethodFingerprint(
|
||||
internal object ByteBufferFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = listOf("I", "Ljava/nio/ByteBuffer;"),
|
@ -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;"
|
||||
}
|
||||
)
|
@ -7,7 +7,7 @@ import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchException
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableClass
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.util.getTargetIndexOrThrow
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import app.revanced.util.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import kotlin.properties.Delegates
|
||||
@ -38,7 +38,8 @@ abstract class BaseMainActivityResolvePatch(
|
||||
|
||||
// set onBackPressed method
|
||||
onBackPressedMethod = getMethod("onBackPressed")
|
||||
onBackPressedMethodIndex = onBackPressedMethod.getTargetIndexOrThrow(Opcode.RETURN_VOID)
|
||||
onBackPressedMethodIndex =
|
||||
onBackPressedMethod.indexOfFirstInstructionOrThrow(Opcode.RETURN_VOID)
|
||||
|
||||
// set onConfigurationChanged method
|
||||
onConfigurationChangedMethod = getMethod("onConfigurationChanged")
|
||||
|
@ -7,11 +7,13 @@ import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.util.smali.ExternalLabel
|
||||
import app.revanced.patches.shared.opus.fingerprints.CodecReferenceFingerprint
|
||||
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 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.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.
|
||||
@ -25,15 +27,14 @@ abstract class BaseOpusCodecsPatch(
|
||||
CodecSelectorFingerprint
|
||||
)
|
||||
) {
|
||||
private lateinit var opusCodecReference: Reference
|
||||
|
||||
override fun execute(context: BytecodeContext) {
|
||||
|
||||
CodecReferenceFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val targetIndex = getTargetIndexWithReferenceOrThrow("Ljava/util/Set;")
|
||||
opusCodecReference = getInstruction<ReferenceInstruction>(targetIndex).reference
|
||||
val opusCodecReference = with(CodecReferenceFingerprint.resultOrThrow().mutableMethod) {
|
||||
val codecIndex = indexOfFirstInstructionOrThrow {
|
||||
opcode == Opcode.INVOKE_STATIC &&
|
||||
getReference<MethodReference>()?.returnType == "Ljava/util/Set;"
|
||||
}
|
||||
getInstruction<ReferenceInstruction>(codecIndex).reference
|
||||
}
|
||||
|
||||
CodecSelectorFingerprint.resultOrThrow().let {
|
||||
|
@ -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.settingmenu.fingerprints.SettingsMenuFingerprint
|
||||
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 com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||
|
||||
@Patch(
|
||||
description = "Hide the settings menu for YouTube or YouTube Music.",
|
||||
@ -25,8 +27,9 @@ object SettingsMenuPatch : BytecodePatch(
|
||||
override fun execute(context: BytecodeContext) {
|
||||
|
||||
SettingsMenuFingerprint.resultOrThrow().mutableMethod.apply {
|
||||
val insertIndex =
|
||||
getTargetIndexWithFieldReferenceTypeOrThrow("Landroid/support/v7/widget/RecyclerView;")
|
||||
val insertIndex = indexOfFirstInstructionOrThrow {
|
||||
getReference<FieldReference>()?.type == "Landroid/support/v7/widget/RecyclerView;"
|
||||
}
|
||||
val insertRegister = getInstruction<TwoRegisterInstruction>(insertIndex).registerA
|
||||
|
||||
addInstruction(
|
||||
|
@ -6,7 +6,7 @@ import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patches.shared.fingerprints.CreatePlayerRequestBodyWithModelFingerprint
|
||||
import app.revanced.patches.shared.fingerprints.CreatePlayerRequestBodyWithModelFingerprint.indexOfReleaseInstruction
|
||||
import app.revanced.util.getTargetIndexReversedOrThrow
|
||||
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
|
||||
import app.revanced.util.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||
@ -20,7 +20,8 @@ abstract class BaseSpoofAppVersionPatch(
|
||||
|
||||
CreatePlayerRequestBodyWithModelFingerprint.resultOrThrow().mutableMethod.apply {
|
||||
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
|
||||
|
||||
addInstructions(
|
||||
|
@ -3,12 +3,12 @@ package app.revanced.patches.shared.viewgroup
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchException
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patches.shared.integrations.Constants.INTEGRATIONS_UTILS_CLASS_DESCRIPTOR
|
||||
import app.revanced.patches.shared.viewgroup.fingerprints.ViewGroupMarginFingerprint
|
||||
import app.revanced.patches.shared.viewgroup.fingerprints.ViewGroupMarginParentFingerprint
|
||||
import app.revanced.util.resultOrThrow
|
||||
import app.revanced.util.alsoResolve
|
||||
import app.revanced.util.findMethodOrThrow
|
||||
|
||||
@Patch(
|
||||
description = "Hook YouTube or YouTube Music to use ViewGroup.MarginLayoutParams in the integration.",
|
||||
@ -18,26 +18,21 @@ object ViewGroupMarginLayoutParamsHookPatch : BytecodePatch(
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
|
||||
val method =
|
||||
context.findClass(INTEGRATIONS_UTILS_CLASS_DESCRIPTOR)?.mutableClass?.methods?.first { method ->
|
||||
method.name == "hideViewGroupByMarginLayoutParams"
|
||||
} ?: throw PatchException("Could not find hideViewGroupByMarginLayoutParams method")
|
||||
|
||||
ViewGroupMarginFingerprint.resolve(
|
||||
context,
|
||||
ViewGroupMarginParentFingerprint.resultOrThrow().classDef
|
||||
)
|
||||
ViewGroupMarginFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val setViewGroupMarginCall = "$definingClass->$name(Landroid/view/View;II)V"
|
||||
|
||||
method.addInstructions(
|
||||
0, """
|
||||
const/4 v0, 0x0
|
||||
invoke-static {p0, v0, v0}, $setViewGroupMarginCall
|
||||
"""
|
||||
)
|
||||
}
|
||||
val setViewGroupMarginCall = with(
|
||||
ViewGroupMarginFingerprint.alsoResolve(
|
||||
context, ViewGroupMarginParentFingerprint
|
||||
).mutableMethod
|
||||
) {
|
||||
"$definingClass->$name(Landroid/view/View;II)V"
|
||||
}
|
||||
|
||||
context.findMethodOrThrow(INTEGRATIONS_UTILS_CLASS_DESCRIPTOR) {
|
||||
name == "hideViewGroupByMarginLayoutParams"
|
||||
}.addInstructions(
|
||||
0, """
|
||||
const/4 v0, 0x0
|
||||
invoke-static {p0, v0, v0}, $setViewGroupMarginCall
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
@ -43,7 +43,7 @@ object AdsBytecodePatch : BytecodePatch(
|
||||
// litho view, used in 'ShowDialogCommandOuterClass' in innertube
|
||||
ShowDialogCommandFingerprint
|
||||
.resultOrThrow()
|
||||
.hookLithoFullscreenAds(context)
|
||||
.hookLithoFullscreenAds()
|
||||
|
||||
// endregion
|
||||
|
||||
|
@ -50,12 +50,8 @@ object AdsPatch : BaseResourcePatch(
|
||||
private const val ADS_FILTER_CLASS_DESCRIPTOR =
|
||||
"$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) {
|
||||
LithoFilterPatch.addFilter(ADS_FILTER_CLASS_DESCRIPTOR)
|
||||
LithoFilterPatch.addFilter(FULLSCREEN_ADS_FILTER_CLASS_DESCRIPTOR)
|
||||
|
||||
context.forEach {
|
||||
|
||||
|
@ -2,7 +2,7 @@ package app.revanced.patches.youtube.ads.general.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
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
|
||||
|
||||
internal object ShowDialogCommandFingerprint : MethodFingerprint(
|
||||
@ -16,7 +16,7 @@ internal object ShowDialogCommandFingerprint : MethodFingerprint(
|
||||
// 18.43 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.containsWideLiteralInstructionIndex(SlidingDialogAnimation)) {
|
||||
if (!methodDef.containsWideLiteralInstructionValue(SlidingDialogAnimation)) {
|
||||
return@custom false
|
||||
}
|
||||
// 18.43 and earlier parameters are: "L", "L"
|
||||
|
@ -7,6 +7,7 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWith
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import app.revanced.patcher.patch.PatchException
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patcher.util.smali.ExternalLabel
|
||||
import app.revanced.patches.shared.litho.LithoFilterPatch
|
||||
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.ElementParserFingerprint
|
||||
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.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.SearchResultsChipBarFingerprint
|
||||
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.fingerprints.EngagementPanelBuilderFingerprint
|
||||
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.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.playertype.PlayerTypeHookPatch
|
||||
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch
|
||||
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.CaptionToggleContainer
|
||||
import app.revanced.patches.youtube.utils.settings.SettingsPatch
|
||||
import app.revanced.util.getTargetIndexOrThrow
|
||||
import app.revanced.util.getTargetIndexReversedOrThrow
|
||||
import app.revanced.util.getTargetIndexWithMethodReferenceName
|
||||
import app.revanced.util.getWideLiteralInstructionIndex
|
||||
import app.revanced.util.alsoResolve
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.getWalkerMethod
|
||||
import app.revanced.util.indexOfFirstInstruction
|
||||
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.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.Method
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
import com.android.tools.smali.dexlib2.util.MethodUtil
|
||||
|
||||
@Suppress("unused")
|
||||
object FeedComponentsPatch : BaseBytecodePatch(
|
||||
@ -56,7 +66,8 @@ object FeedComponentsPatch : BaseBytecodePatch(
|
||||
NavigationBarHookPatch::class,
|
||||
PlayerTypeHookPatch::class,
|
||||
SettingsPatch::class,
|
||||
SharedResourceIdPatch::class
|
||||
SharedResourceIdPatch::class,
|
||||
BottomSheetHookPatch::class,
|
||||
),
|
||||
compatiblePackages = COMPATIBLE_PACKAGE,
|
||||
fingerprints = setOf(
|
||||
@ -68,14 +79,18 @@ object FeedComponentsPatch : BaseBytecodePatch(
|
||||
ChannelListSubMenuTabletSyntheticFingerprint,
|
||||
ChannelTabRendererFingerprint,
|
||||
ElementParserParentFingerprint,
|
||||
EngagementPanelBuilderFingerprint,
|
||||
FilterBarHeightFingerprint,
|
||||
LatestVideosButtonFingerprint,
|
||||
LinearLayoutManagerItemCountsFingerprint,
|
||||
RelatedChipCloudFingerprint,
|
||||
ScrollTopParentFingerprint,
|
||||
SearchResultsChipBarFingerprint,
|
||||
ShowMoreButtonFingerprint
|
||||
ShowMoreButtonFingerprint,
|
||||
)
|
||||
) {
|
||||
private const val CAROUSEL_SHELF_FILTER_CLASS_DESCRIPTOR =
|
||||
"$COMPONENTS_PATH/CarouselShelfFilter;"
|
||||
private const val FEED_COMPONENTS_FILTER_CLASS_DESCRIPTOR =
|
||||
"$COMPONENTS_PATH/FeedComponentsFilter;"
|
||||
private const val FEED_VIDEO_FILTER_CLASS_DESCRIPTOR =
|
||||
@ -84,6 +99,8 @@ object FeedComponentsPatch : BaseBytecodePatch(
|
||||
"$COMPONENTS_PATH/FeedVideoViewsFilter;"
|
||||
private const val KEYWORD_FILTER_CLASS_DESCRIPTOR =
|
||||
"$COMPONENTS_PATH/KeywordContentFilter;"
|
||||
private const val RELATED_VIDEO_CLASS_DESCRIPTOR =
|
||||
"$FEED_PATH/RelatedVideoPatch;"
|
||||
|
||||
override fun execute(context: BytecodeContext) {
|
||||
|
||||
@ -113,8 +130,8 @@ object FeedComponentsPatch : BaseBytecodePatch(
|
||||
// region patch for hide caption button
|
||||
|
||||
CaptionsButtonFingerprint.resultOrThrow().mutableMethod.apply {
|
||||
val constIndex = getWideLiteralInstructionIndex(CaptionToggleContainer)
|
||||
val insertIndex = getTargetIndexReversedOrThrow(constIndex, Opcode.IF_EQZ)
|
||||
val constIndex = indexOfFirstWideLiteralInstructionValueOrThrow(CaptionToggleContainer)
|
||||
val insertIndex = indexOfFirstInstructionReversedOrThrow(constIndex, Opcode.IF_EQZ)
|
||||
val insertRegister = getInstruction<OneRegisterInstruction>(insertIndex).registerA
|
||||
|
||||
addInstructions(
|
||||
@ -126,8 +143,8 @@ object FeedComponentsPatch : BaseBytecodePatch(
|
||||
}
|
||||
|
||||
CaptionsButtonSyntheticFingerprint.resultOrThrow().mutableMethod.apply {
|
||||
val constIndex = getWideLiteralInstructionIndex(CaptionToggleContainer)
|
||||
val targetIndex = getTargetIndexOrThrow(constIndex, Opcode.MOVE_RESULT_OBJECT)
|
||||
val constIndex = indexOfFirstWideLiteralInstructionValueOrThrow(CaptionToggleContainer)
|
||||
val targetIndex = indexOfFirstInstructionOrThrow(constIndex, Opcode.MOVE_RESULT_OBJECT)
|
||||
val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
|
||||
|
||||
addInstruction(
|
||||
@ -138,6 +155,62 @@ object FeedComponentsPatch : BaseBytecodePatch(
|
||||
|
||||
// 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
|
||||
|
||||
arrayOf(
|
||||
@ -198,7 +271,7 @@ object FeedComponentsPatch : BaseBytecodePatch(
|
||||
&& reference.returnType.startsWith("L")
|
||||
}
|
||||
|
||||
val objectIndex = getTargetIndexOrThrow(Opcode.MOVE_OBJECT)
|
||||
val objectIndex = indexOfFirstInstructionOrThrow(Opcode.MOVE_OBJECT)
|
||||
val objectRegister = getInstruction<TwoRegisterInstruction>(objectIndex).registerA
|
||||
|
||||
val jumpIndex = it.scanResult.patternScanResult!!.startIndex
|
||||
@ -253,7 +326,9 @@ object FeedComponentsPatch : BaseBytecodePatch(
|
||||
|
||||
ChannelTabRendererFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val iteratorIndex = getTargetIndexWithMethodReferenceName("hasNext")
|
||||
val iteratorIndex = indexOfFirstInstructionOrThrow {
|
||||
getReference<MethodReference>()?.name == "hasNext"
|
||||
}
|
||||
val iteratorRegister =
|
||||
getInstruction<FiveRegisterInstruction>(iteratorIndex).registerC
|
||||
|
||||
@ -265,7 +340,8 @@ object FeedComponentsPatch : BaseBytecodePatch(
|
||||
&& reference.parameterTypes == channelTabBuilderMethod.parameterTypes
|
||||
}
|
||||
|
||||
val objectIndex = getTargetIndexReversedOrThrow(targetIndex, Opcode.IGET_OBJECT)
|
||||
val objectIndex =
|
||||
indexOfFirstInstructionReversedOrThrow(targetIndex, Opcode.IGET_OBJECT)
|
||||
val objectInstruction = getInstruction<TwoRegisterInstruction>(objectIndex)
|
||||
val objectReference = getInstruction<ReferenceInstruction>(objectIndex).reference
|
||||
|
||||
@ -285,6 +361,7 @@ object FeedComponentsPatch : BaseBytecodePatch(
|
||||
|
||||
// endregion
|
||||
|
||||
LithoFilterPatch.addFilter(CAROUSEL_SHELF_FILTER_CLASS_DESCRIPTOR)
|
||||
LithoFilterPatch.addFilter(FEED_COMPONENTS_FILTER_CLASS_DESCRIPTOR)
|
||||
LithoFilterPatch.addFilter(FEED_VIDEO_FILTER_CLASS_DESCRIPTOR)
|
||||
LithoFilterPatch.addFilter(FEED_VIDEO_VIEWS_FILTER_CLASS_DESCRIPTOR)
|
||||
|
@ -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
|
||||
}
|
||||
)
|
@ -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;"
|
||||
}
|
||||
)
|
@ -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.integrations.Constants.GENERAL_CLASS_DESCRIPTOR
|
||||
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.patch.BaseBytecodePatch
|
||||
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.OneRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
|
||||
@Suppress("unused")
|
||||
object AudioTracksPatch : BaseBytecodePatch(
|
||||
@ -32,15 +33,14 @@ object AudioTracksPatch : BaseBytecodePatch(
|
||||
opcode == Opcode.CHECK_CAST
|
||||
&& (this as ReferenceInstruction).reference.toString() == "Lcom/google/android/libraries/youtube/innertube/model/media/FormatStreamModel;"
|
||||
}
|
||||
val arrayListIndex = getTargetIndexWithReferenceOrThrow(
|
||||
formatStreamModelIndex,
|
||||
"Ljava/util/List;->add(Ljava/lang/Object;)Z"
|
||||
)
|
||||
val insertIndex =
|
||||
getTargetIndexWithReferenceOrThrow(
|
||||
arrayListIndex,
|
||||
"Ljava/util/List;->isEmpty()Z"
|
||||
) + 2
|
||||
val arrayListIndex = indexOfFirstInstructionOrThrow(formatStreamModelIndex) {
|
||||
opcode == Opcode.INVOKE_INTERFACE &&
|
||||
getReference<MethodReference>()?.toString() == "Ljava/util/List;->add(Ljava/lang/Object;)Z"
|
||||
}
|
||||
val insertIndex = indexOfFirstInstructionOrThrow(arrayListIndex) {
|
||||
opcode == Opcode.INVOKE_INTERFACE &&
|
||||
getReference<MethodReference>()?.toString() == "Ljava/util/List;->isEmpty()Z"
|
||||
} + 2
|
||||
|
||||
val formatStreamModelRegister =
|
||||
getInstruction<OneRegisterInstruction>(formatStreamModelIndex).registerA
|
||||
|
@ -1,57 +1,23 @@
|
||||
package app.revanced.patches.youtube.general.autocaptions
|
||||
|
||||
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.util.smali.ExternalLabel
|
||||
import app.revanced.patches.shared.fingerprints.SubtitleTrackFingerprint
|
||||
import app.revanced.patches.youtube.general.autocaptions.fingerprints.StoryboardRendererDecoderRecommendedLevelFingerprint
|
||||
import app.revanced.patches.shared.captions.BaseAutoCaptionsPatch
|
||||
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.util.patch.BaseBytecodePatch
|
||||
import app.revanced.util.resultOrThrow
|
||||
|
||||
@Suppress("unused")
|
||||
object AutoCaptionsPatch : BaseBytecodePatch(
|
||||
name = "Disable auto captions",
|
||||
description = "Adds an option to disable captions from being automatically enabled.",
|
||||
dependencies = setOf(SettingsPatch::class),
|
||||
compatiblePackages = COMPATIBLE_PACKAGE,
|
||||
fingerprints = setOf(
|
||||
SubtitleTrackFingerprint,
|
||||
StartVideoInformerFingerprint,
|
||||
StoryboardRendererDecoderRecommendedLevelFingerprint,
|
||||
)
|
||||
dependencies = setOf(
|
||||
BaseAutoCaptionsPatch::class,
|
||||
SettingsPatch::class
|
||||
),
|
||||
compatiblePackages = COMPATIBLE_PACKAGE
|
||||
) {
|
||||
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
|
||||
*/
|
||||
|
@ -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.AccountSwitcherAccessibility
|
||||
import app.revanced.patches.youtube.utils.settings.SettingsPatch
|
||||
import app.revanced.util.getTargetIndexOrThrow
|
||||
import app.revanced.util.getTargetIndexWithMethodReferenceName
|
||||
import app.revanced.util.getWideLiteralInstructionIndex
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow
|
||||
import app.revanced.util.patch.BaseBytecodePatch
|
||||
import app.revanced.util.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
@ -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.ReferenceInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
import com.android.tools.smali.dexlib2.util.MethodUtil
|
||||
|
||||
@Suppress("unused")
|
||||
@ -171,10 +172,13 @@ object LayoutComponentsPatch : BaseBytecodePatch(
|
||||
|
||||
AccountSwitcherAccessibilityLabelFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val constIndex = getWideLiteralInstructionIndex(AccountSwitcherAccessibility)
|
||||
val insertIndex = getTargetIndexOrThrow(constIndex, Opcode.IF_EQZ)
|
||||
val setVisibilityIndex =
|
||||
getTargetIndexWithMethodReferenceName(insertIndex, "setVisibility")
|
||||
val constIndex =
|
||||
indexOfFirstWideLiteralInstructionValueOrThrow(AccountSwitcherAccessibility)
|
||||
val insertIndex = indexOfFirstInstructionOrThrow(constIndex, Opcode.IF_EQZ)
|
||||
val setVisibilityIndex = indexOfFirstInstructionOrThrow(insertIndex) {
|
||||
opcode == Opcode.INVOKE_VIRTUAL &&
|
||||
getReference<MethodReference>()?.name == "setVisibility"
|
||||
}
|
||||
val visibilityRegister =
|
||||
getInstruction<FiveRegisterInstruction>(setVisibilityIndex).registerD
|
||||
|
||||
@ -209,8 +213,8 @@ object LayoutComponentsPatch : BaseBytecodePatch(
|
||||
// region patch for hide tooltip content
|
||||
|
||||
TooltipContentFullscreenFingerprint.resultOrThrow().mutableMethod.apply {
|
||||
val literalIndex = getWideLiteralInstructionIndex(45384061)
|
||||
val targetIndex = getTargetIndexOrThrow(literalIndex, Opcode.MOVE_RESULT)
|
||||
val literalIndex = indexOfFirstWideLiteralInstructionValueOrThrow(45384061)
|
||||
val targetIndex = indexOfFirstInstructionOrThrow(literalIndex, Opcode.MOVE_RESULT)
|
||||
val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
|
||||
|
||||
addInstruction(
|
||||
|
@ -19,6 +19,7 @@ import app.revanced.patches.youtube.utils.pip.PiPStateHookPatch
|
||||
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch
|
||||
import app.revanced.patches.youtube.utils.settings.SettingsPatch
|
||||
import app.revanced.util.alsoResolve
|
||||
import app.revanced.util.findMethodOrThrow
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import app.revanced.util.patch.BaseBytecodePatch
|
||||
@ -87,23 +88,22 @@ object DownloadActionsPatch : BaseBytecodePatch(
|
||||
?: throw PatchException("Could not find onClickListenerClass")
|
||||
}
|
||||
|
||||
context.findClass(onClickListenerClass)
|
||||
?.mutableClass
|
||||
?.methods
|
||||
?.first { method -> method.name == "onClick" }?.apply {
|
||||
val insertIndex = indexOfFirstInstructionOrThrow {
|
||||
opcode == Opcode.INVOKE_STATIC
|
||||
&& getReference<MethodReference>()?.name == "isEmpty"
|
||||
}
|
||||
val insertRegister = getInstruction<FiveRegisterInstruction>(insertIndex).registerC
|
||||
context.findMethodOrThrow(onClickListenerClass) {
|
||||
name == "onClick"
|
||||
}.apply {
|
||||
val insertIndex = indexOfFirstInstructionOrThrow {
|
||||
opcode == Opcode.INVOKE_STATIC
|
||||
&& getReference<MethodReference>()?.name == "isEmpty"
|
||||
}
|
||||
val insertRegister = getInstruction<FiveRegisterInstruction>(insertIndex).registerC
|
||||
|
||||
addInstructions(
|
||||
insertIndex, """
|
||||
invoke-static {v$insertRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->inAppPlaylistDownloadButtonOnClick(Ljava/lang/String;)Ljava/lang/String;
|
||||
move-result-object v$insertRegister
|
||||
"""
|
||||
)
|
||||
} ?: throw PatchException("Could not find class $onClickListenerClass")
|
||||
addInstructions(
|
||||
insertIndex, """
|
||||
invoke-static {v$insertRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->inAppPlaylistDownloadButtonOnClick(Ljava/lang/String;)Ljava/lang/String;
|
||||
move-result-object v$insertRegister
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
OfflinePlaylistEndpointFingerprint.resultOrThrow().mutableMethod.apply {
|
||||
val playlistIdParameter = parameterTypes.indexOf("Ljava/lang/String;") + 1
|
||||
@ -176,7 +176,7 @@ object DownloadActionsPatch : BaseBytecodePatch(
|
||||
SettingsPatch.addPreference(
|
||||
arrayOf(
|
||||
"PREFERENCE_SCREEN: GENERAL",
|
||||
"PREFERENCE_CATEGORY: GENERAL_EXPERIMENTAL_FLAGS",
|
||||
"SETTINGS: HOOK_BUTTONS",
|
||||
"SETTINGS: HOOK_DOWNLOAD_ACTIONS"
|
||||
)
|
||||
)
|
||||
|
@ -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.integrations.Constants.GENERAL_CLASS_DESCRIPTOR
|
||||
import app.revanced.patches.youtube.utils.settings.SettingsPatch
|
||||
import app.revanced.util.getTargetIndexOrThrow
|
||||
import app.revanced.util.getTargetIndexReversedOrThrow
|
||||
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
|
||||
import app.revanced.util.patch.BaseBytecodePatch
|
||||
import app.revanced.util.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
@ -34,7 +33,7 @@ object LayoutSwitchPatch : BaseBytecodePatch(
|
||||
|
||||
GetFormFactorFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val jumpIndex = getTargetIndexReversedOrThrow(Opcode.SGET_OBJECT)
|
||||
val jumpIndex = indexOfFirstInstructionReversedOrThrow(Opcode.SGET_OBJECT)
|
||||
|
||||
addInstructionsWithLabels(
|
||||
0, """
|
||||
@ -56,7 +55,7 @@ object LayoutSwitchPatch : BaseBytecodePatch(
|
||||
|
||||
LayoutSwitchFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val insertIndex = getTargetIndexOrThrow(Opcode.IF_NEZ)
|
||||
val insertIndex = indexOfFirstInstructionReversedOrThrow(Opcode.IF_NEZ)
|
||||
val insertRegister = getInstruction<OneRegisterInstruction>(insertIndex).registerA
|
||||
|
||||
addInstructions(
|
||||
|
@ -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.integrations.Constants.GENERAL_CLASS_DESCRIPTOR
|
||||
import app.revanced.patches.youtube.utils.settings.SettingsPatch
|
||||
import app.revanced.util.literalInstructionBooleanHook
|
||||
import app.revanced.util.injectLiteralInstructionBooleanCall
|
||||
import app.revanced.util.patch.BaseBytecodePatch
|
||||
|
||||
@Suppress("unused")
|
||||
@ -29,7 +29,7 @@ object GradientLoadingScreenPatch : BaseBytecodePatch(
|
||||
GradientLoadingScreenPrimaryFingerprint to 45412406,
|
||||
GradientLoadingScreenSecondaryFingerprint to 45418917
|
||||
).forEach { (fingerprint, literal) ->
|
||||
fingerprint.literalInstructionBooleanHook(
|
||||
fingerprint.injectLiteralInstructionBooleanCall(
|
||||
literal,
|
||||
"$GENERAL_CLASS_DESCRIPTOR->enableGradientLoadingScreen()Z"
|
||||
)
|
||||
|
@ -44,8 +44,8 @@ import app.revanced.util.fingerprint.LiteralValueFingerprint
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.getWalkerMethod
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import app.revanced.util.indexOfWideLiteralInstructionOrThrow
|
||||
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.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
@ -170,7 +170,7 @@ object MiniplayerPatch : BaseBytecodePatch(
|
||||
}
|
||||
|
||||
if (SettingsPatch.upward1925) {
|
||||
MiniplayerModernEnabledFingerprint.literalInstructionBooleanHook(
|
||||
MiniplayerModernEnabledFingerprint.injectLiteralInstructionBooleanCall(
|
||||
45622882,
|
||||
"$INTEGRATIONS_CLASS_DESCRIPTOR->getModernMiniplayerOverride(Z)Z"
|
||||
)
|
||||
@ -181,11 +181,11 @@ object MiniplayerPatch : BaseBytecodePatch(
|
||||
// region Enable double tap action.
|
||||
|
||||
if (SettingsPatch.upward1925) {
|
||||
MiniplayerModernConstructorFingerprint.literalInstructionBooleanHook(
|
||||
MiniplayerModernConstructorFingerprint.injectLiteralInstructionBooleanCall(
|
||||
45628823,
|
||||
"$INTEGRATIONS_CLASS_DESCRIPTOR->enableMiniplayerDoubleTapAction()Z"
|
||||
)
|
||||
MiniplayerModernConstructorFingerprint.literalInstructionBooleanHook(
|
||||
MiniplayerModernConstructorFingerprint.injectLiteralInstructionBooleanCall(
|
||||
45630429,
|
||||
"$INTEGRATIONS_CLASS_DESCRIPTOR->getModernMiniplayerOverride(Z)Z"
|
||||
)
|
||||
@ -211,7 +211,8 @@ object MiniplayerPatch : BaseBytecodePatch(
|
||||
YtOutlinePictureInPictureWhite to YtOutlineXWhite,
|
||||
YtOutlineXWhite to YtOutlinePictureInPictureWhite,
|
||||
).forEach { (originalResource, replacementResource) ->
|
||||
val imageResourceIndex = indexOfWideLiteralInstructionOrThrow(originalResource)
|
||||
val imageResourceIndex =
|
||||
indexOfFirstWideLiteralInstructionValueOrThrow(originalResource)
|
||||
val register =
|
||||
getInstruction<OneRegisterInstruction>(imageResourceIndex).registerA
|
||||
|
||||
@ -321,7 +322,7 @@ object MiniplayerPatch : BaseBytecodePatch(
|
||||
// region Enable drag and drop.
|
||||
|
||||
if (SettingsPatch.upward1923) {
|
||||
MiniplayerModernDragAndDropFingerprint.literalInstructionBooleanHook(
|
||||
MiniplayerModernDragAndDropFingerprint.injectLiteralInstructionBooleanCall(
|
||||
45628752,
|
||||
"$INTEGRATIONS_CLASS_DESCRIPTOR->enableMiniplayerDragAndDrop()Z"
|
||||
)
|
||||
@ -388,7 +389,7 @@ object MiniplayerPatch : BaseBytecodePatch(
|
||||
) {
|
||||
resultOrThrow().mutableMethod.apply {
|
||||
val imageViewIndex = indexOfFirstInstructionOrThrow(
|
||||
indexOfWideLiteralInstructionOrThrow(literalValue)
|
||||
indexOfFirstWideLiteralInstructionValueOrThrow(literalValue)
|
||||
) {
|
||||
opcode == Opcode.CHECK_CAST && getReference<TypeReference>()?.type == hookedClassType
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import app.revanced.patches.youtube.general.miniplayer.fingerprints.MiniplayerModernConstructorFingerprint.constructorMethodCount
|
||||
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.util.MethodUtil
|
||||
|
||||
@ -13,7 +13,7 @@ internal object MiniplayerModernConstructorFingerprint : MethodFingerprint(
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
|
||||
parameters = listOf("L"),
|
||||
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
|
||||
|
||||
classDef.methods.forEach {
|
||||
@ -24,8 +24,8 @@ internal object MiniplayerModernConstructorFingerprint : MethodFingerprint(
|
||||
return@custom true
|
||||
|
||||
// Double tap action (Used in YouTube 19.25.39+).
|
||||
methodDef.containsWideLiteralInstructionIndex(45628823)
|
||||
&& methodDef.containsWideLiteralInstructionIndex(45630429)
|
||||
methodDef.containsWideLiteralInstructionValue(45628823)
|
||||
&& methodDef.containsWideLiteralInstructionValue(45630429)
|
||||
}
|
||||
) {
|
||||
private var constructorMethodCount = 0
|
||||
|
@ -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
Loading…
x
Reference in New Issue
Block a user