From ac5b65fcb59fd552b8e71d832da7435d4013d678 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Wed, 28 Jan 2026 13:34:35 +0100 Subject: [PATCH] some more progress --- .../license/DisableLicenseCheckPatch.kt | 6 +- .../misc/pairip/license/Fingerprints.kt | 21 +-- .../shared/misc/settings/Fingerprints.kt | 17 ++- .../patches/shared/misc/spoof/Fingerprints.kt | 30 ++-- .../misc/spoof/SpoofVideoStreamsPatch.kt | 18 ++- .../functionality/filesize/Fingerprints.kt | 5 +- .../filesize/RemoveFileSizeLimitPatch.kt | 8 +- .../spotify/layout/theme/CustomThemePatch.kt | 39 ++--- .../spotify/layout/theme/Fingerprints.kt | 25 +-- .../spotify/misc/extension/Fingerprints.kt | 11 +- .../patches/spotify/misc/extension/Hooks.kt | 4 +- .../spotify/misc/fix/login/Fingerprints.kt | 16 +- .../misc/fix/login/FixFacebookLoginPatch.kt | 11 +- .../misc/lyrics/ChangeLyricsProviderPatch.kt | 20 +-- .../spotify/misc/lyrics/Fingerprints.kt | 15 +- .../tumblr/featureflags/Fingerprints.kt | 6 +- .../featureflags/OverrideFeatureFlagsPatch.kt | 142 +++++++++--------- .../patches/tumblr/fixes/Fingerprints.kt | 19 ++- .../tumblr/fixes/FixOldVersionsPatch.kt | 4 +- .../FilterTimelineObjectsPatch.kt | 8 +- .../tumblr/timelinefilter/Fingerprints.kt | 24 ++- .../interaction/downloads/Fingerprints.kt | 12 +- .../downloads/UnlockDownloadsPatch.kt | 9 +- .../youtube/ad/getpremium/Fingerprints.kt | 15 +- .../ad/getpremium/HideGetPremiumPatch.kt | 10 +- .../interaction/dialog/Fingerprints.kt | 16 +- .../RemoveViewerDiscretionDialogPatch.kt | 4 +- .../seekbar/EnableSeekbarTappingPatch.kt | 4 +- .../seekbar/EnableSlideToSeekPatch.kt | 13 +- .../interaction/seekbar/Fingerprints.kt | 10 +- .../interaction/swipecontrols/Fingerprints.kt | 8 +- .../swipecontrols/SwipeControlsPatch.kt | 4 +- .../hide/endscreencards/Fingerprints.kt | 26 ++-- .../endscreencards/HideEndScreenCardsPatch.kt | 12 +- .../hide/endscreensuggestion/Fingerprints.kt | 31 ++-- .../HideEndScreenSuggestedVideoPatch.kt | 13 +- .../layout/hide/general/Fingerprints.kt | 58 +++---- .../hide/general/HideLayoutComponentsPatch.kt | 99 ++++++------ .../layout/hide/infocards/Fingerprints.kt | 34 ++--- .../hide/infocards/HideInfoCardsPatch.kt | 10 +- .../DisableRollingNumberAnimationPatch.kt | 4 +- .../youtube/layout/miniplayer/Fingerprints.kt | 59 ++++---- .../layout/miniplayer/MiniplayerPatch.kt | 90 +++++------ .../layout/player/fullscreen/Fingerprints.kt | 4 +- .../OpenVideosFullscreenHookPatch.kt | 33 ++-- .../CustomPlayerOverlayOpacityPatch.kt | 2 +- .../layout/player/overlay/Fingerprints.kt | 11 +- .../returnyoutubedislike/Fingerprints.kt | 83 +++++----- .../ReturnYouTubeDislikePatch.kt | 44 +++--- .../youtube/layout/seekbar/Fingerprints.kt | 51 +++---- .../layout/seekbar/SeekbarColorPatch.kt | 68 ++++----- .../layout/shortsautoplay/Fingerprints.kt | 28 ++-- .../shortsautoplay/ShortsAutoplayPatch.kt | 17 ++- .../layout/spoofappversion/Fingerprints.kt | 4 +- .../spoofappversion/SpoofAppVersionPatch.kt | 20 +-- .../DisableResumingShortsOnStartupPatch.kt | 12 +- .../layout/startupshortsreset/Fingerprints.kt | 17 +-- .../youtube/layout/theme/ThemePatch.kt | 3 +- .../BackgroundPlaybackPatch.kt | 13 +- .../misc/backgroundplayback/Fingerprints.kt | 27 ++-- ...ckWatchHistoryDomainNameResolutionPatch.kt | 4 +- .../fix/backtoexitgesture/Fingerprints.kt | 19 +-- .../misc/fix/playbackspeed/Fingerprints.kt | 8 +- .../youtube/misc/litho/filter/Fingerprints.kt | 27 ++-- .../misc/litho/filter/LithoFilterPatch.kt | 11 +- .../youtube/misc/navigation/Fingerprints.kt | 78 +++++----- .../misc/navigation/NavigationBarHookPatch.kt | 91 +++++------ .../misc/playercontrols/Fingerprints.kt | 2 +- .../PlayerControlsOverlayVisibilityPatch.kt | 2 +- .../recyclerviewtree/hook/Fingerprints.kt | 6 +- .../hook/RecyclerViewTreeHookPatch.kt | 6 +- .../misc/spoof/SpoofVideoStreamsPatch.kt | 4 +- .../patches/youtube/shared/Fingerprints.kt | 2 +- .../video/audio/ForceOriginalAudioPatch.kt | 4 +- .../youtube/video/codecs/Fingerprints.kt | 10 +- .../video/playerresponse/Fingerprints.kt | 14 +- .../PlayerResponseMethodHookPatch.kt | 18 +-- .../quality/AdvancedVideoQualityMenuPatch.kt | 4 +- 78 files changed, 798 insertions(+), 939 deletions(-) diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/misc/pairip/license/DisableLicenseCheckPatch.kt b/patches/src/main/kotlin/app/revanced/patches/shared/misc/pairip/license/DisableLicenseCheckPatch.kt index 4bd3c25fb..8a6d18010 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/misc/pairip/license/DisableLicenseCheckPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/misc/pairip/license/DisableLicenseCheckPatch.kt @@ -12,15 +12,15 @@ val `Disable Pairip license check` by creatingBytecodePatch( ) { apply { - if (processLicenseResponseMethodOrNull == null || validateLicenseResponseMethodOrNull == null) { + if (processLicenseResponseMethod == null || validateLicenseResponseMethod == null) { return@apply Logger.getLogger(this::class.java.name) .warning("Could not find Pairip licensing check. No changes applied.") } // Set first parameter (responseCode) to 0 (success status). - processLicenseResponseMethod.addInstruction(0, "const/4 p1, 0x0") + processLicenseResponseMethod!!.addInstruction(0, "const/4 p1, 0x0") // Short-circuit the license response validation. - validateLicenseResponseMethod.returnEarly() + validateLicenseResponseMethod!!.returnEarly() } } diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/misc/pairip/license/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/shared/misc/pairip/license/Fingerprints.kt index 09375f3ed..2c83dfad2 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/misc/pairip/license/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/misc/pairip/license/Fingerprints.kt @@ -1,15 +1,16 @@ package app.revanced.patches.shared.misc.pairip.license -internal val BytecodePatchContext.processLicenseResponseMethod by gettingFirstMethodDeclaratively { - custom { method, classDef -> - classDef.type == "Lcom/pairip/licensecheck/LicenseClient;" && - method.name == "processResponse" - } +import app.revanced.patcher.definingClass +import app.revanced.patcher.gettingFirstMutableMethodDeclarativelyOrNull +import app.revanced.patcher.name +import app.revanced.patcher.patch.BytecodePatchContext + +internal val BytecodePatchContext.processLicenseResponseMethod by gettingFirstMutableMethodDeclarativelyOrNull { + name("processResponse") + definingClass("Lcom/pairip/licensecheck/LicenseClient;") } -internal val BytecodePatchContext.validateLicenseResponseMethod by gettingFirstMethodDeclaratively { - custom { method, classDef -> - classDef.type == "Lcom/pairip/licensecheck/ResponseValidator;" && - method.name == "validateResponse" - } +internal val BytecodePatchContext.validateLicenseResponseMethod by gettingFirstMutableMethodDeclarativelyOrNull { + name("validateResponse") + definingClass("Lcom/pairip/licensecheck/ResponseValidator;") } diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/misc/settings/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/shared/misc/settings/Fingerprints.kt index d61b92c3a..a1566c23f 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/misc/settings/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/misc/settings/Fingerprints.kt @@ -1,27 +1,28 @@ package app.revanced.patches.shared.misc.settings import app.revanced.patcher.accessFlags +import app.revanced.patcher.definingClass import app.revanced.patcher.gettingFirstMethodDeclaratively +import app.revanced.patcher.gettingFirstMutableMethodDeclaratively +import app.revanced.patcher.name import app.revanced.patcher.parameterTypes import app.revanced.patcher.patch.BytecodePatchContext import app.revanced.patcher.returnType import app.revanced.patches.shared.misc.extension.EXTENSION_CLASS_DESCRIPTOR import com.android.tools.smali.dexlib2.AccessFlags -internal val BytecodePatchContext.themeLightColorResourceNameMethod by gettingFirstMethodDeclaratively { +internal val BytecodePatchContext.themeLightColorResourceNameMethod by gettingFirstMutableMethodDeclaratively { + name("getThemeLightColorResourceName") + definingClass(EXTENSION_CLASS_DESCRIPTOR) accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC) returnType("Ljava/lang/String;") parameterTypes() - custom { method, classDef -> - method.name == "getThemeLightColorResourceName" && classDef.type == EXTENSION_CLASS_DESCRIPTOR - } } -internal val BytecodePatchContext.themeDarkColorResourceNameMethod by gettingFirstMethodDeclaratively { +internal val BytecodePatchContext.themeDarkColorResourceNameMethod by gettingFirstMutableMethodDeclaratively { + name("getThemeDarkColorResourceName") + definingClass(EXTENSION_CLASS_DESCRIPTOR) accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC) returnType("Ljava/lang/String;") parameterTypes() - custom { method, classDef -> - method.name == "getThemeDarkColorResourceName" && classDef.type == EXTENSION_CLASS_DESCRIPTOR - } } diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/misc/spoof/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/shared/misc/spoof/Fingerprints.kt index 2583e721a..40adaa3d8 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/misc/spoof/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/misc/spoof/Fingerprints.kt @@ -2,13 +2,16 @@ package app.revanced.patches.shared.misc.spoof import app.revanced.patcher.accessFlags import app.revanced.patcher.custom +import app.revanced.patcher.definingClass import app.revanced.patcher.extensions.methodReference import app.revanced.patcher.firstMethodComposite import app.revanced.patcher.gettingFirstMethodDeclaratively +import app.revanced.patcher.gettingFirstMutableMethodDeclaratively import app.revanced.patcher.immutableClassDef import app.revanced.patcher.instructions import app.revanced.patcher.invoke import app.revanced.patcher.method +import app.revanced.patcher.name import app.revanced.patcher.opcodes import app.revanced.patcher.parameterTypes import app.revanced.patcher.patch.BytecodePatchContext @@ -77,12 +80,13 @@ internal val buildRequestMethodMatch = firstMethodComposite { val parameterTypes = parameterTypes val parameterTypesSize = parameterTypes.size (parameterTypesSize == 6 || parameterTypesSize == 7 || parameterTypesSize == 8) && - parameterTypes[1] == "Ljava/util/Map;" && // URL headers. - indexOfNewUrlRequestBuilderInstruction(this) >= 0 + parameterTypes[1] == "Ljava/util/Map;" && // URL headers. + indexOfNewUrlRequestBuilderInstruction(this) >= 0 } } internal val BytecodePatchContext.protobufClassParseByteBufferMethod by gettingFirstMethodDeclaratively { + name("parseFrom") accessFlags(AccessFlags.PROTECTED, AccessFlags.STATIC) returnType("L") parameterTypes("L", "Ljava/nio/ByteBuffer;") @@ -92,7 +96,6 @@ internal val BytecodePatchContext.protobufClassParseByteBufferMethod by gettingF Opcode.MOVE_RESULT_OBJECT, Opcode.RETURN_OBJECT, ) - custom { method, _ -> method.name == "parseFrom" } } internal val createStreamingDataMethodMatch = firstMethodComposite { @@ -112,7 +115,7 @@ internal val createStreamingDataMethodMatch = firstMethodComposite { } } -internal val BytecodePatchContext.buildMediaDataSourceMethod by gettingFirstMethodDeclaratively { +internal val BytecodePatchContext.buildMediaDataSourceMethod by gettingFirstMutableMethodDeclaratively { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) parameterTypes( "Landroid/net/Uri;", @@ -147,7 +150,7 @@ internal val mediaFetchEnumConstructorMethodMatch = firstMethodComposite { ) } -internal val BytecodePatchContext.nerdsStatsVideoFormatBuilderMethod by gettingFirstMethodDeclaratively { +internal val BytecodePatchContext.nerdsStatsVideoFormatBuilderMethod by gettingFirstMutableMethodDeclaratively { accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) returnType("Ljava/lang/String;") parameterTypes("L") @@ -156,12 +159,11 @@ internal val BytecodePatchContext.nerdsStatsVideoFormatBuilderMethod by gettingF ) } -internal val BytecodePatchContext.patchIncludedExtensionMethodMethod by gettingFirstMethodDeclaratively { +internal val BytecodePatchContext.patchIncludedExtensionMethodMethod by gettingFirstMutableMethodDeclaratively { + name("isPatchIncluded") + definingClass(EXTENSION_CLASS_DESCRIPTOR) returnType("Z") parameterTypes() - custom { method, classDef -> - method.name == "isPatchIncluded" && classDef.type == EXTENSION_CLASS_DESCRIPTOR - } } // Feature flag that turns on Platypus programming language code compiled to native C++. @@ -192,9 +194,9 @@ internal fun indexOfNewUrlRequestBuilderInstruction(method: Method) = method.ind val reference = methodReference ?: return@indexOfFirstInstruction false opcode == Opcode.INVOKE_VIRTUAL && reference.definingClass == "Lorg/chromium/net/CronetEngine;" && - reference.name == "newUrlRequestBuilder" && - reference.parameterTypes.size == 3 && - reference.parameterTypes[0] == "Ljava/lang/String;" && - reference.parameterTypes[1] == "Lorg/chromium/net/UrlRequest\$Callback;" && - reference.parameterTypes[2] == "Ljava/util/concurrent/Executor;" + reference.name == "newUrlRequestBuilder" && + reference.parameterTypes.size == 3 && + reference.parameterTypes[0] == "Ljava/lang/String;" && + reference.parameterTypes[1] == "Lorg/chromium/net/UrlRequest\$Callback;" && + reference.parameterTypes[2] == "Ljava/util/concurrent/Executor;" } diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/misc/spoof/SpoofVideoStreamsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/shared/misc/spoof/SpoofVideoStreamsPatch.kt index 8d1ab1715..fde3bfc62 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/misc/spoof/SpoofVideoStreamsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/misc/spoof/SpoofVideoStreamsPatch.kt @@ -1,9 +1,13 @@ package app.revanced.patches.shared.misc.spoof +import app.revanced.patcher.custom import app.revanced.patcher.extensions.* +import app.revanced.patcher.firstMutableMethodDeclaratively +import app.revanced.patcher.opcodes import app.revanced.patcher.patch.BytecodePatchBuilder import app.revanced.patcher.patch.BytecodePatchContext import app.revanced.patcher.patch.bytecodePatch +import app.revanced.patcher.returnType import app.revanced.patches.all.misc.resources.addResources import app.revanced.patches.all.misc.resources.addResourcesPatch import app.revanced.util.* @@ -124,7 +128,7 @@ internal fun spoofVideoStreamsPatch( addInstruction( videoDetailsIndex + 1, "invoke-direct { p0, v$videoDetailsRegister }, " + - "$resultMethodType->$setStreamDataMethodName($videoDetailsClass)V", + "$resultMethodType->$setStreamDataMethodName($videoDetailsClass)V", ) val protobufClass = protobufClassParseByteBufferMethod.definingClass @@ -212,7 +216,7 @@ internal fun spoofVideoStreamsPatch( // A proper fix may include modifying the request body to match the platforms expected body. buildMediaDataSourceMethod.apply { - val targetIndex = instructions.lastIndex + val targetIndex = instructions.count() - 1 // Instructions are added just before the method returns, // so there's no concern of clobbering in-use registers. @@ -271,7 +275,7 @@ internal fun spoofVideoStreamsPatch( val mediaFetchEnumClass = definingClass val sabrFieldIndex = indexOfFirstInstructionOrThrow(disabledBySABRStreamingUrlString) { opcode == Opcode.SPUT_OBJECT && - getReference()?.type == mediaFetchEnumClass + getReference()?.type == mediaFetchEnumClass } Pair( @@ -280,17 +284,15 @@ internal fun spoofVideoStreamsPatch( ) } - val sabrFingerprint = fingerprint { + val sabrMethod = firstMutableMethodDeclaratively { returnType(mediaFetchEnumClass) opcodes( Opcode.SGET_OBJECT, Opcode.RETURN_OBJECT, ) - custom { method, _ -> - !method.parameterTypes.isEmpty() - } + custom { parameterTypes.isEmpty() } } - sabrFingerprint.method.addInstructionsWithLabels( + sabrMethod.addInstructionsWithLabels( 0, """ invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->disableSABR()Z diff --git a/patches/src/main/kotlin/app/revanced/patches/solidexplorer2/functionality/filesize/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/solidexplorer2/functionality/filesize/Fingerprints.kt index 8418844fd..d53aba8a2 100644 --- a/patches/src/main/kotlin/app/revanced/patches/solidexplorer2/functionality/filesize/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/solidexplorer2/functionality/filesize/Fingerprints.kt @@ -1,13 +1,12 @@ package app.revanced.patches.solidexplorer2.functionality.filesize import app.revanced.patcher.definingClass -import app.revanced.patcher.gettingFirstMutableMethodDeclaratively +import app.revanced.patcher.firstMethodComposite import app.revanced.patcher.name import app.revanced.patcher.opcodes -import app.revanced.patcher.patch.BytecodePatchContext import com.android.tools.smali.dexlib2.Opcode -internal val BytecodePatchContext.onReadyMethod by gettingFirstMutableMethodDeclaratively { +internal val onReadyMethodMatch = firstMethodComposite { name("onReady") definingClass("Lpl/solidexplorer/plugins/texteditor/TextEditor;") opcodes( diff --git a/patches/src/main/kotlin/app/revanced/patches/solidexplorer2/functionality/filesize/RemoveFileSizeLimitPatch.kt b/patches/src/main/kotlin/app/revanced/patches/solidexplorer2/functionality/filesize/RemoveFileSizeLimitPatch.kt index 8fbf93254..aed19637e 100644 --- a/patches/src/main/kotlin/app/revanced/patches/solidexplorer2/functionality/filesize/RemoveFileSizeLimitPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/solidexplorer2/functionality/filesize/RemoveFileSizeLimitPatch.kt @@ -12,11 +12,11 @@ val `Remove file size limit` by creatingBytecodePatch( compatibleWith("pl.solidexplorer2") apply { - onReadyMethod.apply { - val cmpIndex = onReadyMethod.indices.first() + 1 // TODO - val cmpResultRegister = getInstruction(cmpIndex).registerA + onReadyMethodMatch.let { + val cmpIndex = it.indices.first() + 1 + val cmpResultRegister = it.method.getInstruction(cmpIndex).registerA - replaceInstruction(cmpIndex, "const/4 v$cmpResultRegister, 0x0") + it.method.replaceInstruction(cmpIndex, "const/4 v$cmpResultRegister, 0x0") } } } diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/layout/theme/CustomThemePatch.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/layout/theme/CustomThemePatch.kt index 028355fbd..6b859d3e0 100644 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/layout/theme/CustomThemePatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/spotify/layout/theme/CustomThemePatch.kt @@ -2,6 +2,7 @@ package app.revanced.patches.spotify.layout.theme import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.getInstruction +import app.revanced.patcher.immutableClassDef import app.revanced.patcher.patch.booleanOption import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.resourcePatch @@ -22,7 +23,7 @@ private val customThemeBytecodePatch = bytecodePatch { val colorSpaceUtilsClassDef = colorSpaceUtilsClassMethod.immutableClassDef // Hook a util method that converts ARGB to RGBA in the sRGB color space to replace hardcoded accent colors. - convertArgbToRgbaMethod.match(colorSpaceUtilsClassDef).method.apply { + colorSpaceUtilsClassDef.getConvertArgbToRgbaMethod().apply { addInstructions( 0, """ @@ -40,7 +41,7 @@ private val customThemeBytecodePatch = bytecodePatch { val invokeParseColorIndex = indexOfFirstInstructionOrThrow { val reference = getReference() reference?.definingClass == "Landroid/graphics/Color;" && - reference.name == "parseColor" + reference.name == "parseColor" } val parsedColorRegister = getInstruction(invokeParseColorIndex + 1).registerA @@ -61,7 +62,7 @@ private val customThemeBytecodePatch = bytecodePatch { val invokeArgbIndex = indexOfFirstInstructionOrThrow { val reference = getReference() reference?.definingClass == "Landroid/graphics/Color;" && - reference.name == "argb" + reference.name == "argb" } val argbColorRegister = getInstruction(invokeArgbIndex + 1).registerA @@ -97,7 +98,7 @@ val customThemePatch = resourcePatch( default = false, name = "Override player gradient color", description = - "Apply primary background color to the player gradient color, which changes dynamically with the song.", + "Apply primary background color to the player gradient color, which changes dynamically with the song.", required = false, ) @@ -105,7 +106,7 @@ val customThemePatch = resourcePatch( default = "#FF121212", name = "Secondary background color", description = "The secondary background color. (e.g. playlist list in home, player artist, song credits). " + - "Can be a hex color or a resource reference.\",", + "Can be a hex color or a resource reference.\",", required = true, ) @@ -120,7 +121,7 @@ val customThemePatch = resourcePatch( default = "#FF1ABC54", name = "Pressed accent color", description = "The color when accented buttons are pressed, by default slightly darker than accent. " + - "Can be a hex color or a resource reference.", + "Can be a hex color or a resource reference.", required = true, ) @@ -143,38 +144,38 @@ val customThemePatch = resourcePatch( node.textContent = when (name) { // Main background color. "gray_7", - // Left sidebar background color in tablet mode. + // Left sidebar background color in tablet mode. "gray_10", - // Gradient next to user photo and "All" in home page. + // Gradient next to user photo and "All" in home page. "dark_base_background_base", - // "Add account", "Settings and privacy", "View Profile" left sidebar background color. + // "Add account", "Settings and privacy", "View Profile" left sidebar background color. "dark_base_background_elevated_base", - // Song/player gradient start/end color. + // Song/player gradient start/end color. "bg_gradient_start_color", "bg_gradient_end_color", - // Login screen background color and gradient start. + // Login screen background color and gradient start. "sthlm_blk", "sthlm_blk_grad_start", - // Misc. + // Misc. "image_placeholder_color", - -> backgroundColor + -> backgroundColor // "About the artist" background color in song player. "gray_15", - // Track credits, merch background color in song player. + // Track credits, merch background color in song player. "track_credits_card_bg", "benefit_list_default_color", "merch_card_background", - // Playlist list background in home page. + // Playlist list background in home page. "opacity_white_10", - // "What's New" pills background. + // "What's New" pills background. "dark_base_background_tinted_highlight", - -> backgroundColorSecondary + -> backgroundColorSecondary "dark_brightaccent_background_base", "dark_base_text_brightaccent", "green_light", "spotify_green_157", - -> accentColor + -> accentColor "dark_brightaccent_background_press", - -> accentColorPressed + -> accentColorPressed else -> continue } diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/layout/theme/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/layout/theme/Fingerprints.kt index f94614376..5a76d1aa8 100644 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/layout/theme/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/spotify/layout/theme/Fingerprints.kt @@ -1,32 +1,35 @@ package app.revanced.patches.spotify.layout.theme import app.revanced.patcher.accessFlags +import app.revanced.patcher.firstMutableMethodDeclaratively +import app.revanced.patcher.gettingFirstMethod import app.revanced.patcher.gettingFirstMethodDeclaratively +import app.revanced.patcher.gettingFirstMutableMethod +import app.revanced.patcher.gettingFirstMutableMethodDeclaratively +import app.revanced.patcher.instructions +import app.revanced.patcher.invoke import app.revanced.patcher.parameterTypes import app.revanced.patcher.patch.BytecodePatchContext import app.revanced.patcher.returnType -import app.revanced.util.containsLiteralInstruction +import app.revanced.patcher.unorderedAllOf import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.iface.ClassDef internal val BytecodePatchContext.colorSpaceUtilsClassMethod by gettingFirstMethodDeclaratively { - strings("The specified color must be encoded in an RGB color space.") // Partial string match. + instructions("The specified color must be encoded in an RGB color space."(String::contains)) } -internal val BytecodePatchContext.convertArgbToRgbaMethod by gettingFirstMethodDeclaratively { +context(_: BytecodePatchContext) +internal fun ClassDef.getConvertArgbToRgbaMethod() = firstMutableMethodDeclaratively { accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC, AccessFlags.FINAL) returnType("J") parameterTypes("J") } -internal val BytecodePatchContext.parseLottieJsonMethod by gettingFirstMethodDeclaratively { - strings("Unsupported matte type: ") -} +internal val BytecodePatchContext.parseLottieJsonMethod by gettingFirstMutableMethod("Unsupported matte type: ") -internal val BytecodePatchContext.parseAnimatedColorMethod by gettingFirstMethodDeclaratively { +internal val BytecodePatchContext.parseAnimatedColorMethod by gettingFirstMutableMethodDeclaratively { parameterTypes("L", "F") returnType("Ljava/lang/Object;") - custom { method, _ -> - method.containsLiteralInstruction(255.0) && - method.containsLiteralInstruction(1.0) - } + instructions(predicates = unorderedAllOf(255.0.toRawBits()(), 1.0.toRawBits()())) } diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/extension/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/extension/Fingerprints.kt index 9392830d2..7d18ae7c2 100644 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/extension/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/extension/Fingerprints.kt @@ -1,5 +1,12 @@ package app.revanced.patches.spotify.misc.extension -internal val BytecodePatchContext.loadOrbitLibraryMethod by gettingFirstMethodDeclaratively { - strings("orbit_library_load", "orbit-jni-spotify") +import app.revanced.patcher.firstMethodComposite +import app.revanced.patcher.instructions +import app.revanced.patcher.invoke + +internal val loadOrbitLibraryMethodMatch = firstMethodComposite { + instructions( + "orbit_library_load"(), + "orbit-jni-spotify"() + ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/extension/Hooks.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/extension/Hooks.kt index 7ccbe492b..efee1d891 100644 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/extension/Hooks.kt +++ b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/extension/Hooks.kt @@ -14,7 +14,7 @@ internal val loadOrbitLibraryHook = extensionHook { // FIXME: Creating this is a mess and needs refactoring. extensionHook( getInsertIndex = { - loadOrbitLibraryMethod.stringMatches.last().index + loadOrbitLibraryMethodMatch.stringMatches.last().index }, getContextRegister = { method -> val contextReferenceIndex = method.indexOfFirstInstruction { @@ -25,6 +25,6 @@ internal val loadOrbitLibraryHook = extensionHook { "v$contextRegister" }, - fingerprint = loadOrbitLibraryMethod, + fingerprint = loadOrbitLibraryMethodMatch, ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/fix/login/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/fix/login/Fingerprints.kt index 2ba7d38bf..26221dd3a 100644 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/fix/login/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/fix/login/Fingerprints.kt @@ -1,14 +1,18 @@ package app.revanced.patches.spotify.misc.fix.login +import app.revanced.patcher.firstMutableMethodDeclaratively +import app.revanced.patcher.gettingFirstMethod import app.revanced.patcher.gettingFirstMethodDeclaratively +import app.revanced.patcher.gettingFirstMutableMethod +import app.revanced.patcher.instructions +import app.revanced.patcher.invoke import app.revanced.patcher.literal import app.revanced.patcher.patch.BytecodePatchContext +import com.android.tools.smali.dexlib2.iface.ClassDef -internal val BytecodePatchContext.katanaProxyLoginMethodHandlerClassMethod by gettingFirstMethodDeclaratively { - strings("katana_proxy_auth") -} +internal val BytecodePatchContext.katanaProxyLoginMethodHandlerClassMethod by gettingFirstMethod("katana_proxy_auth") -internal val BytecodePatchContext.katanaProxyLoginMethodTryAuthorizeMethod by gettingFirstMethodDeclaratively { - strings("e2e") - literal { 0 } +context(_: BytecodePatchContext) +internal fun ClassDef.getKatanaProxyLoginMethodTryAuthorizeMethod() = firstMutableMethodDeclaratively("e2e") { + instructions(0L()) } diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/fix/login/FixFacebookLoginPatch.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/fix/login/FixFacebookLoginPatch.kt index 39bc134d5..8528a5b66 100644 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/fix/login/FixFacebookLoginPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/fix/login/FixFacebookLoginPatch.kt @@ -1,12 +1,13 @@ package app.revanced.patches.spotify.misc.fix.login +import app.revanced.patcher.immutableClassDef import app.revanced.patcher.patch.creatingBytecodePatch import app.revanced.util.returnEarly @Suppress("unused", "ObjectPropertyName") val `Fix Facebook login` by creatingBytecodePatch( description = - "Fix logging in with Facebook when the app is patched by always opening the login in a web browser window.", + "Fix logging in with Facebook when the app is patched by always opening the login in a web browser window.", ) { compatibleWith("com.spotify.music") @@ -16,13 +17,9 @@ val `Fix Facebook login` by creatingBytecodePatch( // which ends up making the Facebook server reject with an invalid key hash for the app signature. // Override the Facebook SDK to always handle the login using the web browser, which does not perform // signature checks. - - val katanaProxyLoginMethodHandlerClass = katanaProxyLoginMethodHandlerClassMethod.immutableClassDef // Always return 0 (no Intent was launched) as the result of trying to authorize with the Facebook app to // make the login fallback to a web browser window. - katanaProxyLoginMethodTryAuthorizeMethod - .match(katanaProxyLoginMethodHandlerClass) - .method - .returnEarly(0) + katanaProxyLoginMethodHandlerClassMethod.immutableClassDef + .getKatanaProxyLoginMethodTryAuthorizeMethod().returnEarly(0) } } diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/lyrics/ChangeLyricsProviderPatch.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/lyrics/ChangeLyricsProviderPatch.kt index ce711bfd1..d9acf8aa4 100644 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/lyrics/ChangeLyricsProviderPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/lyrics/ChangeLyricsProviderPatch.kt @@ -1,10 +1,16 @@ package app.revanced.patches.spotify.misc.lyrics +import app.revanced.patcher.classDef import app.revanced.patcher.extensions.addInstruction import app.revanced.patcher.extensions.getInstruction import app.revanced.patcher.extensions.replaceInstruction +import app.revanced.patcher.firstMutableMethodDeclaratively +import app.revanced.patcher.instructions +import app.revanced.patcher.method +import app.revanced.patcher.parameterTypes import app.revanced.patcher.patch.creatingBytecodePatch import app.revanced.patcher.patch.stringOption +import app.revanced.patcher.returnType import app.revanced.util.getReference import app.revanced.util.indexOfFirstInstruction import app.revanced.util.indexOfFirstInstructionOrThrow @@ -59,8 +65,6 @@ val `Change lyrics provider` by creatingBytecodePatch( } apply { - val httpClientBuilderMethod = httpClientBuilderMethod.immutableMethod - // region Create a modified copy of the HTTP client builder method with the custom lyrics provider host. val patchedHttpClientBuilderMethod = with(httpClientBuilderMethod) { @@ -70,7 +74,7 @@ val `Change lyrics provider` by creatingBytecodePatch( val setUrlBuilderHostIndex = indexOfFirstInstructionReversedOrThrow(invokeBuildUrlIndex) { val reference = getReference() reference?.definingClass == "Lokhttp3/HttpUrl${"$"}Builder;" && - reference.parameterTypes.firstOrNull() == "Ljava/lang/String;" + reference.parameterTypes.firstOrNull() == "Ljava/lang/String;" } val hostRegister = getInstruction(setUrlBuilderHostIndex).registerD @@ -90,17 +94,13 @@ val `Change lyrics provider` by creatingBytecodePatch( // region Replace the call to the HTTP client builder method used exclusively for lyrics by the modified one. - val getLyricsHttpClientFingerprint = fingerprint { + val getLyricsHttpClientMethod = firstMutableMethodDeclaratively { returnType(httpClientBuilderMethod.returnType) parameterTypes() - custom { method, _ -> - method.indexOfFirstInstruction { - getReference() == httpClientBuilderMethod - } >= 0 - } + instructions(method { this == httpClientBuilderMethod }) } - getLyricsHttpClientFingerprint.method.apply { + getLyricsHttpClientMethod.apply { val getLyricsHttpClientIndex = indexOfFirstInstructionOrThrow { getReference() == httpClientBuilderMethod } diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/lyrics/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/lyrics/Fingerprints.kt index c486ac12a..efec9d84a 100644 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/lyrics/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/lyrics/Fingerprints.kt @@ -1,5 +1,6 @@ package app.revanced.patches.spotify.misc.lyrics +import app.revanced.patcher.gettingFirstMethod import app.revanced.patcher.gettingFirstMethodDeclaratively import app.revanced.patcher.parameterTypes import app.revanced.patcher.patch.BytecodePatchContext @@ -8,16 +9,4 @@ import app.revanced.util.getReference import app.revanced.util.indexOfFirstInstruction import com.android.tools.smali.dexlib2.iface.reference.MethodReference -internal val BytecodePatchContext.httpClientBuilderMethod by gettingFirstMethodDeclaratively { - strings("client == null", "scheduler == null") -} - -internal fun getLyricsHttpClientFingerprint(httpClientBuilderMethodReference: MethodReference) = fingerprint { - returnType(httpClientBuilderMethodReference.returnType) - parameterTypes() - custom { method, _ -> - method.indexOfFirstInstruction { - getReference() == httpClientBuilderMethodReference - } >= 0 - } -} +internal val BytecodePatchContext.httpClientBuilderMethod by gettingFirstMethod("client == null", "scheduler == null") diff --git a/patches/src/main/kotlin/app/revanced/patches/tumblr/featureflags/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/tumblr/featureflags/Fingerprints.kt index a560f4113..c7797a925 100644 --- a/patches/src/main/kotlin/app/revanced/patches/tumblr/featureflags/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/tumblr/featureflags/Fingerprints.kt @@ -1,10 +1,9 @@ package app.revanced.patches.tumblr.featureflags import app.revanced.patcher.accessFlags -import app.revanced.patcher.gettingFirstMethodDeclaratively +import app.revanced.patcher.firstMethodComposite import app.revanced.patcher.opcodes import app.revanced.patcher.parameterTypes -import app.revanced.patcher.patch.BytecodePatchContext import app.revanced.patcher.returnType import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode @@ -18,7 +17,7 @@ import com.android.tools.smali.dexlib2.Opcode // Some features seem to be very old and never removed, though, such as Google Login. // The startIndex of the opcode pattern is at the start of the function after the arg null check. // we want to insert our instructions there. -internal val BytecodePatchContext.getFeatureValueMethod by gettingFirstMethodDeclaratively { +internal val getFeatureValueMethodMatch = firstMethodComposite("feature") { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("Ljava/lang/String;") parameterTypes("L", "Z") @@ -27,5 +26,4 @@ internal val BytecodePatchContext.getFeatureValueMethod by gettingFirstMethodDec Opcode.INVOKE_STATIC, Opcode.MOVE_RESULT, ) - strings("feature") } diff --git a/patches/src/main/kotlin/app/revanced/patches/tumblr/featureflags/OverrideFeatureFlagsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/tumblr/featureflags/OverrideFeatureFlagsPatch.kt index a60bcccde..c8b042a3e 100644 --- a/patches/src/main/kotlin/app/revanced/patches/tumblr/featureflags/OverrideFeatureFlagsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/tumblr/featureflags/OverrideFeatureFlagsPatch.kt @@ -24,54 +24,55 @@ val overrideFeatureFlagsPatch = bytecodePatch( ) { apply { - val configurationClass = getFeatureValueMethod.immutableMethod.definingClass - val featureClass = getFeatureValueMethod.immutableMethod.parameterTypes[0].toString() + getFeatureValueMethodMatch.let { match -> + val configurationClass = match.immutableMethod.definingClass + val featureClass = match.immutableMethod.parameterTypes[0].toString() - // The method we want to inject into does not have enough registers, so we inject a helper method - // and inject more instructions into it later, see addOverride. - // This is not in an extension since the unused variable would get compiled away and the method would - // get compiled to only have one register, which is not enough for our later injected instructions. - val helperMethod = ImmutableMethod( - getFeatureValueMethod.immutableMethod.definingClass, - "getValueOverride", - listOf(ImmutableMethodParameter(featureClass, null, "feature")), - "Ljava/lang/String;", - AccessFlags.PUBLIC.value or AccessFlags.FINAL.value, - null, - null, - MutableMethodImplementation(4), - ).toMutable().apply { - // This is the equivalent of - // String featureName = feature.toString() - // - // return null - addInstructions( - 0, - """ - # toString() the enum value - invoke-virtual {p1}, $featureClass->toString()Ljava/lang/String; - move-result-object v0 - - # !!! If you add more instructions above this line, update helperInsertIndex below! - # Here we will insert one compare & return for every registered Feature override - # This is done below in the addOverride function - - # If none of the overrides returned a value, we should return null - const/4 v0, 0x0 - return-object v0 - """, - ) - }.also { helperMethod -> - getFeatureValueMethod.classDef.methods.add(helperMethod) - } + // The method we want to inject into does not have enough registers, so we inject a helper method + // and inject more instructions into it later, see addOverride. + // This is not in an extension since the unused variable would get compiled away and the method would + // get compiled to only have one register, which is not enough for our later injected instructions. + val helperMethod = ImmutableMethod( + match.immutableMethod.definingClass, + "getValueOverride", + listOf(ImmutableMethodParameter(featureClass, null, "feature")), + "Ljava/lang/String;", + AccessFlags.PUBLIC.value or AccessFlags.FINAL.value, + null, + null, + MutableMethodImplementation(4), + ).toMutable().apply { + // This is the equivalent of + // String featureName = feature.toString() + // + // return null + addInstructions( + 0, + """ + # toString() the enum value + invoke-virtual {p1}, $featureClass->toString()Ljava/lang/String; + move-result-object v0 + + # !!! If you add more instructions above this line, update helperInsertIndex below! + # Here we will insert one compare & return for every registered Feature override + # This is done below in the addOverride function + + # If none of the overrides returned a value, we should return null + const/4 v0, 0x0 + return-object v0 + """, + ) + }.also { helperMethod -> + match.classDef.methods.add(helperMethod) + } - // Here we actually insert the hook to call our helper method and return its value if it returns not null - // This is equivalent to - // String forcedValue = getValueOverride(feature) - // if (forcedValue != null) return forcedValue - val getFeatureIndex = getFeatureValueMethod.indices.first() - getFeatureValueMethod.addInstructionsWithLabels( - getFeatureIndex, + // Here we actually insert the hook to call our helper method and return its value if it returns not null + // This is equivalent to + // String forcedValue = getValueOverride(feature) + // if (forcedValue != null) return forcedValue + val getFeatureIndex = match.indices.first() + match.method.addInstructionsWithLabels( + getFeatureIndex, """ # Call the Helper Method with the Feature invoke-virtual {p0, p1}, $configurationClass->getValueOverride($featureClass)Ljava/lang/String; @@ -85,31 +86,32 @@ val overrideFeatureFlagsPatch = bytecodePatch( :is_null nop """, - ) - - val helperInsertIndex = 2 - addFeatureFlagOverride = { name, value -> - // For every added override, we add a few instructions in the middle of the helper method - // to check if the feature is the one we want and return the override value if it is. - // This is equivalent to - // if (featureName == {name}) return {value} - helperMethod.addInstructionsWithLabels( - helperInsertIndex, - """ - # v0 is still the string name of the currently checked feature from above - # Compare the current string with the override string - const-string v1, "$name" - invoke-virtual {v0, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z - move-result v1 - # If the current string is the one we want to override, we return the override value - if-eqz v1, :no_override - const-string v1, "$value" - return-object v1 - # Else we just continue... - :no_override - nop - """, ) + + val helperInsertIndex = 2 + addFeatureFlagOverride = { name, value -> + // For every added override, we add a few instructions in the middle of the helper method + // to check if the feature is the one we want and return the override value if it is. + // This is equivalent to + // if (featureName == {name}) return {value} + helperMethod.addInstructionsWithLabels( + helperInsertIndex, + """ + # v0 is still the string name of the currently checked feature from above + # Compare the current string with the override string + const-string v1, "$name" + invoke-virtual {v0, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z + move-result v1 + # If the current string is the one we want to override, we return the override value + if-eqz v1, :no_override + const-string v1, "$value" + return-object v1 + # Else we just continue... + :no_override + nop + """, + ) + } } } } diff --git a/patches/src/main/kotlin/app/revanced/patches/tumblr/fixes/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/tumblr/fixes/Fingerprints.kt index 0823aa733..5dc2661c3 100644 --- a/patches/src/main/kotlin/app/revanced/patches/tumblr/fixes/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/tumblr/fixes/Fingerprints.kt @@ -1,26 +1,25 @@ package app.revanced.patches.tumblr.fixes -import app.revanced.patcher.gettingFirstMethodDeclaratively +import app.revanced.patcher.firstMethodComposite +import app.revanced.patcher.gettingFirstMutableMethodDeclaratively import app.revanced.patcher.opcodes import app.revanced.patcher.parameterTypes import app.revanced.patcher.patch.BytecodePatchContext import com.android.tools.smali.dexlib2.Opcode -// Fingerprint for the addQueryParam method from retrofit2 -// https://github.com/square/retrofit/blob/trunk/retrofit/src/main/java/retrofit2/RequestBuilder.java#L186 -// Injecting here allows modifying dynamically set query parameters -internal val BytecodePatchContext.addQueryParamMethod by gettingFirstMethodDeclaratively { +// Fingerprint for the addQueryParam method from retrofit2: +// https://github.com/square/retrofit/blob/trunk/retrofit/src/main/java/retrofit2/RequestBuilder.java#L186. +// Injecting here allows modifying dynamically set query parameters. +internal val BytecodePatchContext.addQueryParamMethod by gettingFirstMutableMethodDeclaratively("Malformed URL. Base: ", ", Relative: ") { parameterTypes("Ljava/lang/String;", "Ljava/lang/String;", "Z") - strings("Malformed URL. Base: ", ", Relative: ") } -// Fingerprint for the parseHttpMethodAndPath method from retrofit2 +// Fingerprint for the parseHttpMethodAndPath method from retrofit2: // https://github.com/square/retrofit/blob/ebf87b10997e2136af4d335276fa950221852c64/retrofit/src/main/java/retrofit2/RequestFactory.java#L270-L302 -// Injecting here allows modifying the path/query params of API endpoints defined via annotations -internal val BytecodePatchContext.httpPathParserMethod by gettingFirstMethodDeclaratively { +// Injecting here allows modifying the path/query params of API endpoints defined via annotations. +internal val httpPathParserMethodMatch = firstMethodComposite("Only one HTTP method is allowed. Found: %s and %s.") { opcodes( Opcode.IPUT_OBJECT, Opcode.IPUT_BOOLEAN, ) - strings("Only one HTTP method is allowed. Found: %s and %s.") } diff --git a/patches/src/main/kotlin/app/revanced/patches/tumblr/fixes/FixOldVersionsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/tumblr/fixes/FixOldVersionsPatch.kt index 1d1596da7..a118ee5da 100644 --- a/patches/src/main/kotlin/app/revanced/patches/tumblr/fixes/FixOldVersionsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/tumblr/fixes/FixOldVersionsPatch.kt @@ -19,8 +19,8 @@ val `Fix old versions` by creatingBytecodePatch( // Remove the live query parameters from the path when it's specified via a @METHOD annotation. for (liveQueryParameter in liveQueryParameters) { - httpPathParserMethod.addInstructions( - httpPathParserMethod.indices.last() + 1, + httpPathParserMethodMatch.method.addInstructions( + httpPathParserMethodMatch.indices.last() + 1, """ # urlPath = urlPath.replace(liveQueryParameter, "") const-string p1, "$liveQueryParameter" diff --git a/patches/src/main/kotlin/app/revanced/patches/tumblr/timelinefilter/FilterTimelineObjectsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/tumblr/timelinefilter/FilterTimelineObjectsPatch.kt index 793621056..a108fd1b7 100644 --- a/patches/src/main/kotlin/app/revanced/patches/tumblr/timelinefilter/FilterTimelineObjectsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/tumblr/timelinefilter/FilterTimelineObjectsPatch.kt @@ -24,9 +24,9 @@ val filterTimelineObjectsPatch = bytecodePatch( dependsOn(sharedExtensionPatch) apply { - val filterInsertIndex = timelineFilterExtensionMethod.indices.first() + val filterInsertIndex = timelineFilterExtensionMethodMatch.indices.first() - timelineFilterExtensionMethod.apply { + timelineFilterExtensionMethodMatch.method.apply { val addInstruction = getInstruction(filterInsertIndex + 1) val filterListRegister = addInstruction.registerC @@ -50,8 +50,8 @@ val filterTimelineObjectsPatch = bytecodePatch( arrayOf( timelineConstructorMethod to 1, postsResponseConstructorMethod to 2, - ).forEach { (fingerprint, timelineObjectsRegister) -> - fingerprint.method.addInstructions( + ).forEach { (method, timelineObjectsRegister) -> + method.addInstructions( 0, "invoke-static {p$timelineObjectsRegister}, " + "Lapp/revanced/extension/tumblr/patches/TimelineFilterPatch;->" + diff --git a/patches/src/main/kotlin/app/revanced/patches/tumblr/timelinefilter/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/tumblr/timelinefilter/Fingerprints.kt index 24d18a266..b508b0968 100644 --- a/patches/src/main/kotlin/app/revanced/patches/tumblr/timelinefilter/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/tumblr/timelinefilter/Fingerprints.kt @@ -1,39 +1,33 @@ package app.revanced.patches.tumblr.timelinefilter -import app.revanced.patcher.accessFlags -import app.revanced.patcher.gettingFirstMethodDeclaratively -import app.revanced.patcher.opcodes +import app.revanced.patcher.* import app.revanced.patcher.patch.BytecodePatchContext import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode // This is the constructor of the PostsResponse class. // The same applies here as with the TimelineConstructorMethod. -internal val BytecodePatchContext.postsResponseConstructorMethod by gettingFirstMethodDeclaratively { +internal val BytecodePatchContext.postsResponseConstructorMethod by gettingFirstMutableMethodDeclaratively { + definingClass { endsWith("/PostsResponse;") } accessFlags(AccessFlags.CONSTRUCTOR, AccessFlags.PUBLIC) - custom { method, classDef -> classDef.endsWith("/PostsResponse;") && method.parameters.size == 4 } + custom { parameters.size == 4 } } // This is the constructor of the Timeline class. // It receives the List as an argument with a @Json annotation, so this should be the first time // that the List is exposed in non-library code. -internal val BytecodePatchContext.timelineConstructorMethod by gettingFirstMethodDeclaratively { - strings("timelineObjectsList") - custom { method, classDef -> - classDef.endsWith("/Timeline;") && method.parameters[0].type == "Ljava/util/List;" - } +internal val BytecodePatchContext.timelineConstructorMethod by gettingFirstMutableMethodDeclaratively("timelineObjectsList") { + definingClass { endsWith("/Timeline;") } + custom { parameters[0].type == "Ljava/util/List;" } } // This fingerprints the extension TimelineFilterPatch.filterTimeline method. // The opcode fingerprint is searching for // if ("BLOCKED_OBJECT_DUMMY".equals(elementType)) iterator.remove(); -internal val BytecodePatchContext.timelineFilterExtensionMethod by gettingFirstMethodDeclaratively { +internal val timelineFilterExtensionMethodMatch = firstMethodComposite("BLOCKED_OBJECT_DUMMY") { + definingClass { endsWith("/TimelineFilterPatch;") } opcodes( Opcode.CONST_STRING, // "BLOCKED_OBJECT_DUMMY" Opcode.INVOKE_VIRTUAL, // HashSet.add(^) ) - strings("BLOCKED_OBJECT_DUMMY") - custom { _, classDef -> - classDef.endsWith("/TimelineFilterPatch;") - } } diff --git a/patches/src/main/kotlin/app/revanced/patches/twitter/interaction/downloads/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/twitter/interaction/downloads/Fingerprints.kt index 24162e3d1..15061ac17 100644 --- a/patches/src/main/kotlin/app/revanced/patches/twitter/interaction/downloads/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/twitter/interaction/downloads/Fingerprints.kt @@ -1,30 +1,26 @@ package app.revanced.patches.twitter.interaction.downloads import app.revanced.patcher.accessFlags -import app.revanced.patcher.gettingFirstMethodDeclaratively +import app.revanced.patcher.firstMethodComposite import app.revanced.patcher.opcodes -import app.revanced.patcher.patch.BytecodePatchContext import app.revanced.patcher.returnType import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -internal val BytecodePatchContext.buildMediaOptionsSheetMethod by gettingFirstMethodDeclaratively { +internal val buildMediaOptionsSheetMethodMatch = firstMethodComposite("mediaEntity", "media_options_sheet") { opcodes( Opcode.IF_EQ, Opcode.SGET_OBJECT, Opcode.GOTO_16, Opcode.NEW_INSTANCE, ) - strings("mediaEntity", "media_options_sheet") } -internal val BytecodePatchContext.constructMediaOptionsSheetMethod by gettingFirstMethodDeclaratively { +internal val constructMediaOptionsSheetMethodMatch = firstMethodComposite("captionsState") { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) - strings("captionsState") } -internal val BytecodePatchContext.showDownloadVideoUpsellBottomSheetMethod by gettingFirstMethodDeclaratively { +internal val showDownloadVideoUpsellBottomSheetMethodMatch = firstMethodComposite("mediaEntity", "url") { returnType("Z") - strings("mediaEntity", "url") opcodes(Opcode.IF_EQZ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/twitter/interaction/downloads/UnlockDownloadsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/twitter/interaction/downloads/UnlockDownloadsPatch.kt index 2b6b3ebd8..abb089da4 100644 --- a/patches/src/main/kotlin/app/revanced/patches/twitter/interaction/downloads/UnlockDownloadsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/twitter/interaction/downloads/UnlockDownloadsPatch.kt @@ -1,5 +1,6 @@ package app.revanced.patches.twitter.interaction.downloads +import app.revanced.patcher.MatchBuilder import app.revanced.patcher.extensions.* import app.revanced.patcher.patch.creatingBytecodePatch import com.android.tools.smali.dexlib2.Opcode @@ -13,13 +14,13 @@ val `Unlock downloads` by creatingBytecodePatch( compatibleWith("com.twitter.android") apply { - fun Fingerprint.patch(getRegisterAndIndex: Fingerprint.() -> Pair) { + fun MatchBuilder.patch(getRegisterAndIndex: MatchBuilder.() -> Pair) { val (index, register) = getRegisterAndIndex() method.addInstruction(index, "const/4 v$register, 0x1") } // Allow downloads for non-premium users. - showDownloadVideoUpsellBottomSheetMethod.patch { + showDownloadVideoUpsellBottomSheetMethodMatch.patch { val checkIndex = indices.first() val register = method.getInstruction(checkIndex).registerA @@ -27,7 +28,7 @@ val `Unlock downloads` by creatingBytecodePatch( } // Force show the download menu item. - constructMediaOptionsSheetMethod.patch { + constructMediaOptionsSheetMethodMatch.patch { val showDownloadButtonIndex = method.instructions.lastIndex - 1 val register = method.getInstruction(showDownloadButtonIndex).registerA @@ -35,7 +36,7 @@ val `Unlock downloads` by creatingBytecodePatch( } // Make GIFs downloadable. - buildMediaOptionsSheetMethod.let { + buildMediaOptionsSheetMethodMatch.let { it.method.apply { val checkMediaTypeIndex = it.indices.first() val checkMediaTypeInstruction = getInstruction(checkMediaTypeIndex) diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/ad/getpremium/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/ad/getpremium/Fingerprints.kt index 0bd2cbea1..16e2f6244 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/ad/getpremium/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/ad/getpremium/Fingerprints.kt @@ -1,15 +1,12 @@ package app.revanced.patches.youtube.ad.getpremium -import app.revanced.patcher.accessFlags -import app.revanced.patcher.gettingFirstMethodDeclaratively -import app.revanced.patcher.opcodes -import app.revanced.patcher.parameterTypes -import app.revanced.patcher.patch.BytecodePatchContext -import app.revanced.patcher.returnType +import app.revanced.patcher.* import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -internal val BytecodePatchContext.getPremiumViewMethod by gettingFirstMethodDeclaratively { +internal val getPremiumViewMethodMatch = firstMethodComposite { + name("onMeasure") + definingClass("Lcom/google/android/apps/youtube/app/red/presenter/CompactYpcOfferModuleView;") accessFlags(AccessFlags.PROTECTED, AccessFlags.FINAL) returnType("V") parameterTypes("I", "I") @@ -19,8 +16,4 @@ internal val BytecodePatchContext.getPremiumViewMethod by gettingFirstMethodDecl Opcode.INVOKE_VIRTUAL, Opcode.RETURN_VOID, ) - custom { method, _ -> - method.name == "onMeasure" && - method.definingClass == "Lcom/google/android/apps/youtube/app/red/presenter/CompactYpcOfferModuleView;" - } } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/ad/getpremium/HideGetPremiumPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/ad/getpremium/HideGetPremiumPatch.kt index e91ff83c3..aadb87f97 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/ad/getpremium/HideGetPremiumPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/ad/getpremium/HideGetPremiumPatch.kt @@ -39,15 +39,15 @@ val hideGetPremiumPatch = bytecodePatch( SwitchPreference("revanced_hide_get_premium"), ) - getPremiumViewMethod.apply { - val startIndex = getPremiumViewMethod.indices.first() - val measuredWidthRegister = getInstruction(startIndex).registerA - val measuredHeightInstruction = getInstruction(startIndex + 1) + getPremiumViewMethodMatch.let { + val startIndex = it.indices.first() + val measuredWidthRegister = it.method.getInstruction(startIndex).registerA + val measuredHeightInstruction = it.method.getInstruction(startIndex + 1) val measuredHeightRegister = measuredHeightInstruction.registerA val tempRegister = measuredHeightInstruction.registerB - addInstructionsWithLabels( + it.method.addInstructionsWithLabels( startIndex + 2, """ # Override the internal measurement of the layout with zero values. diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/dialog/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/dialog/Fingerprints.kt index 845354ff0..f022f7ab8 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/dialog/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/dialog/Fingerprints.kt @@ -1,18 +1,14 @@ package app.revanced.patches.youtube.interaction.dialog -import app.revanced.patcher.gettingFirstMethodDeclaratively -import app.revanced.patcher.instructions -import app.revanced.patcher.parameterTypes -import app.revanced.patcher.patch.BytecodePatchContext -import app.revanced.patcher.returnType +import app.revanced.patcher.* -internal val BytecodePatchContext.createDialogMethod by gettingFirstMethodDeclaratively { +internal val createDialogMethodMatch = firstMethodComposite { returnType("V") parameterTypes("L", "L", "Ljava/lang/String;") instructions( - methodCall(smali = "Landroid/app/AlertDialog\$Builder;->setNegativeButton(ILandroid/content/DialogInterface\$OnClickListener;)Landroid/app/AlertDialog\$Builder;"), - methodCall(smali = "Landroid/app/AlertDialog\$Builder;->setOnCancelListener(Landroid/content/DialogInterface\$OnCancelListener;)Landroid/app/AlertDialog\$Builder;"), - methodCall(smali = "Landroid/app/AlertDialog\$Builder;->create()Landroid/app/AlertDialog;"), - methodCall(smali = "Landroid/app/AlertDialog;->show()V"), + method { toString() == $$"Landroid/app/AlertDialog$Builder;->setNegativeButton(ILandroid/content/DialogInterface$OnClickListener;)Landroid/app/AlertDialog$Builder;" }, + method { toString() == $$"Landroid/app/AlertDialog$Builder;->setOnCancelListener(Landroid/content/DialogInterface$OnCancelListener;)Landroid/app/AlertDialog$Builder;" }, + method { toString() == $$"Landroid/app/AlertDialog$Builder;->create()Landroid/app/AlertDialog;" }, + method { toString() == "Landroid/app/AlertDialog;->show()V" }, ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/dialog/RemoveViewerDiscretionDialogPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/dialog/RemoveViewerDiscretionDialogPatch.kt index 910c6b507..9cd87bdf7 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/dialog/RemoveViewerDiscretionDialogPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/dialog/RemoveViewerDiscretionDialogPatch.kt @@ -41,9 +41,9 @@ val `Remove viewer discretion dialog` by creatingBytecodePatch( SwitchPreference("revanced_remove_viewer_discretion_dialog"), ) - createDialogMethod.let { + createDialogMethodMatch.let { it.method.apply { - val showDialogIndex = it.indices.last() // TODO + val showDialogIndex = it.indices.last() val dialogRegister = getInstruction(showDialogIndex).registerC replaceInstructions( diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/EnableSeekbarTappingPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/EnableSeekbarTappingPatch.kt index 3b423d7c3..a454d9dba 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/EnableSeekbarTappingPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/EnableSeekbarTappingPatch.kt @@ -34,7 +34,7 @@ val enableSeekbarTappingPatch = bytecodePatch( ) // Find the required methods to tap the seekbar. - val seekbarTappingMethods = onTouchEventHandlerMethod.let { + val seekbarTappingMethods = onTouchEventHandlerMethodMatch.let { fun getReference(index: Int) = it.method.getInstruction(index) .reference as MethodReference @@ -44,7 +44,7 @@ val enableSeekbarTappingPatch = bytecodePatch( ) } - seekbarTappingMethod.let { + seekbarTappingMethodMatch.let { val insertIndex = it.indices.last() + 1 it.method.apply { diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/EnableSlideToSeekPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/EnableSlideToSeekPatch.kt index c516f8fec..28ac4dce5 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/EnableSlideToSeekPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/EnableSlideToSeekPatch.kt @@ -2,6 +2,7 @@ package app.revanced.patches.youtube.interaction.seekbar import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.getInstruction +import app.revanced.patcher.extensions.methodReference import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.bytecodePatch import app.revanced.patches.all.misc.resources.addResources @@ -42,16 +43,16 @@ val enableSlideToSeekPatch = bytecodePatch( // Restore the behaviour to slide to seek. - val checkIndex = slideToSeekMethod.indices.first() - val checkReference = slideToSeekMethod.getInstruction(checkIndex) + val checkIndex = slideToSeekMethodMatch.indices.first() + val checkReference = slideToSeekMethodMatch.method.getInstruction(checkIndex) .getReference()!! val extensionMethodDescriptor = "$EXTENSION_CLASS_DESCRIPTOR->isSlideToSeekDisabled(Z)Z" // A/B check method was only called on this class. - slideToSeekMethod.classDef.methods.forEach { method -> + slideToSeekMethodMatch.classDef.methods.forEach { method -> method.findInstructionIndicesReversed { - opcode == Opcode.INVOKE_VIRTUAL && getReference() == checkReference + opcode == Opcode.INVOKE_VIRTUAL && methodReference == checkReference }.forEach { index -> method.apply { val register = getInstruction(index + 1).registerA @@ -73,7 +74,7 @@ val enableSlideToSeekPatch = bytecodePatch( // Disable the double speed seek gesture. if (is_19_17_or_greater) { - disableFastForwardGestureMethod.let { + disableFastForwardGestureMethodMatch.let { it.method.apply { val targetIndex = it.indices.last() val targetRegister = getInstruction(targetIndex).registerA @@ -88,7 +89,7 @@ val enableSlideToSeekPatch = bytecodePatch( } } } else { - disableFastForwardLegacyMethod.let { + disableFastForwardLegacyMethodMatch.let { it.method.apply { val insertIndex = it.indices.last() + 1 val targetRegister = getInstruction(insertIndex).registerA diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/Fingerprints.kt index 0d24c3ae3..84104d894 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/Fingerprints.kt @@ -40,7 +40,7 @@ internal fun ClassDef.getAllowSwipingUpGestureMethod() = firstMutableMethodDecla parameterTypes("L") } -internal val BytecodePatchContext.disableFastForwardLegacyMethod by gettingFirstMethodDeclaratively { +internal val disableFastForwardLegacyMethodMatch = firstMethodComposite { returnType("Z") parameterTypes() opcodes(Opcode.MOVE_RESULT) @@ -48,7 +48,7 @@ internal val BytecodePatchContext.disableFastForwardLegacyMethod by gettingFirst literal { 45411330 } } -internal val BytecodePatchContext.disableFastForwardGestureMethod by gettingFirstMethodDeclaratively { +internal val disableFastForwardGestureMethodMatch = firstMethodComposite { definingClass { endsWith("/NextGenWatchLayout;") } accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("Z") @@ -80,7 +80,7 @@ internal val customTapAndHoldMethodMatch = firstMethodComposite { } } -internal val BytecodePatchContext.onTouchEventHandlerMethod by gettingFirstMethodDeclaratively { +internal val onTouchEventHandlerMethodMatch = firstMethodComposite { name("onTouchEvent") accessFlags(AccessFlags.PUBLIC, AccessFlags.PUBLIC) returnType("Z") @@ -103,7 +103,7 @@ internal val BytecodePatchContext.onTouchEventHandlerMethod by gettingFirstMetho ) } -internal val BytecodePatchContext.seekbarTappingMethod by gettingFirstMethodDeclaratively { +internal val seekbarTappingMethodMatch = firstMethodComposite { name("onTouchEvent") accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("Z") @@ -119,7 +119,7 @@ internal val BytecodePatchContext.seekbarTappingMethod by gettingFirstMethodDecl ) } -internal val BytecodePatchContext.slideToSeekMethod by gettingFirstMethodDeclaratively { +internal val slideToSeekMethodMatch = firstMethodComposite { accessFlags(AccessFlags.PRIVATE, AccessFlags.FINAL) returnType("V") parameterTypes("Landroid/view/View;", "F") diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/Fingerprints.kt index 5bda3130e..1a2cd2379 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/Fingerprints.kt @@ -1,6 +1,8 @@ package app.revanced.patches.youtube.interaction.swipecontrols import app.revanced.patcher.accessFlags +import app.revanced.patcher.definingClass +import app.revanced.patcher.firstMethodComposite import app.revanced.patcher.gettingFirstMethodDeclaratively import app.revanced.patcher.instructions import app.revanced.patcher.invoke @@ -9,14 +11,12 @@ import app.revanced.patcher.patch.BytecodePatchContext import com.android.tools.smali.dexlib2.AccessFlags internal val BytecodePatchContext.swipeControlsHostActivityMethod by gettingFirstMethodDeclaratively { + definingClass(EXTENSION_CLASS_DESCRIPTOR) accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) parameterTypes() - custom { method, _ -> - method.definingClass == EXTENSION_CLASS_DESCRIPTOR - } } -internal val BytecodePatchContext.swipeChangeVideoMethod by gettingFirstMethodDeclaratively { +internal val swipeChangeVideoMethodMatch = firstMethodComposite { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) instructions( 45631116L(), // Swipe to change fullscreen video feature flag. diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/SwipeControlsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/SwipeControlsPatch.kt index 02d30c558..1700af293 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/SwipeControlsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/SwipeControlsPatch.kt @@ -134,9 +134,9 @@ val `Swipe controls` by creatingBytecodePatch( // region patch to enable/disable swipe to change video. if (is_19_43_or_greater && !is_20_34_or_greater) { - swipeChangeVideoMethod.let { + swipeChangeVideoMethodMatch.let { it.method.insertLiteralOverride( - it.indices.last(), // TODO + it.indices.last(), "$EXTENSION_CLASS_DESCRIPTOR->allowSwipeChangeVideo(Z)Z", ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/Fingerprints.kt index 7b44f33f6..7b716ff75 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/Fingerprints.kt @@ -1,11 +1,7 @@ package app.revanced.patches.youtube.layout.hide.endscreencards -import app.revanced.patcher.accessFlags -import app.revanced.patcher.gettingFirstMethodDeclaratively -import app.revanced.patcher.opcodes -import app.revanced.patcher.parameterTypes +import app.revanced.patcher.* import app.revanced.patcher.patch.BytecodePatchContext -import app.revanced.patcher.returnType import app.revanced.util.containsLiteralInstruction import app.revanced.util.getReference import app.revanced.util.indexOfFirstInstruction @@ -14,7 +10,7 @@ import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.reference.FieldReference -internal val BytecodePatchContext.layoutCircleMethod by gettingFirstMethodDeclaratively { +internal val layoutCircleMethodMatch = firstMethodComposite { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) parameterTypes() returnType("Landroid/view/View;") @@ -28,7 +24,7 @@ internal val BytecodePatchContext.layoutCircleMethod by gettingFirstMethodDeclar literal { layoutCircle } } -internal val BytecodePatchContext.layoutIconMethod by gettingFirstMethodDeclaratively { +internal val layoutIconMethodMatch = firstMethodComposite { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) parameterTypes() returnType("Landroid/view/View;") @@ -41,7 +37,7 @@ internal val BytecodePatchContext.layoutIconMethod by gettingFirstMethodDeclarat literal { layoutIcon } } -internal val BytecodePatchContext.layoutVideoMethod by gettingFirstMethodDeclaratively { +internal val layoutVideoMethodMatch = firstMethodComposite { accessFlags(AccessFlags.PUBLIC) parameterTypes() returnType("Landroid/view/View;") @@ -55,16 +51,16 @@ internal val BytecodePatchContext.layoutVideoMethod by gettingFirstMethodDeclara literal { layoutVideo } } -internal val BytecodePatchContext.showEndscreenCardsMethod by gettingFirstMethodDeclaratively { +internal val BytecodePatchContext.showEndscreenCardsMethod by gettingFirstMutableMethodDeclaratively { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("V") parameterTypes("L") - custom { method, classDef -> - classDef.methods.count() == 5 && - method.containsLiteralInstruction(0) && - method.containsLiteralInstruction(5) && - method.containsLiteralInstruction(8) && - method.indexOfFirstInstruction { + custom { + immutableClassDef.methods.count() == 5 && + containsLiteralInstruction(0) && + containsLiteralInstruction(5) && + containsLiteralInstruction(8) && + indexOfFirstInstruction { val reference = getReference() reference?.type == "Lcom/google/android/libraries/youtube/innertube/model/player/PlayerResponseModel;" } >= 0 diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/HideEndScreenCardsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/HideEndScreenCardsPatch.kt index 7ae38375e..9d4035f7d 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/HideEndScreenCardsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/HideEndScreenCardsPatch.kt @@ -70,12 +70,12 @@ val `Hide end screen cards` by creatingBytecodePatch( apply { listOf( - layoutCircleMethod, - layoutIconMethod, - layoutVideoMethod, - ).forEach { fingerprint -> - fingerprint.method.apply { - val insertIndex = fingerprint.indices.last() + 1 // TODO + layoutCircleMethodMatch, + layoutIconMethodMatch, + layoutVideoMethodMatch, + ).forEach { match -> + match.method.apply { + val insertIndex = match.indices.last() + 1 val viewRegister = getInstruction(insertIndex - 1).registerA addInstruction( diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreensuggestion/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreensuggestion/Fingerprints.kt index f8a3f2445..4fdf367e7 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreensuggestion/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreensuggestion/Fingerprints.kt @@ -1,30 +1,26 @@ package app.revanced.patches.youtube.layout.hide.endscreensuggestion -import app.revanced.patcher.accessFlags -import app.revanced.patcher.gettingFirstMethodDeclaratively -import app.revanced.patcher.opcodes -import app.revanced.patcher.parameterTypes +import app.revanced.patcher.* +import app.revanced.patcher.extensions.instructions +import app.revanced.patcher.extensions.methodReference import app.revanced.patcher.patch.BytecodePatchContext -import app.revanced.patcher.returnType -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 +import com.android.tools.smali.dexlib2.iface.ClassDef -internal val BytecodePatchContext.autoNavConstructorMethod by gettingFirstMethodDeclaratively { +internal val BytecodePatchContext.autoNavConstructorMethod by gettingFirstMethodDeclaratively("main_app_autonav") { returnType("V") accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) - strings("main_app_autonav") } -internal val BytecodePatchContext.autoNavStatusMethod by gettingFirstMethodDeclaratively { +context(_: BytecodePatchContext) +internal fun ClassDef.getAutoNavStatusMethod() = firstMutableMethodDeclaratively { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("Z") parameterTypes() } -internal val BytecodePatchContext.removeOnLayoutChangeListenerMethod by gettingFirstMethodDeclaratively { +internal val removeOnLayoutChangeListenerMethodMatch = firstMethodComposite { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("V") parameterTypes() @@ -33,11 +29,10 @@ internal val BytecodePatchContext.removeOnLayoutChangeListenerMethod by gettingF Opcode.INVOKE_VIRTUAL, ) // This is the only reference present in the entire smali. - custom { method, _ -> - method.indexOfFirstInstruction { - val reference = getReference() - reference?.name == "removeOnLayoutChangeListener" && - reference.definingClass.endsWith("/YouTubePlayerOverlaysLayout;") - } >= 0 + custom { + instructions.anyInstruction { + val reference = methodReference + reference?.name == "removeOnLayoutChangeListener" && reference.definingClass.endsWith("/YouTubePlayerOverlaysLayout;") + } } } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreensuggestion/HideEndScreenSuggestedVideoPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreensuggestion/HideEndScreenSuggestedVideoPatch.kt index dd8947b29..6870212f0 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreensuggestion/HideEndScreenSuggestedVideoPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreensuggestion/HideEndScreenSuggestedVideoPatch.kt @@ -3,18 +3,18 @@ package app.revanced.patches.youtube.layout.hide.endscreensuggestion import app.revanced.patcher.extensions.ExternalLabel import app.revanced.patcher.extensions.addInstructionsWithLabels import app.revanced.patcher.extensions.getInstruction +import app.revanced.patcher.extensions.methodReference +import app.revanced.patcher.immutableClassDef import app.revanced.patcher.patch.creatingBytecodePatch import app.revanced.patches.all.misc.resources.addResources import app.revanced.patches.all.misc.resources.addResourcesPatch import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch import app.revanced.patches.youtube.misc.settings.PreferenceScreen -import app.revanced.util.getReference import app.revanced.util.indexOfFirstInstructionOrThrow import app.revanced.util.indexOfFirstInstructionReversedOrThrow import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction -import com.android.tools.smali.dexlib2.iface.reference.MethodReference private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/HideEndScreenSuggestedVideoPatch;" @@ -44,20 +44,19 @@ val `Hide end screen suggested video` by creatingBytecodePatch( SwitchPreference("revanced_end_screen_suggested_video"), ) - removeOnLayoutChangeListenerMethod.let { + removeOnLayoutChangeListenerMethodMatch.let { val endScreenMethod = navigate(it.immutableMethod).to(it.indices.last()).stop() // TODO endScreenMethod.apply { - val autoNavStatusMethodName = autoNavStatusMethod.match( - autoNavConstructorMethod.classDef, - ).immutableMethod.name + val autoNavStatusMethodName = autoNavConstructorMethod.immutableClassDef.getAutoNavStatusMethod().name val invokeIndex = indexOfFirstInstructionOrThrow { - val reference = getReference() + val reference = methodReference reference?.name == autoNavStatusMethodName && reference.returnType == "Z" && reference.parameterTypes.isEmpty() } + val iGetObjectIndex = indexOfFirstInstructionReversedOrThrow(invokeIndex, Opcode.IGET_OBJECT) val invokeReference = getInstruction(invokeIndex).reference val iGetObjectReference = getInstruction(iGetObjectIndex).reference diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/Fingerprints.kt index 7969ddf13..837eacbea 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/Fingerprints.kt @@ -1,54 +1,45 @@ package app.revanced.patches.youtube.layout.hide.general -import app.revanced.patcher.StringComparisonType -import app.revanced.patcher.accessFlags -import app.revanced.patcher.after -import app.revanced.patcher.afterAtMost -import app.revanced.patcher.checkCast -import app.revanced.patcher.gettingFirstMethodDeclaratively -import app.revanced.patcher.instructions -import app.revanced.patcher.invoke -import app.revanced.patcher.opcodes -import app.revanced.patcher.parameterTypes +import app.revanced.patcher.* import app.revanced.patcher.patch.BytecodePatchContext -import app.revanced.patcher.returnType import app.revanced.patches.shared.misc.mapping.ResourceType import app.revanced.patches.youtube.layout.searchbar.wideSearchbarLayoutMethod +import app.revanced.util.literal import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.iface.ClassDef /** * 20.26+ */ -internal val BytecodePatchContext.hideShowMoreButtonMethod by gettingFirstMethodDeclaratively { +internal val hideShowMoreButtonMethodMatch = firstMethodComposite { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL, AccessFlags.SYNTHETIC) returnType("V") parameterTypes("L", "Ljava/lang/Object;") instructions( ResourceType.LAYOUT("expand_button_down"), - methodCall(smali = "Landroid/view/LayoutInflater;->inflate(ILandroid/view/ViewGroup;Z)Landroid/view/View;"), + method { toString() == "Landroid/view/LayoutInflater;->inflate(ILandroid/view/ViewGroup;Z)Landroid/view/View;" }, after(Opcode.MOVE_RESULT_OBJECT()), ) } -internal val BytecodePatchContext.hideShowMoreLegacyButtonMethod by gettingFirstMethodDeclaratively { +internal val hideShowMoreLegacyButtonMethodMatch = firstMethodComposite { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) instructions( ResourceType.LAYOUT("expand_button_down"), - methodCall(smali = "Landroid/view/View;->inflate(Landroid/content/Context;ILandroid/view/ViewGroup;)Landroid/view/View;"), + method { toString() == "Landroid/view/View;->inflate(Landroid/content/Context;ILandroid/view/ViewGroup;)Landroid/view/View;" }, Opcode.MOVE_RESULT_OBJECT(), ) } -internal val BytecodePatchContext.parseElementFromBufferMethod by gettingFirstMethodDeclaratively { +internal val parseElementFromBufferMethodMatch = firstMethodComposite { parameterTypes("L", "L", "[B", "L", "L") instructions( Opcode.IGET_OBJECT(), // IGET_BOOLEAN // 20.07+ afterAtMost(1, Opcode.INVOKE_INTERFACE()), after(Opcode.MOVE_RESULT_OBJECT()), - - addString("Failed to parse Element", comparison = StringComparisonType.STARTS_WITH), + "Failed to parse Element"(String::startsWith), ) } @@ -60,7 +51,8 @@ internal val BytecodePatchContext.playerOverlayMethod by gettingFirstMethodDecla ) } -internal val BytecodePatchContext.showWatermarkMethod by gettingFirstMethodDeclaratively { +context(_: BytecodePatchContext) +internal fun ClassDef.getShowWatermarkMethod() = firstMutableMethodDeclaratively { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("V") parameterTypes("L", "L") @@ -69,16 +61,14 @@ internal val BytecodePatchContext.showWatermarkMethod by gettingFirstMethodDecla /** * Matches same method as [wideSearchbarLayoutMethod]. */ -internal val BytecodePatchContext.yoodlesImageViewMethod by gettingFirstMethodDeclaratively { +internal val BytecodePatchContext.yoodlesImageViewMethod by gettingFirstMutableMethodDeclaratively { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("Landroid/view/View;") parameterTypes("L", "L") - instructions( - ResourceType.ID("youtube_logo"), - ) + instructions(ResourceType.ID("youtube_logo")) } -internal val BytecodePatchContext.crowdfundingBoxMethod by gettingFirstMethodDeclaratively { +internal val crowdfundingBoxMethodMatch = firstMethodComposite { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) opcodes( Opcode.INVOKE_VIRTUAL, @@ -88,7 +78,7 @@ internal val BytecodePatchContext.crowdfundingBoxMethod by gettingFirstMethodDec literal { crowdfundingBoxId } } -internal val BytecodePatchContext.albumCardsMethod by gettingFirstMethodDeclaratively { +internal val albumCardsMethodMatch = firstMethodComposite { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) opcodes( Opcode.MOVE_RESULT_OBJECT, @@ -101,7 +91,7 @@ internal val BytecodePatchContext.albumCardsMethod by gettingFirstMethodDeclarat literal { albumCardId } } -internal val BytecodePatchContext.filterBarHeightMethod by gettingFirstMethodDeclaratively { +internal val filterBarHeightMethodMatch = firstMethodComposite { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) opcodes( Opcode.CONST, @@ -112,7 +102,7 @@ internal val BytecodePatchContext.filterBarHeightMethod by gettingFirstMethodDec literal { filterBarHeightId } } -internal val BytecodePatchContext.relatedChipCloudMethod by gettingFirstMethodDeclaratively { +internal val relatedChipCloudMethodMatch = firstMethodComposite { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) opcodes( Opcode.CONST, @@ -122,7 +112,7 @@ internal val BytecodePatchContext.relatedChipCloudMethod by gettingFirstMethodDe literal { relatedChipCloudMarginId } } -internal val BytecodePatchContext.searchResultsChipBarMethod by gettingFirstMethodDeclaratively { +internal val searchResultsChipBarMethodMatch = firstMethodComposite { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) opcodes( Opcode.CONST, @@ -134,27 +124,25 @@ internal val BytecodePatchContext.searchResultsChipBarMethod by gettingFirstMeth literal { barContainerHeightId } } -internal val BytecodePatchContext.showFloatingMicrophoneButtonMethod by gettingFirstMethodDeclaratively { +internal val showFloatingMicrophoneButtonMethodMatch = firstMethodComposite { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("V") parameterTypes() instructions( ResourceType.ID("fab"), - checkCast("/FloatingActionButton;", afterAtMost(10)), + afterAtMost(10, allOf(Opcode.CHECK_CAST(), "/FloatingActionButton;"())), afterAtMost(15, Opcode.IGET_BOOLEAN()), ) } -internal val BytecodePatchContext.hideViewCountMethod by gettingFirstMethodDeclaratively { +internal val hideViewCountMethodMatch = firstMethodComposite( + "Has attachmentRuns but drawableRequester is missing.", +) { accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) returnType("Ljava/lang/CharSequence;") - opcodes( Opcode.RETURN_OBJECT, Opcode.CONST_STRING, Opcode.RETURN_OBJECT, ) - strings( - "Has attachmentRuns but drawableRequester is missing.", - ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsPatch.kt index e2758c6d9..2b53fd698 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsPatch.kt @@ -1,6 +1,8 @@ package app.revanced.patches.youtube.layout.hide.general +import app.revanced.patcher.MatchBuilder import app.revanced.patcher.extensions.* +import app.revanced.patcher.immutableClassDef import app.revanced.patcher.patch.creatingBytecodePatch import app.revanced.patcher.patch.resourcePatch import app.revanced.patches.all.misc.resources.addResources @@ -41,30 +43,15 @@ private val hideLayoutComponentsResourcePatch = resourcePatch { dependsOn(resourceMappingPatch) apply { - albumCardId = getResourceId( - ResourceType.LAYOUT, - "album_card", - ) + albumCardId = ResourceType.LAYOUT["album_card"] - crowdfundingBoxId = getResourceId( - ResourceType.LAYOUT, - "donation_companion", - ) + crowdfundingBoxId = ResourceType.LAYOUT["donation_companion"] - relatedChipCloudMarginId = getResourceId( - ResourceType.LAYOUT, - "related_chip_cloud_reduced_margins", - ) + relatedChipCloudMarginId = ResourceType.LAYOUT["related_chip_cloud_reduced_margins"] - filterBarHeightId = getResourceId( - ResourceType.DIMEN, - "filter_bar_height", - ) + filterBarHeightId = ResourceType.DIMEN["filter_bar_height"] - barContainerHeightId = getResourceId( - ResourceType.DIMEN, - "bar_container_height", - ) + barContainerHeightId = ResourceType.DIMEN["bar_container_height"] } } @@ -240,38 +227,40 @@ val `Hide layout components` by creatingBytecodePatch( // region Mix playlists - parseElementFromBufferMethod.apply { - val startIndex = parseElementFromBufferMethod.indices.first() - val insertIndex = startIndex + 1 + parseElementFromBufferMethodMatch.let { + it.method.apply { + val startIndex = it.indices.first() + val insertIndex = startIndex + 1 - val byteArrayParameter = "p3" - val conversionContextRegister = getInstruction(startIndex).registerA - val returnEmptyComponentInstruction = instructions.last { it.opcode == Opcode.INVOKE_STATIC } - val returnEmptyComponentRegister = (returnEmptyComponentInstruction as FiveRegisterInstruction).registerC - val freeRegister = findFreeRegister(insertIndex, conversionContextRegister, returnEmptyComponentRegister) + val byteArrayParameter = "p3" + val conversionContextRegister = getInstruction(startIndex).registerA + val returnEmptyComponentInstruction = instructions.last { it.opcode == Opcode.INVOKE_STATIC } + val returnEmptyComponentRegister = + (returnEmptyComponentInstruction as FiveRegisterInstruction).registerC + val freeRegister = + findFreeRegister(insertIndex, conversionContextRegister, returnEmptyComponentRegister) - addInstructionsWithLabels( - insertIndex, - """ - invoke-static { v$conversionContextRegister, $byteArrayParameter }, $LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR->filterMixPlaylists(Ljava/lang/Object;[B)Z - move-result v$freeRegister - if-eqz v$freeRegister, :show - move-object v$returnEmptyComponentRegister, p1 # Required for 19.47 - goto :return_empty_component - :show - nop - """, - ExternalLabel("return_empty_component", returnEmptyComponentInstruction), - ) + addInstructionsWithLabels( + insertIndex, + """ + invoke-static { v$conversionContextRegister, $byteArrayParameter }, $LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR->filterMixPlaylists(Ljava/lang/Object;[B)Z + move-result v$freeRegister + if-eqz v$freeRegister, :show + move-object v$returnEmptyComponentRegister, p1 # Required for 19.47 + goto :return_empty_component + :show + nop + """, + ExternalLabel("return_empty_component", returnEmptyComponentInstruction), + ) + } } // endregion // region Watermark (legacy code for old versions of YouTube) - showWatermarkMethod.match( - playerOverlayMethod.immutableClassDef, - ).method.apply { + playerOverlayMethod.immutableClassDef.getShowWatermarkMethod().apply { val index = implementation!!.instructions.size - 5 removeInstruction(index) @@ -288,7 +277,7 @@ val `Hide layout components` by creatingBytecodePatch( // region Show more button - (if (is_20_26_or_greater) hideShowMoreButtonMethod else hideShowMoreLegacyButtonMethod).let { + (if (is_20_26_or_greater) hideShowMoreButtonMethodMatch else hideShowMoreLegacyButtonMethodMatch).let { it.method.apply { val moveRegisterIndex = it.indices.last() val viewRegister = getInstruction(moveRegisterIndex).registerA @@ -305,7 +294,7 @@ val `Hide layout components` by creatingBytecodePatch( // endregion // region crowdfunding box - crowdfundingBoxMethod.let { + crowdfundingBoxMethodMatch.let { it.method.apply { val insertIndex = it.indices.last() val objectRegister = getInstruction(insertIndex).registerA @@ -322,7 +311,7 @@ val `Hide layout components` by creatingBytecodePatch( // region hide album cards - albumCardsMethod.let { + albumCardsMethodMatch.let { it.method.apply { val checkCastAnchorIndex = it.indices.last() val insertIndex = checkCastAnchorIndex + 1 @@ -340,7 +329,7 @@ val `Hide layout components` by creatingBytecodePatch( // region hide floating microphone - showFloatingMicrophoneButtonMethod.let { + showFloatingMicrophoneButtonMethodMatch.let { it.method.apply { val index = it.indices.last() val register = getInstruction(index).registerA @@ -378,8 +367,8 @@ val `Hide layout components` by creatingBytecodePatch( // region hide view count - hideViewCountMethod.apply { - val startIndex = hideViewCountMethod.patternMatch.startIndex + hideViewCountMethodMatch.method.apply { + val startIndex = hideViewCountMethodMatch.indices.first() var returnStringRegister = getInstruction(startIndex).registerA // Find the instruction where the text dimension is retrieved. @@ -414,11 +403,11 @@ val `Hide layout components` by creatingBytecodePatch( * Patch a [Method] with a given [instructions]. * * @param RegisterInstruction The type of instruction to get the register from. - * @param insertIndexOffset The offset to add to the end index of the [Match.patternMatch]. + * @param insertIndexOffset The offset to add to the end index of the [MatchBuilder.indices]. * @param hookRegisterOffset The offset to add to the register of the hook. * @param instructions The instructions to add with the register as a parameter. */ - fun Fingerprint.patch( + fun MatchBuilder.patch( insertIndexOffset: Int = 0, hookRegisterOffset: Int = 0, instructions: (Int) -> String, @@ -430,21 +419,21 @@ val `Hide layout components` by creatingBytecodePatch( addInstructions(insertIndex, instructions(register)) } - filterBarHeightMethod.patch { register -> + filterBarHeightMethodMatch.patch { register -> """ invoke-static { v$register }, $LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR->hideInFeed(I)I move-result v$register """ } - searchResultsChipBarMethod.patch(-1, -2) { register -> + searchResultsChipBarMethodMatch.patch(-1, -2) { register -> """ invoke-static { v$register }, $LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR->hideInSearch(I)I move-result v$register """ } - relatedChipCloudMethod.patch(1) { register -> + relatedChipCloudMethodMatch.patch(1) { register -> "invoke-static { v$register }, " + "$LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR->hideInRelatedVideos(Landroid/view/View;)V" } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/Fingerprints.kt index d9a949ec0..0fe436f65 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/Fingerprints.kt @@ -1,24 +1,18 @@ package app.revanced.patches.youtube.layout.hide.infocards -import app.revanced.patcher.accessFlags -import app.revanced.patcher.gettingFirstMethodDeclaratively -import app.revanced.patcher.instructions -import app.revanced.patcher.invoke -import app.revanced.patcher.opcodes -import app.revanced.patcher.parameterTypes +import app.revanced.patcher.* import app.revanced.patcher.patch.BytecodePatchContext -import app.revanced.patcher.returnType import app.revanced.util.literal import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.iface.ClassDef -internal val BytecodePatchContext.infocardsIncognitoMethod by gettingFirstMethodDeclaratively { +context(_: BytecodePatchContext) +internal fun ClassDef.getInfocardsIncognitoMethod() = firstMutableMethodDeclaratively { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("Ljava/lang/Boolean;") parameterTypes("L", "J") - instructions( - "vibrator"(), - ) + instructions("vibrator"()) } internal val BytecodePatchContext.infocardsIncognitoParentMethod by gettingFirstMethodDeclaratively { @@ -29,12 +23,12 @@ internal val BytecodePatchContext.infocardsIncognitoParentMethod by gettingFirst ) } -internal val BytecodePatchContext.infocardsMethodCallMethod by gettingFirstMethodDeclaratively { - opcodes( - Opcode.INVOKE_VIRTUAL, - Opcode.IGET_OBJECT, - Opcode.INVOKE_INTERFACE, - ) - strings("Missing ControlsOverlayPresenter for InfoCards to work.") - literal { drawerResourceId } -} +internal val infocardsMethodCallMethodMatch = + firstMethodComposite("Missing ControlsOverlayPresenter for InfoCards to work.") { + opcodes( + Opcode.INVOKE_VIRTUAL, + Opcode.IGET_OBJECT, + Opcode.INVOKE_INTERFACE, + ) + literal { drawerResourceId } + } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/HideInfoCardsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/HideInfoCardsPatch.kt index e23b41e68..e4cac186c 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/HideInfoCardsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/HideInfoCardsPatch.kt @@ -4,6 +4,7 @@ import app.revanced.patcher.extensions.ExternalLabel import app.revanced.patcher.extensions.addInstruction import app.revanced.patcher.extensions.addInstructionsWithLabels import app.revanced.patcher.extensions.getInstruction +import app.revanced.patcher.immutableClassDef import app.revanced.patcher.patch.creatingBytecodePatch import app.revanced.patcher.patch.resourcePatch import app.revanced.patches.all.misc.resources.addResources @@ -27,10 +28,7 @@ private val hideInfocardsResourcePatch = resourcePatch { dependsOn(resourceMappingPatch) apply { - drawerResourceId = getResourceId( - ResourceType.ID, - "info_cards_drawer_header", - ) + drawerResourceId = ResourceType.ID["info_cards_drawer_header"] } } @@ -63,7 +61,7 @@ val `Hide info cards` by creatingBytecodePatch( ) // Edit: This old non litho code may be obsolete and no longer used by any supported versions. - infocardsIncognitoMethod.match(infocardsIncognitoParentMethod.immutableClassDef).method.apply { + infocardsIncognitoParentMethod.immutableClassDef.getInfocardsIncognitoMethod().apply { val invokeInstructionIndex = implementation!!.instructions.indexOfFirst { it.opcode.ordinal == Opcode.INVOKE_VIRTUAL.ordinal && ((it as ReferenceInstruction).reference.toString() == "Landroid/view/View;->setVisibility(I)V") @@ -77,7 +75,7 @@ val `Hide info cards` by creatingBytecodePatch( } // Edit: This old non litho code may be obsolete and no longer used by any supported versions. - infocardsMethodCallMethod.let { + infocardsMethodCallMethodMatch.let { val invokeInterfaceIndex = it.indices.last() it.method.apply { val register = implementation!!.registerCount - 1 diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/rollingnumber/DisableRollingNumberAnimationPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/rollingnumber/DisableRollingNumberAnimationPatch.kt index f976a4fb1..466d12836 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/rollingnumber/DisableRollingNumberAnimationPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/rollingnumber/DisableRollingNumberAnimationPatch.kt @@ -11,7 +11,7 @@ import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.settingsPatch -import app.revanced.patches.youtube.shared.rollingNumberTextViewAnimationUpdateMethod +import app.revanced.patches.youtube.shared.rollingNumberTextViewAnimationUpdateMethodMatch import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction private const val EXTENSION_CLASS_DESCRIPTOR = @@ -45,7 +45,7 @@ val `Disable rolling number animations` by creatingBytecodePatch( // Animations are disabled by preventing an Image from being applied to the text span, // which prevents the animations from appearing. - rollingNumberTextViewAnimationUpdateMethod.let { + rollingNumberTextViewAnimationUpdateMethodMatch.let { val blockStartIndex = it.indices.first() val blockEndIndex = it.indices.last() + 1 it.method.apply { diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/Fingerprints.kt index ea840585b..d5c103bb0 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/Fingerprints.kt @@ -2,19 +2,12 @@ package app.revanced.patches.youtube.layout.miniplayer -import app.revanced.patcher.accessFlags -import app.revanced.patcher.afterAtMost -import app.revanced.patcher.checkCast -import app.revanced.patcher.gettingFirstMethodDeclaratively -import app.revanced.patcher.instructions -import app.revanced.patcher.invoke -import app.revanced.patcher.opcodes -import app.revanced.patcher.parameterTypes +import app.revanced.patcher.* import app.revanced.patcher.patch.BytecodePatchContext -import app.revanced.patcher.returnType import app.revanced.patches.shared.misc.mapping.ResourceType import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.iface.ClassDef internal const val MINIPLAYER_MODERN_FEATURE_KEY = 45622882L @@ -28,7 +21,7 @@ internal const val MINIPLAYER_INITIAL_SIZE_FEATURE_KEY = 45640023L internal const val MINIPLAYER_DISABLED_FEATURE_KEY = 45657015L internal const val MINIPLAYER_ANIMATED_EXPAND_FEATURE_KEY = 45644360L -internal val BytecodePatchContext.miniplayerModernConstructorMethod by gettingFirstMethodDeclaratively { +internal val BytecodePatchContext.miniplayerModernConstructorMethod by gettingFirstMutableMethodDeclaratively { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) instructions( 45623000L(), // Magic number found in the constructor. @@ -56,7 +49,8 @@ internal val BytecodePatchContext.miniplayerModernViewParentMethod by gettingFir /** * Matches using the class found in [miniplayerModernViewParentMethod]. */ -internal val BytecodePatchContext.miniplayerModernAddViewListenerMethod by gettingFirstMethodDeclaratively { +context(_: BytecodePatchContext) +internal fun ClassDef.getMiniplayerModernAddViewListenerMethod() = firstMutableMethodDeclaratively { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("V") parameterTypes("Landroid/view/View;") @@ -65,33 +59,34 @@ internal val BytecodePatchContext.miniplayerModernAddViewListenerMethod by getti /** * Matches using the class found in [miniplayerModernViewParentMethod]. */ -internal val BytecodePatchContext.miniplayerModernCloseButtonMethod by gettingFirstMethodDeclaratively { +internal val miniplayerModernCloseButtonMethodMatch = firstMethodComposite { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("L") parameterTypes() instructions( ResourceType.ID("modern_miniplayer_close"), - checkCast("Landroid/widget/ImageView;"), + allOf(Opcode.CHECK_CAST(), "Landroid/widget/ImageView;"()), ) } /** * Matches using the class found in [miniplayerModernViewParentMethod]. */ -internal val BytecodePatchContext.miniplayerModernExpandButtonMethod by gettingFirstMethodDeclaratively { +internal val miniplayerModernExpandButtonMethodMatch = firstMethodComposite { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("L") parameterTypes() instructions( ResourceType.ID("modern_miniplayer_expand"), - checkCast("Landroid/widget/ImageView;"), + allOf(Opcode.CHECK_CAST(), "Landroid/widget/ImageView;"()), ) } /** * Matches using the class found in [miniplayerModernViewParentMethod]. */ -internal val BytecodePatchContext.miniplayerModernExpandCloseDrawablesMethod by gettingFirstMethodDeclaratively { +context(_: BytecodePatchContext) +internal fun ClassDef.getMiniplayerModernExpandCloseDrawablesMethod() = firstMutableMethodDeclaratively { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("V") parameterTypes("L") @@ -103,7 +98,7 @@ internal val BytecodePatchContext.miniplayerModernExpandCloseDrawablesMethod by /** * Matches using the class found in [miniplayerModernViewParentMethod]. */ -internal val BytecodePatchContext.miniplayerModernForwardButtonMethod by gettingFirstMethodDeclaratively { +internal val miniplayerModernForwardButtonMethodMatch = firstMethodComposite { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("L") parameterTypes() @@ -113,7 +108,7 @@ internal val BytecodePatchContext.miniplayerModernForwardButtonMethod by getting ) } -internal val BytecodePatchContext.miniplayerModernOverlayViewMethod by gettingFirstMethodDeclaratively { +internal val miniplayerModernOverlayViewMethodMatch = firstMethodComposite { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) parameterTypes() instructions( @@ -125,7 +120,7 @@ internal val BytecodePatchContext.miniplayerModernOverlayViewMethod by gettingFi /** * Matches using the class found in [miniplayerModernViewParentMethod]. */ -internal val BytecodePatchContext.miniplayerModernRewindButtonMethod by gettingFirstMethodDeclaratively { +internal val miniplayerModernRewindButtonMethodMatch = firstMethodComposite { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("L") parameterTypes() @@ -138,7 +133,7 @@ internal val BytecodePatchContext.miniplayerModernRewindButtonMethod by gettingF /** * Matches using the class found in [miniplayerModernViewParentMethod]. */ -internal val BytecodePatchContext.miniplayerModernActionButtonMethod by gettingFirstMethodDeclaratively { +internal val miniplayerModernActionButtonMethodMatch = firstMethodComposite { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("L") parameterTypes() @@ -148,7 +143,7 @@ internal val BytecodePatchContext.miniplayerModernActionButtonMethod by gettingF ) } -internal val BytecodePatchContext.miniplayerMinimumSizeMethod by gettingFirstMethodDeclaratively { +internal val miniplayerMinimumSizeMethodMatch = firstMethodComposite { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) instructions( ResourceType.DIMEN("miniplayer_max_size"), @@ -157,20 +152,20 @@ internal val BytecodePatchContext.miniplayerMinimumSizeMethod by gettingFirstMet ) } -internal val BytecodePatchContext.miniplayerOverrideMethod by gettingFirstMethodDeclaratively { +internal val miniplayerOverrideMethodMatch = firstMethodComposite { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("L") instructions( "appName"(), - methodCall( - parameters = listOf("Landroid/content/Context;"), - returnType = "Z", - afterAtMost(10), + afterAtMost( + 10, + method { parameterTypes.count() == 1 && parameterTypes.first() == "Landroid/content/Context;" && returnType == "Z" }, ), ) } -internal val BytecodePatchContext.miniplayerOverrideNoContextMethod by gettingFirstMethodDeclaratively { +context(_: BytecodePatchContext) +internal fun ClassDef.getMiniplayerOverrideNoContextMethod() = firstMutableMethodDeclaratively { accessFlags(AccessFlags.PRIVATE, AccessFlags.FINAL) returnType("Z") opcodes( @@ -181,7 +176,7 @@ internal val BytecodePatchContext.miniplayerOverrideNoContextMethod by gettingFi /** * 20.36 and lower. Codes appears to be removed in 20.37+ */ -internal val BytecodePatchContext.miniplayerResponseModelSizeCheckMethod by gettingFirstMethodDeclaratively { +internal val miniplayerResponseModelSizeCheckMethodMatch = firstMethodComposite { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("L") parameterTypes("Ljava/lang/Object;", "Ljava/lang/Object;") @@ -195,7 +190,7 @@ internal val BytecodePatchContext.miniplayerResponseModelSizeCheckMethod by gett ) } -internal val BytecodePatchContext.miniplayerOnCloseHandlerMethod by gettingFirstMethodDeclaratively { +internal val BytecodePatchContext.miniplayerOnCloseHandlerMethod by gettingFirstMutableMethodDeclaratively { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("Z") instructions( @@ -207,12 +202,10 @@ internal const val YOUTUBE_PLAYER_OVERLAYS_LAYOUT_CLASS_NAME = "Lcom/google/android/apps/youtube/app/common/player/overlay/YouTubePlayerOverlaysLayout;" internal val BytecodePatchContext.playerOverlaysLayoutMethod by gettingFirstMethodDeclaratively { - custom { method, _ -> - method.definingClass == YOUTUBE_PLAYER_OVERLAYS_LAYOUT_CLASS_NAME - } + definingClass(YOUTUBE_PLAYER_OVERLAYS_LAYOUT_CLASS_NAME) } -internal val BytecodePatchContext.miniplayerSetIconsMethod by gettingFirstMethodDeclaratively { +internal val BytecodePatchContext.miniplayerSetIconsMethod by gettingFirstMutableMethodDeclaratively { returnType("V") parameterTypes("I", "Ljava/lang/Runnable;") instructions( diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/MiniplayerPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/MiniplayerPatch.kt index e1752f767..99c00c96f 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/MiniplayerPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/MiniplayerPatch.kt @@ -2,10 +2,12 @@ package app.revanced.patches.youtube.layout.miniplayer +import app.revanced.patcher.classDef import app.revanced.patcher.extensions.addInstruction import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.getInstruction import app.revanced.patcher.extensions.replaceInstruction +import app.revanced.patcher.immutableClassDef import app.revanced.patcher.patch.creatingBytecodePatch import app.revanced.patcher.patch.resourcePatch import app.revanced.patches.all.misc.resources.addResources @@ -46,22 +48,12 @@ private val miniplayerResourcePatch = resourcePatch { apply { // Resource id is not used during patching, but is used by extension. // Verify the resource is present while patching. - getResourceId( - ResourceType.ID, - "modern_miniplayer_subtitle_text", - ) + ResourceType.ID["modern_miniplayer_subtitle_text"] // Only required for exactly 19.16 if (!is_19_17_or_greater) { - ytOutlinePictureInPictureWhite24 = getResourceId( - ResourceType.DRAWABLE, - "yt_outline_picture_in_picture_white_24", - ) - - ytOutlineXWhite24 = getResourceId( - ResourceType.DRAWABLE, - "yt_outline_x_white_24", - ) + ytOutlinePictureInPictureWhite24 = ResourceType.DRAWABLE["yt_outline_picture_in_picture_white_24"] + ytOutlineXWhite24 = ResourceType.DRAWABLE["yt_outline_x_white_24"] } } } @@ -189,31 +181,29 @@ val Miniplayer by creatingBytecodePatch( insertMiniplayerBooleanOverride(index, "getModernMiniplayerOverride") } - fun Fingerprint.insertMiniplayerFeatureFlagBooleanOverride( + fun MutableMethod.insertMiniplayerFeatureFlagBooleanOverride( literal: Long, extensionMethod: String, - ) = method.insertLiteralOverride( + ) = insertLiteralOverride( literal, "$EXTENSION_CLASS_DESCRIPTOR->$extensionMethod(Z)Z", ) - fun Fingerprint.insertMiniplayerFeatureFlagFloatOverride( + fun MutableMethod.insertMiniplayerFeatureFlagFloatOverride( literal: Long, extensionMethod: String, - ) { - method.apply { - val literalIndex = indexOfFirstLiteralInstructionOrThrow(literal) - val targetIndex = indexOfFirstInstructionOrThrow(literalIndex, Opcode.DOUBLE_TO_FLOAT) - val register = getInstruction(targetIndex).registerA + ) = apply { + val literalIndex = indexOfFirstLiteralInstructionOrThrow(literal) + val targetIndex = indexOfFirstInstructionOrThrow(literalIndex, Opcode.DOUBLE_TO_FLOAT) + val register = getInstruction(targetIndex).registerA - addInstructions( - targetIndex + 1, - """ - invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->$extensionMethod(F)F - move-result v$register - """, - ) - } + addInstructions( + targetIndex + 1, + """ + invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->$extensionMethod(F)F + move-result v$register + """, + ) } /** @@ -235,20 +225,16 @@ val Miniplayer by creatingBytecodePatch( // Parts of the YT code is removed in 20.37+ and the legacy player no longer works. if (!is_20_37_or_greater) { - miniplayerOverrideNoContextMethod.match( - miniplayerDimensionsCalculatorParentMethod.immutableClassDef, - ).method.apply { + miniplayerDimensionsCalculatorParentMethod.immutableClassDef.getMiniplayerOverrideNoContextMethod().apply { findReturnIndicesReversed().forEach { index -> - insertLegacyTabletMiniplayerOverride( - index, - ) + insertLegacyTabletMiniplayerOverride(index) } } // endregion // region Legacy tablet miniplayer hooks. - miniplayerOverrideMethod.let { + miniplayerOverrideMethodMatch.let { val appNameStringIndex = it.indices.last() navigate(it.immutableMethod).to(appNameStringIndex).stop().apply { findReturnIndicesReversed().forEach { index -> @@ -259,7 +245,7 @@ val Miniplayer by creatingBytecodePatch( } } - miniplayerResponseModelSizeCheckMethod.let { + miniplayerResponseModelSizeCheckMethodMatch.let { it.method.insertLegacyTabletMiniplayerOverride(it.indices.last()) } } @@ -324,7 +310,7 @@ val Miniplayer by creatingBytecodePatch( } // Override a minimum size constant. - miniplayerMinimumSizeMethod.let { + miniplayerMinimumSizeMethodMatch.let { it.method.apply { val index = it.indices[1] val register = getInstruction(index).registerA @@ -367,9 +353,7 @@ val Miniplayer by creatingBytecodePatch( // YT fixed this mistake in 19.17. // Fix this, by swapping the drawable resource values with each other. if (!is_19_17_or_greater) { - miniplayerModernExpandCloseDrawablesMethod.match( - miniplayerModernViewParentMethod.immutableClassDef, - ).method.apply { + miniplayerModernViewParentMethod.immutableClassDef.getMiniplayerModernExpandCloseDrawablesMethod().apply { listOf( ytOutlinePictureInPictureWhite24 to ytOutlineXWhite24, ytOutlineXWhite24 to ytOutlinePictureInPictureWhite24, @@ -411,17 +395,15 @@ val Miniplayer by creatingBytecodePatch( // region Add hooks to hide modern miniplayer buttons. listOf( - miniplayerModernExpandButtonMethod to "hideMiniplayerExpandClose", - miniplayerModernCloseButtonMethod to "hideMiniplayerExpandClose", - miniplayerModernActionButtonMethod to "hideMiniplayerActionButton", - miniplayerModernRewindButtonMethod to "hideMiniplayerRewindForward", - miniplayerModernForwardButtonMethod to "hideMiniplayerRewindForward", - miniplayerModernOverlayViewMethod to "adjustMiniplayerOpacity", - ).forEach { (fingerprint, methodName) -> - fingerprint.match( - miniplayerModernViewParentMethod.classDef, - ).method.apply { - val index = fingerprint.indices.last() + miniplayerModernExpandButtonMethodMatch to "hideMiniplayerExpandClose", + miniplayerModernCloseButtonMethodMatch to "hideMiniplayerExpandClose", + miniplayerModernActionButtonMethodMatch to "hideMiniplayerActionButton", + miniplayerModernRewindButtonMethodMatch to "hideMiniplayerRewindForward", + miniplayerModernForwardButtonMethodMatch to "hideMiniplayerRewindForward", + miniplayerModernOverlayViewMethodMatch to "adjustMiniplayerOpacity", + ).forEach { (match, methodName) -> + match.match(miniplayerModernViewParentMethod.immutableClassDef).method.apply { + val index = match.indices.last() val register = getInstruction(index).registerA addInstruction( @@ -431,9 +413,7 @@ val Miniplayer by creatingBytecodePatch( } } - miniplayerModernAddViewListenerMethod.match( - miniplayerModernViewParentMethod.classDef, - ).method.addInstruction( + miniplayerModernViewParentMethod.immutableClassDef.getMiniplayerModernAddViewListenerMethod().addInstruction( 0, "invoke-static { p1 }, $EXTENSION_CLASS_DESCRIPTOR->" + "hideMiniplayerSubTexts(Landroid/view/View;)V", diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/fullscreen/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/fullscreen/Fingerprints.kt index 690ec2f39..7322a252f 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/fullscreen/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/fullscreen/Fingerprints.kt @@ -8,7 +8,7 @@ import com.android.tools.smali.dexlib2.Opcode /** * 19.46+ */ -internal val BytecodePatchContext.openVideosFullscreenPortraitMethod by gettingFirstMethodDeclaratively { +internal val openVideosFullscreenPortraitMethodMatch = firstMethodComposite { returnType("V") parameterTypes("L", "Lj\$/util/Optional;") instructions( @@ -22,7 +22,7 @@ internal val BytecodePatchContext.openVideosFullscreenPortraitMethod by gettingF /** * Pre 19.46. */ -internal val BytecodePatchContext.openVideosFullscreenPortraitLegacyMethod by gettingFirstMethodDeclaratively { +internal val openVideosFullscreenPortraitLegacyMethodMatch = firstMethodComposite { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("V") parameterTypes("L", "Lj\$/util/Optional;") diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/fullscreen/OpenVideosFullscreenHookPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/fullscreen/OpenVideosFullscreenHookPatch.kt index e5c004233..fce46c591 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/fullscreen/OpenVideosFullscreenHookPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/fullscreen/OpenVideosFullscreenHookPatch.kt @@ -1,5 +1,6 @@ package app.revanced.patches.youtube.layout.player.fullscreen +import app.revanced.patcher.MatchBuilder import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.getInstruction import app.revanced.patcher.patch.bytecodePatch @@ -23,14 +24,14 @@ internal val openVideosFullscreenHookPatch = bytecodePatch { ) apply { - var fingerprint: Fingerprint + var match: MatchBuilder var insertIndex: Int if (is_19_46_or_greater) { - fingerprint = openVideosFullscreenPortraitMethod - insertIndex = fingerprint.indices.first() + match = openVideosFullscreenPortraitMethodMatch + insertIndex = match.indices.first() - openVideosFullscreenPortraitMethod.let { + openVideosFullscreenPortraitMethodMatch.let { // Remove A/B feature call that forces what this patch already does. // Cannot use the A/B flag to accomplish the same goal because 19.50+ // Shorts fullscreen regular player does not use fullscreen @@ -41,22 +42,20 @@ internal val openVideosFullscreenHookPatch = bytecodePatch { ) } } else { - fingerprint = openVideosFullscreenPortraitLegacyMethod - insertIndex = fingerprint.indices.last() + match = openVideosFullscreenPortraitLegacyMethodMatch + insertIndex = match.indices.last() } - fingerprint.let { - it.method.apply { - val register = getInstruction(insertIndex).registerA + match.method.apply { + val register = getInstruction(insertIndex).registerA - addInstructions( - insertIndex + 1, - """ - invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->doNotOpenVideoFullscreenPortrait(Z)Z - move-result v$register - """, - ) - } + addInstructions( + insertIndex + 1, + """ + invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->doNotOpenVideoFullscreenPortrait(Z)Z + move-result v$register + """, + ) } } } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/overlay/CustomPlayerOverlayOpacityPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/overlay/CustomPlayerOverlayOpacityPatch.kt index 727292b4c..ac1cd9c03 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/overlay/CustomPlayerOverlayOpacityPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/overlay/CustomPlayerOverlayOpacityPatch.kt @@ -41,7 +41,7 @@ val `Custom player overlay opacity` by creatingBytecodePatch( TextPreference("revanced_player_overlay_opacity", inputType = InputType.NUMBER), ) - createPlayerOverviewMethod.let { + createPlayerOverviewMethodMatch.let { it.method.apply { val viewRegisterIndex = it.indices.last() val viewRegister = getInstruction(viewRegisterIndex).registerA diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/overlay/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/overlay/Fingerprints.kt index 7a04fc447..62c49c774 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/overlay/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/overlay/Fingerprints.kt @@ -1,16 +1,13 @@ package app.revanced.patches.youtube.layout.player.overlay -import app.revanced.patcher.checkCast -import app.revanced.patcher.gettingFirstMethodDeclaratively -import app.revanced.patcher.instructions -import app.revanced.patcher.patch.BytecodePatchContext -import app.revanced.patcher.returnType +import app.revanced.patcher.* import app.revanced.patches.shared.misc.mapping.ResourceType +import com.android.tools.smali.dexlib2.Opcode -internal val BytecodePatchContext.createPlayerOverviewMethod by gettingFirstMethodDeclaratively { +internal val createPlayerOverviewMethodMatch = firstMethodComposite { returnType("V") instructions( ResourceType.ID("scrim_overlay"), - checkCast("Landroid/widget/ImageView;", afterAtMost(10)), + afterAtMost(10, allOf(Opcode.CHECK_CAST(), type("Landroid/widget/ImageView;"))), ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/Fingerprints.kt index 871e7c9e0..551f5977a 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/Fingerprints.kt @@ -1,43 +1,33 @@ package app.revanced.patches.youtube.layout.returnyoutubedislike -import app.revanced.patcher.accessFlags -import app.revanced.patcher.gettingFirstMethodDeclaratively -import app.revanced.patcher.instructions -import app.revanced.patcher.invoke -import app.revanced.patcher.opcodes -import app.revanced.patcher.parameterTypes +import app.revanced.patcher.* +import app.revanced.patcher.extensions.instructions import app.revanced.patcher.patch.BytecodePatchContext -import app.revanced.patcher.returnType import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.iface.ClassDef -internal val BytecodePatchContext.dislikeMethod by gettingFirstMethodDeclaratively { +internal val BytecodePatchContext.dislikeMethod by gettingFirstMutableMethodDeclaratively { returnType("V") - instructions( - "like/dislike"(), - ) + instructions("like/dislike"()) } -internal val BytecodePatchContext.likeMethod by gettingFirstMethodDeclaratively { +internal val BytecodePatchContext.likeMethod by gettingFirstMutableMethodDeclaratively { returnType("V") - instructions( - "like/like"(), - ) + instructions("like/like"()) } -internal val BytecodePatchContext.removeLikeMethod by gettingFirstMethodDeclaratively { +internal val BytecodePatchContext.removeLikeMethod by gettingFirstMutableMethodDeclaratively { returnType("V") - instructions( - "like/removelike"(), - ) + instructions("like/removelike"()) } -internal val BytecodePatchContext.rollingNumberMeasureAnimatedTextMethod by gettingFirstMethodDeclaratively { +internal val rollingNumberMeasureAnimatedTextMethodMatch = firstMethodComposite { accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) returnType("Lj\$/util/Optional;") parameterTypes("L", "Ljava/lang/String;", "L") opcodes( - Opcode.IGET, // First instruction of method + Opcode.IGET, // First instruction of method. Opcode.IGET_OBJECT, Opcode.IGET_OBJECT, Opcode.CONST_HIGH16, @@ -46,14 +36,14 @@ internal val BytecodePatchContext.rollingNumberMeasureAnimatedTextMethod by gett Opcode.CONST_4, Opcode.AGET, Opcode.CONST_4, - Opcode.CONST_4, // Measured text width + Opcode.CONST_4, // Measured text width. ) } /** * Matches to class found in [rollingNumberMeasureStaticLabelParentMethod]. */ -internal val BytecodePatchContext.rollingNumberMeasureStaticLabelMethod by gettingFirstMethodDeclaratively { +internal val rollingNumberMeasureStaticLabelMethod = firstMethodComposite { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("F") parameterTypes("Ljava/lang/String;") @@ -74,29 +64,33 @@ internal val BytecodePatchContext.rollingNumberMeasureStaticLabelParentMethod by ) } -internal val BytecodePatchContext.rollingNumberSetterMethod by gettingFirstMethodDeclaratively { +internal val rollingNumberSetterMethodMatch = firstMethodComposite { opcodes( Opcode.INVOKE_DIRECT, Opcode.IGET_OBJECT, ) - // Partial string match. - strings("RollingNumberType required properties missing! Need") + custom { + instructions.matchIndexed( + "string", + "RollingNumberType required properties missing! Need"(String::contains), + ) + } } -internal val BytecodePatchContext.rollingNumberTextViewMethod by gettingFirstMethodDeclaratively { +internal val BytecodePatchContext.rollingNumberTextViewMethod by gettingFirstMutableMethodDeclaratively { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("V") parameterTypes("L", "F", "F") - opcodes( - Opcode.IPUT, - null, // invoke-direct or invoke-virtual - Opcode.IPUT_OBJECT, - Opcode.IGET_OBJECT, - Opcode.INVOKE_VIRTUAL, - Opcode.RETURN_VOID, + instructions( + Opcode.IPUT(), + anyOf(Opcode.INVOKE_DIRECT(), Opcode.INVOKE_VIRTUAL()), + Opcode.IPUT_OBJECT(), + Opcode.IGET_OBJECT(), + Opcode.INVOKE_VIRTUAL(), + Opcode.RETURN_VOID(), ) - custom { _, classDef -> - classDef.superclass == "Landroid/support/v7/widget/AppCompatTextView;" || classDef.superclass == + custom { + immutableClassDef.superclass == "Landroid/support/v7/widget/AppCompatTextView;" || immutableClassDef.superclass == "Lcom/google/android/libraries/youtube/rendering/ui/spec/typography/YouTubeAppCompatTextView;" } } @@ -114,28 +108,23 @@ internal val BytecodePatchContext.textComponentDataMethod by gettingFirstMethodD instructions( "text"(), ) - custom { _, classDef -> - classDef.fields.find { it.type == "Ljava/util/BitSet;" } != null - } + custom { immutableClassDef.anyField { type == "Ljava/util/BitSet;" } } } /** * Matches against the same class found in [textComponentConstructorMethod]. */ -internal val BytecodePatchContext.textComponentLookupMethod by gettingFirstMethodDeclaratively { +context(_: BytecodePatchContext) +internal fun ClassDef.getTextComponentLookupMethod() = firstMutableMethodDeclaratively { accessFlags(AccessFlags.PROTECTED, AccessFlags.FINAL) returnType("L") parameterTypes("L") - instructions( - "…"(), - ) + instructions("…"()) } -internal val BytecodePatchContext.textComponentFeatureFlagMethod by gettingFirstMethodDeclaratively { +internal val BytecodePatchContext.textComponentFeatureFlagMethod by gettingFirstMutableMethodDeclaratively { accessFlags(AccessFlags.FINAL) returnType("Z") parameterTypes() - instructions( - 45675738L(), - ) + instructions(45675738L()) } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/ReturnYouTubeDislikePatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/ReturnYouTubeDislikePatch.kt index 971c755f1..0f0441a48 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/ReturnYouTubeDislikePatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/ReturnYouTubeDislikePatch.kt @@ -1,7 +1,10 @@ package app.revanced.patches.youtube.layout.returnyoutubedislike import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.fieldReference import app.revanced.patcher.extensions.getInstruction +import app.revanced.patcher.extensions.methodReference +import app.revanced.patcher.immutableClassDef import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.creatingBytecodePatch import app.revanced.patches.all.misc.resources.addResources @@ -18,21 +21,20 @@ import app.revanced.patches.youtube.misc.playservice.* import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.settingsPatch import app.revanced.patches.youtube.shared.conversionContextToStringMethod -import app.revanced.patches.youtube.shared.rollingNumberTextViewAnimationUpdateMethod +import app.revanced.patches.youtube.shared.rollingNumberTextViewAnimationUpdateMethodMatch import app.revanced.patches.youtube.video.videoid.hookPlayerResponseVideoId import app.revanced.patches.youtube.video.videoid.hookVideoId import app.revanced.patches.youtube.video.videoid.videoIdPatch -import app.revanced.util.* +import app.revanced.util.addInstructionsAtControlFlowLabel +import app.revanced.util.findFreeRegister +import app.revanced.util.indexOfFirstInstructionOrThrow +import app.revanced.util.returnLate 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.iface.reference.TypeReference import java.util.logging.Logger -import kotlin.jvm.java private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/ReturnYouTubeDislikePatch;" @@ -102,8 +104,8 @@ val `Return YouTube Dislike` by creatingBytecodePatch( likeMethod to Vote.LIKE, dislikeMethod to Vote.DISLIKE, removeLikeMethod to Vote.REMOVE_LIKE, - ).forEach { (fingerprint, vote) -> - fingerprint.method.addInstructions( + ).forEach { (method, vote) -> + method.addInstructions( 0, """ const/4 v0, ${vote.value} @@ -128,7 +130,7 @@ val `Return YouTube Dislike` by creatingBytecodePatch( it.type == conversionContextClass.superclass } ?: throw PatchException("Could not find conversion context field") - textComponentLookupMethod.match(textComponentConstructorMethod.immutableClassDef).method.apply { + textComponentConstructorMethod.immutableClassDef.getTextComponentLookupMethod().apply { // Find the instruction for creating the text data object. val textDataClassType = textComponentDataMethod.immutableClassDef.type @@ -138,24 +140,24 @@ val `Return YouTube Dislike` by creatingBytecodePatch( if (is_19_33_or_greater && !is_20_10_or_greater) { val index = indexOfFirstInstructionOrThrow { (opcode == Opcode.INVOKE_STATIC || opcode == Opcode.INVOKE_STATIC_RANGE) && - getReference()?.returnType == textDataClassType + methodReference?.returnType == textDataClassType } insertIndex = indexOfFirstInstructionOrThrow(index) { opcode == Opcode.INVOKE_VIRTUAL && - getReference()?.parameterTypes?.firstOrNull() == "Ljava/lang/CharSequence;" + methodReference?.parameterTypes?.firstOrNull() == "Ljava/lang/CharSequence;" } charSequenceRegister = getInstruction(insertIndex).registerD } else { insertIndex = indexOfFirstInstructionOrThrow { opcode == Opcode.NEW_INSTANCE && - getReference()?.type == textDataClassType + fieldReference?.type == textDataClassType } val charSequenceIndex = indexOfFirstInstructionOrThrow(insertIndex) { opcode == Opcode.IPUT_OBJECT && - getReference()?.type == "Ljava/lang/CharSequence;" + fieldReference?.type == "Ljava/lang/CharSequence;" } charSequenceRegister = getInstruction(charSequenceIndex).registerA } @@ -221,13 +223,11 @@ val `Return YouTube Dislike` by creatingBytecodePatch( // region Hook rolling numbers. - rollingNumberSetterMethod.apply { + rollingNumberSetterMethodMatch.method.apply { val insertIndex = 1 - val dislikesIndex = rollingNumberSetterMethod.indices.last() - val charSequenceInstanceRegister = - getInstruction(0).registerA - val charSequenceFieldReference = - getInstruction(dislikesIndex).reference + val dislikesIndex = rollingNumberSetterMethodMatch.indices.last() + val charSequenceInstanceRegister = getInstruction(0).registerA + val charSequenceFieldReference = getInstruction(dislikesIndex).reference val conversionContextRegister = implementation!!.registerCount - parameters.size + 1 @@ -246,7 +246,7 @@ val `Return YouTube Dislike` by creatingBytecodePatch( // Rolling Number text views use the measured width of the raw string for layout. // Modify the measure text calculation to include the left drawable separator if needed. - rollingNumberMeasureAnimatedTextMethod.let { + rollingNumberMeasureAnimatedTextMethodMatch.let { // Additional check to verify the opcodes are at the start of the method if (it.indices.first() != 0) throw PatchException("Unexpected opcode location") val endIndex = it.indices.last() @@ -290,11 +290,11 @@ val `Return YouTube Dislike` by creatingBytecodePatch( rollingNumberTextViewMethod, // Videos less than 24 hours after uploaded, like counts will be updated in real time. // Whenever like counts are updated, TextView is set in this method. - rollingNumberTextViewAnimationUpdateMethod, + rollingNumberTextViewAnimationUpdateMethodMatch.method, ).forEach { insertMethod -> insertMethod.apply { val setTextIndex = indexOfFirstInstructionOrThrow { - getReference()?.name == "setText" + methodReference?.name == "setText" } val textViewRegister = getInstruction(setTextIndex).registerC diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/Fingerprints.kt index 826ff3579..024c66522 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/Fingerprints.kt @@ -1,33 +1,22 @@ package app.revanced.patches.youtube.layout.seekbar -import app.revanced.patcher.accessFlags -import app.revanced.patcher.afterAtMost -import app.revanced.patcher.anyInstruction -import app.revanced.patcher.custom -import app.revanced.patcher.definingClass -import app.revanced.patcher.gettingFirstMethodDeclaratively -import app.revanced.patcher.instructions -import app.revanced.patcher.invoke -import app.revanced.patcher.literal -import app.revanced.patcher.method -import app.revanced.patcher.opcodes -import app.revanced.patcher.parameterTypes +import app.revanced.patcher.* import app.revanced.patcher.patch.BytecodePatchContext -import app.revanced.patcher.returnType import app.revanced.patches.shared.misc.mapping.ResourceType import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.iface.ClassDef internal val BytecodePatchContext.fullscreenSeekbarThumbnailsMethod by gettingFirstMethodDeclaratively { returnType("Z") accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) parameterTypes() instructions( - 45398577(), + 45398577L(), ) } -internal val BytecodePatchContext.playerSeekbarColorMethod by gettingFirstMethodDeclaratively { +internal val playerSeekbarColorMethodMatch = firstMethodComposite { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) instructions( ResourceType.COLOR("inline_time_bar_played_not_highlighted_color"), @@ -36,19 +25,24 @@ internal val BytecodePatchContext.playerSeekbarColorMethod by gettingFirstMethod } // class is ControlsOverlayStyle in 20.32 and lower, and obfuscated in 20.33+ -internal val BytecodePatchContext.setSeekbarClickedColorMethod by gettingFirstMethodDeclaratively { +internal val setSeekbarClickedColorMethodMatch = firstMethodComposite( + "YOUTUBE", + "PREROLL", + "POSTROLL", + "REMOTE_LIVE", + "AD_LARGE_CONTROLS", +) { opcodes(Opcode.CONST_HIGH16) - strings("YOUTUBE", "PREROLL", "POSTROLL", "REMOTE_LIVE", "AD_LARGE_CONTROLS") } -internal val BytecodePatchContext.shortsSeekbarColorMethod by gettingFirstMethodDeclaratively { +internal val shortsSeekbarColorMethodMatch = firstMethodComposite { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) instructions( ResourceType.COLOR("reel_time_bar_played_color"), ) } -internal val BytecodePatchContext.playerSeekbarHandle1ColorMethod by gettingFirstMethodDeclaratively { +internal val playerSeekbarHandle1ColorMethodMatch = firstMethodComposite { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) instructions( ResourceType.COLOR("inline_time_bar_live_seekable_range"), @@ -56,7 +50,7 @@ internal val BytecodePatchContext.playerSeekbarHandle1ColorMethod by gettingFirs ) } -internal val BytecodePatchContext.playerSeekbarHandle2ColorMethod by gettingFirstMethodDeclaratively { +internal val playerSeekbarHandle2ColorMethodMatch = firstMethodComposite { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) parameterTypes("Landroid/content/Context;") instructions( @@ -65,18 +59,18 @@ internal val BytecodePatchContext.playerSeekbarHandle2ColorMethod by gettingFirs ) } -internal val BytecodePatchContext.watchHistoryMenuUseProgressDrawableMethod by gettingFirstMethodDeclaratively { +internal val watchHistoryMenuUseProgressDrawableMethodMatch = firstMethodComposite { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("V") parameterTypes("L") instructions( - methodCall("Landroid/widget/ProgressBar;", "setMax"), + method { name == "setMax" && definingClass == "Landroid/widget/ProgressBar;" }, Opcode.MOVE_RESULT(), - -1712394514(), + (-1712394514L)(), ) } -internal val BytecodePatchContext.lithoLinearGradientMethod by gettingFirstMethodDeclaratively { +internal val BytecodePatchContext.lithoLinearGradientMethod by gettingFirstMutableMethodDeclaratively { accessFlags(AccessFlags.STATIC) returnType("Landroid/graphics/LinearGradient;") parameterTypes("F", "F", "F", "F", "[I", "[F") @@ -85,7 +79,7 @@ internal val BytecodePatchContext.lithoLinearGradientMethod by gettingFirstMetho /** * 19.49+ */ -internal val BytecodePatchContext.playerLinearGradientMethod by gettingFirstMethodDeclaratively { +internal val playerLinearGradientMethodMatch = firstMethodComposite { accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) parameterTypes("I", "I", "I", "I", "Landroid/content/Context;", "I") returnType("Landroid/graphics/LinearGradient;") @@ -100,7 +94,7 @@ internal val BytecodePatchContext.playerLinearGradientMethod by gettingFirstMeth /** * 19.25 - 19.47 */ -internal val BytecodePatchContext.playerLinearGradientLegacyMethod by gettingFirstMethodDeclaratively { +internal val playerLinearGradientLegacyMethodMatch = firstMethodComposite { returnType("V") instructions( ResourceType.COLOR("yt_youtube_magenta"), @@ -142,11 +136,12 @@ internal val BytecodePatchContext.lottieCompositionFactoryZipMethod by gettingFi * * [Original method](https://github.com/airbnb/lottie-android/blob/26ad8bab274eac3f93dccccfa0cafc39f7408d13/lottie/src/main/java/com/airbnb/lottie/LottieCompositionFactory.java#L386) */ -internal val BytecodePatchContext.lottieCompositionFactoryFromJsonInputStreamMethod by gettingFirstMethodDeclaratively { +context(_: BytecodePatchContext) +internal fun ClassDef.getLottieCompositionFactoryFromJsonInputStreamMethod() = firstMutableMethodDeclaratively { accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) parameterTypes("Ljava/io/InputStream;", "Ljava/lang/String;") returnType("L") instructions( - anyInstruction(literal(2), literal(3)), + anyOf(2L(), 3L()), ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/SeekbarColorPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/SeekbarColorPatch.kt index 587d89f33..5d0f75c3e 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/SeekbarColorPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/SeekbarColorPatch.kt @@ -1,5 +1,6 @@ package app.revanced.patches.youtube.layout.seekbar +import app.revanced.patcher.* import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.getInstruction import app.revanced.patcher.extensions.replaceInstruction @@ -47,19 +48,19 @@ val seekbarColorPatch = bytecodePatch( ) } - playerSeekbarColorMethod.let { + playerSeekbarColorMethodMatch.let { it.method.apply { addColorChangeInstructions(it.indices.last()) addColorChangeInstructions(it.indices.first()) } } - shortsSeekbarColorMethod.let { + shortsSeekbarColorMethodMatch.let { it.method.addColorChangeInstructions(it.indices.first()) } - setSeekbarClickedColorMethod.immutableMethod.let { - val setColorMethodIndex = setSeekbarClickedColorMethod.indices.first() + 1 + setSeekbarClickedColorMethodMatch.immutableMethod.let { + val setColorMethodIndex = setSeekbarClickedColorMethodMatch.indices.first() + 1 navigate(it).to(setColorMethodIndex).stop().apply { val colorRegister = getInstruction(0).registerA @@ -77,9 +78,9 @@ val seekbarColorPatch = bytecodePatch( // 19.25+ changes - var handleBarColorFingerprints = mutableListOf(playerSeekbarHandle1ColorMethod) + var handleBarColorFingerprints = mutableListOf(playerSeekbarHandle1ColorMethodMatch) if (!is_20_34_or_greater) { - handleBarColorFingerprints += playerSeekbarHandle2ColorMethod + handleBarColorFingerprints += playerSeekbarHandle2ColorMethodMatch } handleBarColorFingerprints.forEach { it.method.addColorChangeInstructions(it.indices.last()) @@ -89,7 +90,7 @@ val seekbarColorPatch = bytecodePatch( // of the watch history menu items as they use the same gradient as the // player and there is no easy way to distinguish which to use a transparent color. if (is_19_34_or_greater) { - watchHistoryMenuUseProgressDrawableMethod.let { + watchHistoryMenuUseProgressDrawableMethodMatch.let { it.method.apply { val index = it.indices[1] val register = getInstruction(index).registerA @@ -113,17 +114,17 @@ val seekbarColorPatch = bytecodePatch( """, ) - val playerFingerprint: Fingerprint + val playerMatch: MatchBuilder val checkGradientCoordinates: Boolean if (is_19_49_or_greater) { - playerFingerprint = playerLinearGradientMethod + playerMatch = playerLinearGradientMethodMatch checkGradientCoordinates = true } else { - playerFingerprint = playerLinearGradientLegacyMethod + playerMatch = playerLinearGradientLegacyMethodMatch checkGradientCoordinates = false } - playerFingerprint.let { + playerMatch.let { it.method.apply { val index = it.indices.last() val register = getInstruction(index).registerA @@ -153,8 +154,7 @@ val seekbarColorPatch = bytecodePatch( // Hook the splash animation to set the a seekbar color. mainActivityOnCreateMethod.apply { - val setAnimationIntMethodName = - lottieAnimationViewSetAnimationIntMethod.immutableMethod.name + val setAnimationIntMethodName = lottieAnimationViewSetAnimationIntMethod.name findInstructionIndicesReversedOrThrow { val reference = getReference() @@ -175,8 +175,7 @@ val seekbarColorPatch = bytecodePatch( // and `setAnimation(InputStream, String)` so extension code can call them. lottieAnimationViewSetAnimationIntMethod.classDef.methods.apply { val addedMethodName = "patch_setAnimation" - val setAnimationIntName = lottieAnimationViewSetAnimationIntMethod - .immutableMethod.name + val setAnimationIntMethodName = lottieAnimationViewSetAnimationIntMethod.name add( ImmutableMethod( @@ -191,9 +190,9 @@ val seekbarColorPatch = bytecodePatch( ).toMutable().apply { addInstructions( """ - invoke-virtual { p0, p1 }, Lcom/airbnb/lottie/LottieAnimationView;->$setAnimationIntName(I)V - return-void - """, + invoke-virtual { p0, p1 }, Lcom/airbnb/lottie/LottieAnimationView;->$setAnimationIntMethodName(I)V + return-void + """, ) }, ) @@ -201,24 +200,21 @@ val seekbarColorPatch = bytecodePatch( val factoryStreamClass: CharSequence val factoryStreamName: CharSequence val factoryStreamReturnType: CharSequence - lottieCompositionFactoryFromJsonInputStreamMethod.match( - lottieCompositionFactoryZipMethod.immutableClassDef, - ).immutableMethod.apply { - factoryStreamClass = definingClass - factoryStreamName = name - factoryStreamReturnType = returnType - } - val lottieAnimationViewSetAnimationStreamFingerprint = fingerprint { + lottieCompositionFactoryZipMethod.immutableClassDef.getLottieCompositionFactoryFromJsonInputStreamMethod() + .let { + factoryStreamClass = it.definingClass + factoryStreamName = it.name + factoryStreamReturnType = it.returnType + } + + val lottieAnimationViewSetAnimationStreamMethod = firstMutableMethodDeclaratively { + definingClass(lottieAnimationViewSetAnimationIntMethod.immutableClassDef.type) accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) parameterTypes(factoryStreamReturnType.toString()) returnType("V") - custom { _, classDef -> - classDef.type == lottieAnimationViewSetAnimationIntMethod.immutableClassDef.type - } } - val setAnimationStreamName = lottieAnimationViewSetAnimationStreamFingerprint - .immutableMethod.name + val setAnimationStreamMethodName = lottieAnimationViewSetAnimationStreamMethod.name add( ImmutableMethod( @@ -236,11 +232,11 @@ val seekbarColorPatch = bytecodePatch( ).toMutable().apply { addInstructions( """ - invoke-static { p1, p2 }, $factoryStreamClass->$factoryStreamName(Ljava/io/InputStream;Ljava/lang/String;)$factoryStreamReturnType - move-result-object v0 - invoke-virtual { p0, v0}, Lcom/airbnb/lottie/LottieAnimationView;->$setAnimationStreamName($factoryStreamReturnType)V - return-void - """, + invoke-static { p1, p2 }, $factoryStreamClass->$factoryStreamName(Ljava/io/InputStream;Ljava/lang/String;)$factoryStreamReturnType + move-result-object v0 + invoke-virtual { p0, v0}, Lcom/airbnb/lottie/LottieAnimationView;->$setAnimationStreamMethodName($factoryStreamReturnType)V + return-void + """, ) }, ) diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/shortsautoplay/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/shortsautoplay/Fingerprints.kt index f69bea26f..9c6551e70 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/shortsautoplay/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/shortsautoplay/Fingerprints.kt @@ -1,18 +1,10 @@ package app.revanced.patches.youtube.layout.shortsautoplay -import app.revanced.patcher.accessFlags -import app.revanced.patcher.afterAtMost -import app.revanced.patcher.field -import app.revanced.patcher.firstMethodComposite -import app.revanced.patcher.gettingFirstMethodDeclaratively -import app.revanced.patcher.instructions -import app.revanced.patcher.invoke -import app.revanced.patcher.method -import app.revanced.patcher.parameterTypes +import app.revanced.patcher.* import app.revanced.patcher.patch.BytecodePatchContext -import app.revanced.patcher.returnType import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.iface.ClassDef internal val reelEnumConstructorMethodMatch = firstMethodComposite { accessFlags(AccessFlags.STATIC, AccessFlags.CONSTRUCTOR) @@ -36,7 +28,8 @@ internal val BytecodePatchContext.reelPlaybackRepeatParentMethod by gettingFirst /** * Matches class found in [reelPlaybackRepeatParentMethod]. */ -internal val BytecodePatchContext.reelPlaybackRepeatMethod by gettingFirstMethodDeclaratively { +context(_: BytecodePatchContext) +internal fun ClassDef.getReelPlaybackRepeatMethod() = firstMutableMethodDeclaratively { returnType("V") parameterTypes("L") instructions(method { toString() == "Lcom/google/common/util/concurrent/ListenableFuture;->isDone()Z" }) @@ -54,14 +47,15 @@ internal val reelPlaybackMethodMatch = firstMethodComposite { 15, method { name == "" && - parameterTypes.zip(methodParametersPrefix).all { (a, b) -> a.startsWith(b) } + parameterTypes.zip(methodParametersPrefix).all { (a, b) -> a.startsWith(b) } }, ), - methodCall( - opcode = Opcode.INVOKE_VIRTUAL, - parameters = listOf("L"), - returnType = "I", - afterAtMost(5), + afterAtMost( + 5, + allOf( + Opcode.INVOKE_VIRTUAL(), + method { returnType == "I" && parameterTypes.count() == 1 && parameterTypes.first() == "L" }, + ), ), ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/shortsautoplay/ShortsAutoplayPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/shortsautoplay/ShortsAutoplayPatch.kt index 0303a3afe..0f9b9661c 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/shortsautoplay/ShortsAutoplayPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/shortsautoplay/ShortsAutoplayPatch.kt @@ -1,5 +1,6 @@ package app.revanced.patches.youtube.layout.shortsautoplay +import app.revanced.patcher.classDef import app.revanced.patcher.extensions.addInstruction import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.addInstructionsWithLabels @@ -88,15 +89,15 @@ val `Shorts autoplay` by creatingBytecodePatch( ) } - reelPlaybackRepeatMethod.match( - reelPlaybackRepeatParentMethod.immutableClassDef, - ).method.apply { + val reelPlaybackRepeatMethod = reelPlaybackRepeatParentMethod.immutableClassDef.getReelPlaybackRepeatMethod() + + reelPlaybackRepeatMethod.apply { // The behavior enums are looked up from an ordinal value to an enum type. findInstructionIndicesReversedOrThrow { val reference = getReference() reference?.definingClass == reelEnumClass && - reference.parameterTypes.firstOrNull() == "I" && - reference.returnType == reelEnumClass + reference.parameterTypes.firstOrNull() == "I" && + reference.returnType == reelEnumClass }.forEach { index -> val register = getInstruction(index + 1).registerA @@ -123,14 +124,14 @@ val `Shorts autoplay` by creatingBytecodePatch( // Find the first call modified by extension code above. val extensionReturnResultIndex = indexOfFirstInstructionOrThrow { opcode == Opcode.INVOKE_STATIC && - getReference()?.definingClass == EXTENSION_CLASS_DESCRIPTOR + getReference()?.definingClass == EXTENSION_CLASS_DESCRIPTOR } + 1 val enumRegister = getInstruction(extensionReturnResultIndex).registerA val getReelSequenceControllerIndex = indexOfFirstInstructionOrThrow { val reference = getReference() opcode == Opcode.IGET_OBJECT && - reference?.definingClass == definingClass && - reference.type == reelSequenceControllerMethodReference.definingClass + reference?.definingClass == definingClass && + reference.type == reelSequenceControllerMethodReference.definingClass } val getReelSequenceControllerReference = getInstruction(getReelSequenceControllerIndex).reference diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/Fingerprints.kt index b27ba7362..06dcbbe79 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/Fingerprints.kt @@ -6,7 +6,7 @@ import app.revanced.patches.shared.misc.mapping.ResourceType import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -internal val BytecodePatchContext.toolBarButtonMethod by gettingFirstMethodDeclaratively { +internal val toolBarButtonMethodMatch = firstMethodComposite { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("V") instructions( @@ -21,7 +21,7 @@ internal val BytecodePatchContext.toolBarButtonMethod by gettingFirstMethodDecla custom { parameterTypes.count() in 1..2 && parameterTypes.first() == "Landroid/view/MenuItem;" } } -internal val BytecodePatchContext.spoofAppVersionMethod by gettingFirstMethodDeclaratively( +internal val spoofAppVersionMethodMatch = firstMethodComposite( // Instead of applying a bytecode patch, it might be possible to only rely on code from the extension and // manually set the desired version string as this keyed value in the SharedPreferences. // But, this bytecode patch is simple and it works. diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/SpoofAppVersionPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/SpoofAppVersionPatch.kt index 191398139..c3f4d9f3e 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/SpoofAppVersionPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/SpoofAppVersionPatch.kt @@ -81,23 +81,23 @@ val `Spoof app version` by creatingBytecodePatch( * missing image resources. As a workaround, do not set an image in the * toolbar when the enum name is UNKNOWN. */ - toolBarButtonMethod.apply { - val imageResourceIndex = indices[2] - val register = method.getInstruction(imageResourceIndex).registerA - val jumpIndex = indices.last() + 1 + toolBarButtonMethodMatch.let { + val imageResourceIndex = it.indices[2] + val register = it.method.getInstruction(imageResourceIndex).registerA + val jumpIndex = it.indices.last() + 1 - method.addInstructionsWithLabels( + it.method.addInstructionsWithLabels( imageResourceIndex + 1, "if-eqz v$register, :ignore", - ExternalLabel("ignore", method.getInstruction(jumpIndex)), + ExternalLabel("ignore", it.method.getInstruction(jumpIndex)), ) } - spoofAppVersionMethod.apply { - val index = indices.first() - val register = method.getInstruction(index).registerA + spoofAppVersionMethodMatch.let { + val index = it.indices.first() + val register = it.method.getInstruction(index).registerA - method.addInstructions( + it.method.addInstructions( index + 1, """ invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->getYouTubeVersionOverride(Ljava/lang/String;)Ljava/lang/String; diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/DisableResumingShortsOnStartupPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/DisableResumingShortsOnStartupPatch.kt index f9ca0c061..6577f5b2c 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/DisableResumingShortsOnStartupPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/DisableResumingShortsOnStartupPatch.kt @@ -1,6 +1,7 @@ package app.revanced.patches.youtube.layout.startupshortsreset import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.getInstruction import app.revanced.patcher.patch.creatingBytecodePatch import app.revanced.patches.all.misc.resources.addResources import app.revanced.patches.all.misc.resources.addResourcesPatch @@ -49,11 +50,10 @@ val `Disable resuming Shorts on startup` by creatingBytecodePatch( ) if (is_20_03_or_greater) { - userWasInShortsAlternativeMethod.let { + userWasInShortsAlternativeMethodMatch.let { it.method.apply { - val match = it.instructionMatches[2] - val insertIndex = match.index + 1 - val register = match.getInstruction().registerA + val insertIndex = it.indices[2] + 1 + val register = getInstruction(insertIndex).registerA addInstructions( insertIndex, @@ -68,8 +68,8 @@ val `Disable resuming Shorts on startup` by creatingBytecodePatch( userWasInShortsLegacyMethod.apply { val listenableInstructionIndex = indexOfFirstInstructionOrThrow { opcode == Opcode.INVOKE_INTERFACE && - getReference()?.definingClass == "Lcom/google/common/util/concurrent/ListenableFuture;" && - getReference()?.name == "isDone" + getReference()?.definingClass == "Lcom/google/common/util/concurrent/ListenableFuture;" && + getReference()?.name == "isDone" } val freeRegister = findFreeRegister(listenableInstructionIndex) diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/Fingerprints.kt index ec5560ae4..1d5abef2c 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/Fingerprints.kt @@ -1,30 +1,23 @@ package app.revanced.patches.youtube.layout.startupshortsreset -import app.revanced.patcher.StringComparisonType -import app.revanced.patcher.accessFlags -import app.revanced.patcher.checkCast -import app.revanced.patcher.gettingFirstMethodDeclaratively -import app.revanced.patcher.instructions -import app.revanced.patcher.invoke -import app.revanced.patcher.parameterTypes +import app.revanced.patcher.* import app.revanced.patcher.patch.BytecodePatchContext -import app.revanced.patcher.returnType import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode /** * 20.02+ */ -internal val BytecodePatchContext.userWasInShortsAlternativeMethod by gettingFirstMethodDeclaratively { +internal val userWasInShortsAlternativeMethodMatch = firstMethodComposite { returnType("V") accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) parameterTypes("Ljava/lang/Object;") instructions( - checkCast("Ljava/lang/Boolean;"), - methodCall(smali = "Ljava/lang/Boolean;->booleanValue()Z", after()), + allOf(Opcode.CHECK_CAST(), type("Ljava/lang/Boolean;")), + after(method { toString() == "Ljava/lang/Boolean;->booleanValue()Z" }), after(Opcode.MOVE_RESULT()), // 20.40+ string was merged into another string and is a partial match. - addString("userIsInShorts: ", comparison = StringComparisonType.CONTAINS, afterAtMost(15)), + afterAtMost(15, "userIsInShorts: "(String::contains)), ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/theme/ThemePatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/theme/ThemePatch.kt index efcda2b9d..946f8eb8d 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/theme/ThemePatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/theme/ThemePatch.kt @@ -33,7 +33,7 @@ val themePatch = baseThemePatch( block = { val lightThemeBackgroundColor by stringOption( - key = "lightThemeBackgroundColor", + name = "Light theme background color", default = "@android:color/white", values = mapOf( "White" to "@android:color/white", @@ -46,7 +46,6 @@ val themePatch = baseThemePatch( "Light orange" to "#FFE6CC", "Light red" to "#FFD6D6", ), - name = "Light theme background color", description = THEME_COLOR_OPTION_DESCRIPTION, ) diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/BackgroundPlaybackPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/BackgroundPlaybackPatch.kt index 523298e24..5105d71d8 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/BackgroundPlaybackPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/BackgroundPlaybackPatch.kt @@ -56,16 +56,13 @@ val `Remove background playback restrictions` by creatingBytecodePatch( SwitchPreference("revanced_shorts_disable_background_playback"), ) - prefBackgroundAndOfflineCategoryId = getResourceId( - ResourceType.STRING, - "pref_background_and_offline_category", - ) + prefBackgroundAndOfflineCategoryId = ResourceType.STRING["pref_background_and_offline_category"] arrayOf( backgroundPlaybackManagerMethod to "isBackgroundPlaybackAllowed", backgroundPlaybackManagerShortsMethod to "isBackgroundShortsPlaybackAllowed", - ).forEach { (fingerprint, integrationsMethod) -> - fingerprint.method.apply { + ).forEach { (method, integrationsMethod) -> + method.apply { findInstructionIndicesReversedOrThrow(Opcode.RETURN).forEach { index -> val register = getInstruction(index).registerA @@ -81,7 +78,7 @@ val `Remove background playback restrictions` by creatingBytecodePatch( } // Enable background playback option in YouTube settings - backgroundPlaybackSettingsMethod.immutableMethod.apply { + backgroundPlaybackSettingsMethod.apply { val booleanCalls = instructions.withIndex().filter { it.value.getReference()?.returnType == "Z" } @@ -101,7 +98,7 @@ val `Remove background playback restrictions` by creatingBytecodePatch( // Fix PiP buttons not working after locking/unlocking device screen. if (is_19_34_or_greater) { - pipInputConsumerFeatureFlagMethod.let { + pipInputConsumerFeatureFlagMethodMatch.let { it.method.insertLiteralOverride( it.indices.first(), false, diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/Fingerprints.kt index 00b99ff5a..1b9f07fdd 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/Fingerprints.kt @@ -1,17 +1,12 @@ package app.revanced.patches.youtube.misc.backgroundplayback -import app.revanced.patcher.accessFlags -import app.revanced.patcher.gettingFirstMethodDeclaratively -import app.revanced.patcher.instructions -import app.revanced.patcher.opcodes -import app.revanced.patcher.parameterTypes +import app.revanced.patcher.* import app.revanced.patcher.patch.BytecodePatchContext -import app.revanced.patcher.returnType import app.revanced.util.literal import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -internal val BytecodePatchContext.backgroundPlaybackManagerMethod by gettingFirstMethodDeclaratively { +internal val BytecodePatchContext.backgroundPlaybackManagerMethod by gettingFirstMutableMethodDeclaratively { accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) returnType("Z") parameterTypes("L") @@ -60,7 +55,7 @@ internal val BytecodePatchContext.backgroundPlaybackSettingsMethod by gettingFir literal { prefBackgroundAndOfflineCategoryId } } -internal val BytecodePatchContext.kidsBackgroundPlaybackPolicyControllerMethod by gettingFirstMethodDeclaratively { +internal val BytecodePatchContext.kidsBackgroundPlaybackPolicyControllerMethod by gettingFirstMutableMethodDeclaratively { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("V") parameterTypes("I", "L", "L") @@ -77,28 +72,24 @@ internal val BytecodePatchContext.kidsBackgroundPlaybackPolicyControllerMethod b literal { 5 } } -internal val BytecodePatchContext.backgroundPlaybackManagerShortsMethod by gettingFirstMethodDeclaratively { +internal val BytecodePatchContext.backgroundPlaybackManagerShortsMethod by gettingFirstMutableMethodDeclaratively { accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) returnType("Z") parameterTypes("L") - instructions( - app.revanced.patcher.literal(151635310), - ) + instructions(151635310L()) } -internal val BytecodePatchContext.shortsBackgroundPlaybackFeatureFlagMethod by gettingFirstMethodDeclaratively { +internal val BytecodePatchContext.shortsBackgroundPlaybackFeatureFlagMethod by gettingFirstMutableMethodDeclaratively { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("Z") parameterTypes() - instructions( - app.revanced.patcher.literal(45415425), - ) + instructions(45415425L()) } // Fix 'E/InputDispatcher: Window handle pip_input_consumer has no registered input channel' -internal val BytecodePatchContext.pipInputConsumerFeatureFlagMethod by gettingFirstMethodDeclaratively { +internal val pipInputConsumerFeatureFlagMethodMatch = firstMethodComposite { instructions( // PiP input consumer feature flag. - app.revanced.patcher.literal(45638483L), + 45638483L(), ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/dns/CheckWatchHistoryDomainNameResolutionPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/dns/CheckWatchHistoryDomainNameResolutionPatch.kt index 1a0da97e2..3266d228b 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/dns/CheckWatchHistoryDomainNameResolutionPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/dns/CheckWatchHistoryDomainNameResolutionPatch.kt @@ -1,7 +1,9 @@ package app.revanced.patches.youtube.misc.dns +import app.revanced.patcher.patch.BytecodePatchContext import app.revanced.patches.shared.misc.dns.checkWatchHistoryDomainNameResolutionPatch import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch +import app.revanced.patches.youtube.shared.mainActivityOnCreateMethod val checkWatchHistoryDomainNameResolutionPatch = checkWatchHistoryDomainNameResolutionPatch( block = { @@ -18,5 +20,5 @@ val checkWatchHistoryDomainNameResolutionPatch = checkWatchHistoryDomainNameReso ) ) }, - getMainActivityMethod = mainActivityOnCreateFingerprint + getMainActivityMethod = BytecodePatchContext::mainActivityOnCreateMethod::get ) diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/backtoexitgesture/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/backtoexitgesture/Fingerprints.kt index 5afc84e4e..5e798a09f 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/backtoexitgesture/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/backtoexitgesture/Fingerprints.kt @@ -1,15 +1,6 @@ package app.revanced.patches.youtube.misc.fix.backtoexitgesture -import app.revanced.patcher.accessFlags -import app.revanced.patcher.after -import app.revanced.patcher.checkCast -import app.revanced.patcher.firstMethodComposite -import app.revanced.patcher.instructions -import app.revanced.patcher.invoke -import app.revanced.patcher.literal -import app.revanced.patcher.opcodes -import app.revanced.patcher.parameterTypes -import app.revanced.patcher.returnType +import app.revanced.patcher.* import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode @@ -29,11 +20,11 @@ internal val recyclerViewTopScrollingMethodMatch = firstMethodComposite { returnType("V") parameterTypes() instructions( - methodCall(smali = "Ljava/util/Iterator;->next()Ljava/lang/Object;"), + method { toString() == "Ljava/util/Iterator;->next()Ljava/lang/Object;" }, after(Opcode.MOVE_RESULT_OBJECT()), - checkCast("Landroid/support/v7/widget/RecyclerView;", MatchAfterImmediately()), - literal(0, after()), - methodCall(definingClass = "Landroid/support/v7/widget/RecyclerView;", after()), + after(allOf(Opcode.CHECK_CAST(), type("Landroid/support/v7/widget/RecyclerView;"))), + after(0L()), + after(method { definingClass == "Landroid/support/v7/widget/RecyclerView;" }), after(Opcode.GOTO()), ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playbackspeed/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playbackspeed/Fingerprints.kt index e1cea4203..07ff1d21d 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playbackspeed/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playbackspeed/Fingerprints.kt @@ -1,7 +1,9 @@ package app.revanced.patches.youtube.misc.fix.playbackspeed import app.revanced.patcher.accessFlags +import app.revanced.patcher.custom import app.revanced.patcher.gettingFirstMethodDeclaratively +import app.revanced.patcher.gettingFirstMutableMethodDeclaratively import app.revanced.patcher.opcodes import app.revanced.patcher.parameterTypes import app.revanced.patcher.patch.BytecodePatchContext @@ -17,7 +19,7 @@ import com.android.tools.smali.dexlib2.iface.reference.FieldReference * This method is usually used to set the initial speed (1.0x) when playback starts from the feed. * For some reason, in the latest YouTube, it is invoked even after the video has already started. */ -internal val BytecodePatchContext.playbackSpeedInFeedsMethod by gettingFirstMethodDeclaratively { +internal val BytecodePatchContext.playbackSpeedInFeedsMethod by gettingFirstMutableMethodDeclaratively { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("V") parameterTypes("L") @@ -31,8 +33,8 @@ internal val BytecodePatchContext.playbackSpeedInFeedsMethod by gettingFirstMeth Opcode.IF_LEZ, Opcode.SUB_LONG_2ADDR, ) - custom { method, _ -> - indexOfGetPlaybackSpeedInstruction(method) >= 0 + custom { + indexOfGetPlaybackSpeedInstruction(this) >= 0 } } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/Fingerprints.kt index f878a9f0b..ef5b08094 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/Fingerprints.kt @@ -2,23 +2,22 @@ package app.revanced.patches.youtube.misc.litho.filter import app.revanced.patcher.* import app.revanced.patcher.patch.BytecodePatchContext -import app.revanced.util.containsLiteralInstruction import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -internal val BytecodePatchContext.componentCreateMethod by gettingFirstMethodDeclaratively { +internal val BytecodePatchContext.componentCreateMethod by gettingFirstMutableMethodDeclaratively { instructions( "Element missing correct type extension"(), "Element missing type"(), ) } -internal val BytecodePatchContext.lithoFilterMethod by gettingFirstMethodDeclaratively { +internal val BytecodePatchContext.lithoFilterMethod by gettingFirstMutableMethodDeclaratively { definingClass { endsWith("/LithoFilterPatch;") } accessFlags(AccessFlags.STATIC, AccessFlags.CONSTRUCTOR) } -internal val BytecodePatchContext.protobufBufferReferenceMethod by gettingFirstMethodDeclaratively { +internal val protobufBufferReferenceMethodMatch = firstMethodComposite { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("V") parameterTypes("[B") @@ -38,7 +37,7 @@ internal val BytecodePatchContext.protobufBufferReferenceMethod by gettingFirstM ) } -internal val BytecodePatchContext.protobufBufferReferenceLegacyMethod by gettingFirstMethodDeclaratively { +internal val BytecodePatchContext.protobufBufferReferenceLegacyMethod by gettingFirstMutableMethodDeclaratively { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("V") parameterTypes("I", "Ljava/nio/ByteBuffer;") @@ -57,27 +56,23 @@ internal val BytecodePatchContext.emptyComponentMethod by gettingFirstMethodDecl custom { immutableClassDef.methods.filter { AccessFlags.STATIC.isSet(it.accessFlags) }.size == 1 } } -internal val BytecodePatchContext.lithoThreadExecutorMethod by gettingFirstMethodDeclaratively { +internal val BytecodePatchContext.lithoThreadExecutorMethod by gettingFirstMutableMethodDeclaratively { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) parameterTypes("I", "I", "I") + instructions(1L()) // 1L = default thread timeout. custom { - immutableClassDef.superclass == "Ljava/util/concurrent/ThreadPoolExecutor;" && - containsLiteralInstruction(1L) // 1L = default thread timeout. + immutableClassDef.superclass == "Ljava/util/concurrent/ThreadPoolExecutor;" } } -internal val BytecodePatchContext.lithoComponentNameUpbFeatureFlagMethod by gettingFirstMethodDeclaratively { +internal val BytecodePatchContext.lithoComponentNameUpbFeatureFlagMethod by gettingFirstMutableMethodDeclaratively { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("Z") parameterTypes() - instructions( - 45631264L(), - ) + instructions(45631264L()) } -internal val BytecodePatchContext.lithoConverterBufferUpbFeatureFlagMethod by gettingFirstMethodDeclaratively { +internal val lithoConverterBufferUpbFeatureFlagMethodMatch = firstMethodComposite { returnType("L") - instructions( - 45419603L(), - ) + instructions(45419603L()) } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/LithoFilterPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/LithoFilterPatch.kt index 512ce3cf0..834b9a65a 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/LithoFilterPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/LithoFilterPatch.kt @@ -7,6 +7,7 @@ import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.removeInstructions import app.revanced.patcher.extensions.replaceInstruction import app.revanced.patcher.firstClassDef +import app.revanced.patcher.immutableClassDef import app.revanced.patcher.patch.bytecodePatch import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch import app.revanced.patches.youtube.misc.playservice.* @@ -90,7 +91,7 @@ val lithoFilterPatch = bytecodePatch( if (is_20_22_or_greater) { // Hook method that bridges between UPB buffer native code and FB Litho. // Method is found in 19.25+, but is forcefully turned off for 20.21 and lower. - protobufBufferReferenceMethod.let { + protobufBufferReferenceMethodMatch.let { // Hook the buffer after the call to jniDecode(). it.method.addInstruction( it.indices.last() + 1, @@ -112,14 +113,14 @@ val lithoFilterPatch = bytecodePatch( // Find the identifier/path fields of the conversion context. - val conversionContextIdentifierField = conversionContextToStringMethod.method + val conversionContextIdentifierField = conversionContextToStringMethod .findFieldFromToString("identifierProperty=") val conversionContextPathBuilderField = conversionContextToStringMethod.immutableClassDef .fields.single { field -> field.type == "Ljava/lang/StringBuilder;" } // Find class and methods to create an empty component. - val builderMethodDescriptor = emptyComponentMethod.classDef.methods.single { + val builderMethodDescriptor = emptyComponentMethod.immutableClassDef.methods.single { // The only static method in the class. method -> AccessFlags.STATIC.isSet(method.accessFlags) @@ -146,7 +147,7 @@ val lithoFilterPatch = bytecodePatch( # 20.41 field is the abstract superclass. # Verify it's the expected subclass just in case. - instance-of v$identifierRegister, v$freeRegister, ${conversionContextToStringMethod.classDef.type} + instance-of v$identifierRegister, v$freeRegister, ${conversionContextToStringMethod.immutableClassDef.type} if-eqz v$identifierRegister, :unfiltered iget-object v$identifierRegister, v$freeRegister, $conversionContextIdentifierField @@ -196,7 +197,7 @@ val lithoFilterPatch = bytecodePatch( } // Turn off a feature flag that enables native code of protobuf parsing (Upb protobuf). - lithoConverterBufferUpbFeatureFlagMethod.let { + lithoConverterBufferUpbFeatureFlagMethodMatch.let { // 20.22 the flag is still enabled in one location, but what it does is not known. // Disable it anyway. it.method.insertLiteralOverride( diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/navigation/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/navigation/Fingerprints.kt index 80394fb77..2ddb4b0a7 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/navigation/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/navigation/Fingerprints.kt @@ -12,20 +12,23 @@ import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.ClassDef -internal val BytecodePatchContext.actionBarSearchResultsMethod by gettingFirstMethodDeclaratively { +internal val actionBarSearchResultsMethodMatch = firstMethodComposite { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("Landroid/view/View;") instructions( ResourceType.LAYOUT("action_bar_search_results_view_mic"), - methodCall(name = "setLayoutDirection"), + method("setLayoutDirection"), ) } -internal val BytecodePatchContext.toolbarLayoutMethod by gettingFirstMethodDeclaratively { +internal val toolbarLayoutMethodMatch = firstMethodComposite { accessFlags(AccessFlags.PROTECTED, AccessFlags.CONSTRUCTOR) instructions( ResourceType.ID("toolbar_container"), - checkCast("Lcom/google/android/apps/youtube/app/ui/actionbar/MainCollapsingToolbarLayout;"), + allOf( + Opcode.CHECK_CAST(), + type("Lcom/google/android/apps/youtube/app/ui/actionbar/MainCollapsingToolbarLayout;") + ) ) } @@ -33,12 +36,10 @@ internal val BytecodePatchContext.toolbarLayoutMethod by gettingFirstMethodDecla * Matches to https://android.googlesource.com/platform/frameworks/support/+/9eee6ba/v7/appcompat/src/android/support/v7/widget/Toolbar.java#963 */ internal val BytecodePatchContext.appCompatToolbarBackButtonMethod by gettingFirstMethodDeclaratively { + definingClass("Landroid/support/v7/widget/Toolbar;") accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("Landroid/graphics/drawable/Drawable;") parameterTypes() - custom { _, classDef -> - classDef.type == "Landroid/support/v7/widget/Toolbar;" - } } /** @@ -57,62 +58,57 @@ internal fun ClassDef.getInitializeButtonsMethod() = firstMutableMethodDeclarati * Extension method, used for callback into to other patches. * Specifically, [navigationButtonsPatch]. */ -internal val BytecodePatchContext.navigationBarHookCallbackMethod by gettingFirstMethodDeclaratively { +internal val BytecodePatchContext.navigationBarHookCallbackMethod by gettingFirstMutableMethodDeclaratively { + name("navigationTabCreatedCallback") + definingClass(EXTENSION_CLASS_DESCRIPTOR) accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC) returnType("V") parameterTypes(EXTENSION_NAVIGATION_BUTTON_DESCRIPTOR, "Landroid/view/View;") - custom { method, _ -> - method.name == "navigationTabCreatedCallback" && - method.definingClass == EXTENSION_CLASS_DESCRIPTOR - } } /** * Matches to the Enum class that looks up ordinal -> instance. */ -internal val BytecodePatchContext.navigationEnumMethod by gettingFirstMethodDeclaratively { +internal val BytecodePatchContext.navigationEnumMethod by gettingFirstMethodDeclaratively( + "PIVOT_HOME", + "TAB_SHORTS", + "CREATION_TAB_LARGE", + "PIVOT_SUBSCRIPTIONS", + "TAB_ACTIVITY", + "VIDEO_LIBRARY_WHITE", + "INCOGNITO_CIRCLE", + "UNKNOWN", // Required to distinguish from patch extension class. +) { accessFlags(AccessFlags.STATIC, AccessFlags.CONSTRUCTOR) - strings( - "PIVOT_HOME", - "TAB_SHORTS", - "CREATION_TAB_LARGE", - "PIVOT_SUBSCRIPTIONS", - "TAB_ACTIVITY", - "VIDEO_LIBRARY_WHITE", - "INCOGNITO_CIRCLE", - "UNKNOWN", // Required to distinguish from patch extension class. - ) } internal val BytecodePatchContext.pivotBarButtonsCreateDrawableViewMethod by gettingFirstMethodDeclaratively { + definingClass("Lcom/google/android/libraries/youtube/rendering/ui/pivotbar/PivotBar;") accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("Landroid/view/View;") - custom { method, _ -> - method.definingClass == "Lcom/google/android/libraries/youtube/rendering/ui/pivotbar/PivotBar;" && - // Only one view creation method has a Drawable parameter. - method.parameterTypes.firstOrNull() == "Landroid/graphics/drawable/Drawable;" + custom { + // Only one view creation method has a Drawable parameter. + parameterTypes.firstOrNull() == "Landroid/graphics/drawable/Drawable;" } } internal val BytecodePatchContext.pivotBarButtonsCreateResourceStyledViewMethod by gettingFirstMethodDeclaratively { + definingClass("Lcom/google/android/libraries/youtube/rendering/ui/pivotbar/PivotBar;") accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("Landroid/view/View;") parameterTypes("L", "Z", "I", "L") - custom { method, _ -> - method.definingClass == "Lcom/google/android/libraries/youtube/rendering/ui/pivotbar/PivotBar;" - } } /** * 20.21+ */ internal val BytecodePatchContext.pivotBarButtonsCreateResourceIntViewMethod by gettingFirstMethodDeclaratively { + definingClass("Lcom/google/android/libraries/youtube/rendering/ui/pivotbar/PivotBar;") accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("Landroid/view/View;") - custom { method, _ -> - method.definingClass == "Lcom/google/android/libraries/youtube/rendering/ui/pivotbar/PivotBar;" && - // Only one view creation method has an int first parameter. - method.parameterTypes.firstOrNull() == "I" + custom { + // Only one view creation method has an int first parameter. + parameterTypes.firstOrNull() == "I" } } @@ -131,7 +127,7 @@ internal val BytecodePatchContext.pivotBarConstructorMethod by gettingFirstMetho ) } -internal val BytecodePatchContext.imageEnumConstructorMethod by gettingFirstMethodDeclaratively { +internal val imageEnumConstructorMethodMatch = firstMethodComposite { accessFlags(AccessFlags.STATIC, AccessFlags.CONSTRUCTOR) instructions( "TAB_ACTIVITY_CAIRO"(), @@ -140,13 +136,13 @@ internal val BytecodePatchContext.imageEnumConstructorMethod by gettingFirstMeth ) } -internal val BytecodePatchContext.setEnumMapMethod by gettingFirstMethodDeclaratively { +internal val setEnumMapMethodMatch = firstMethodComposite { instructions( ResourceType.DRAWABLE("yt_fill_bell_black_24"), - methodCall(smali = "Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;", afterAtMost(10)), - methodCall( - smali = "Ljava/util/EnumMap;->put(Ljava/lang/Enum;Ljava/lang/Object;)Ljava/lang/Object;", - afterAtMost(10), - ), + afterAtMost(10, method { toString() == "Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;" }), + afterAtMost( + 10, + method { toString() == "Ljava/util/EnumMap;->put(Ljava/lang/Enum;Ljava/lang/Object;)Ljava/lang/Object;" } + ) ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/navigation/NavigationBarHookPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/navigation/NavigationBarHookPatch.kt index 6bdbb13ec..27c8c856e 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/navigation/NavigationBarHookPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/navigation/NavigationBarHookPatch.kt @@ -5,6 +5,7 @@ import app.revanced.patcher.extensions.addInstruction import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.getInstruction import app.revanced.patcher.extensions.instructions +import app.revanced.patcher.extensions.reference import app.revanced.patcher.immutableClassDef import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.bytecodePatch @@ -72,7 +73,7 @@ val navigationBarHookPatch = bytecodePatch(description = "Hooks the active navig addInstruction( insertIndex, "invoke-static { v$register }, " + - "$EXTENSION_CLASS_DESCRIPTOR->${hook.methodName}(${hook.parameters})V", + "$EXTENSION_CLASS_DESCRIPTOR->${hook.methodName}(${hook.parameters})V", ) } } @@ -82,7 +83,7 @@ val navigationBarHookPatch = bytecodePatch(description = "Hooks the active navig val navigationEnumClassName = navigationEnumMethod.classDef.type addHook(NavigationHook.SET_LAST_APP_NAVIGATION_ENUM) { opcode == Opcode.INVOKE_STATIC && - getReference()?.definingClass == navigationEnumClassName + getReference()?.definingClass == navigationEnumClassName } // Hook the creation of navigation tab views. @@ -120,7 +121,7 @@ val navigationBarHookPatch = bytecodePatch(description = "Hooks the active navig addInstruction( index + 1, "invoke-static { v$viewRegister, v$isSelectedRegister }, " + - "$EXTENSION_CLASS_DESCRIPTOR->navigationTabSelected(Landroid/view/View;Z)V", + "$EXTENSION_CLASS_DESCRIPTOR->navigationTabSelected(Landroid/view/View;Z)V", ) } @@ -136,7 +137,7 @@ val navigationBarHookPatch = bytecodePatch(description = "Hooks the active navig // Two different layouts are used at the hooked code. // Insert before the first ViewGroup method call after inflating, // so this works regardless which layout is used. - actionBarSearchResultsMethod.let { + actionBarSearchResultsMethodMatch.let { it.method.apply { val instructionIndex = it.indices.last() val viewRegister = getInstruction(instructionIndex).registerC @@ -144,14 +145,14 @@ val navigationBarHookPatch = bytecodePatch(description = "Hooks the active navig addInstruction( instructionIndex, "invoke-static { v$viewRegister }, " + - "$EXTENSION_CLASS_DESCRIPTOR->searchBarResultsViewLoaded(Landroid/view/View;)V", + "$EXTENSION_CLASS_DESCRIPTOR->searchBarResultsViewLoaded(Landroid/view/View;)V", ) } } // Hook the back button visibility. - toolbarLayoutMethod.let { + toolbarLayoutMethodMatch.let { it.method.apply { val index = it.indices.last() val register = getInstruction(index).registerA @@ -164,43 +165,41 @@ val navigationBarHookPatch = bytecodePatch(description = "Hooks the active navig } // Add interface for extensions code to call obfuscated methods. - appCompatToolbarBackButtonMethod.let { - it.classDef.apply { - interfaces.add(EXTENSION_TOOLBAR_INTERFACE) + appCompatToolbarBackButtonMethod.classDef.apply { + interfaces.add(EXTENSION_TOOLBAR_INTERFACE) - val definingClass = type - val obfuscatedMethodName = it.immutableMethod.name - val returnType = "Landroid/graphics/drawable/Drawable;" + val definingClass = type + val obfuscatedMethodName = appCompatToolbarBackButtonMethod.name + val returnType = "Landroid/graphics/drawable/Drawable;" - methods.add( - ImmutableMethod( - definingClass, - "patch_getNavigationIcon", - listOf(), - returnType, - AccessFlags.PUBLIC.value or AccessFlags.FINAL.value, - null, - null, - MutableMethodImplementation(2), - ).toMutable().apply { - addInstructions( - 0, - """ + methods.add( + ImmutableMethod( + definingClass, + "patch_getNavigationIcon", + listOf(), + returnType, + AccessFlags.PUBLIC.value or AccessFlags.FINAL.value, + null, + null, + MutableMethodImplementation(2), + ).toMutable().apply { + addInstructions( + 0, + """ invoke-virtual { p0 }, $definingClass->$obfuscatedMethodName()$returnType move-result-object v0 return-object v0 """, - ) - }, - ) - } + ) + }, + ) } hookNavigationButtonCreated = { extensionClassDescriptor -> navigationBarHookCallbackMethod.addInstruction( 0, "invoke-static { p0, p1 }, $extensionClassDescriptor->navigationTabCreated" + - "(${EXTENSION_NAVIGATION_BUTTON_DESCRIPTOR}Landroid/view/View;)V", + "(${EXTENSION_NAVIGATION_BUTTON_DESCRIPTOR}Landroid/view/View;)V", ) } @@ -212,22 +211,24 @@ val navigationBarHookPatch = bytecodePatch(description = "Hooks the active navig // Fix YT bug of notification tab missing the filled icon. if (is_19_35_or_greater && !is_20_39_or_greater) { // FIXME: 20.39+ needs this fix. - val cairoNotificationEnumReference = imageEnumConstructorMethod - .instructionMatches.last().getInstruction().reference + val cairoNotificationEnumReference = + imageEnumConstructorMethodMatch.method.getInstruction(imageEnumConstructorMethodMatch.indices.last()).reference - setEnumMapMethod.apply { - val setEnumIntegerIndex = setEnumMapMethod.indices.last() - val enumMapRegister = getInstruction(setEnumIntegerIndex).registerC - val insertIndex = setEnumIntegerIndex + 1 - val freeRegister = findFreeRegister(insertIndex, enumMapRegister) + setEnumMapMethodMatch.apply { + val setEnumIntegerIndex = setEnumMapMethodMatch.indices.last() + method.apply { + val enumMapRegister = getInstruction(setEnumIntegerIndex).registerC + val insertIndex = setEnumIntegerIndex + 1 + val freeRegister = findFreeRegister(insertIndex, enumMapRegister) - addInstructions( - insertIndex, - """ - sget-object v$freeRegister, $cairoNotificationEnumReference - invoke-static { v$enumMapRegister, v$freeRegister }, $EXTENSION_CLASS_DESCRIPTOR->setCairoNotificationFilledIcon(Ljava/util/EnumMap;Ljava/lang/Enum;)V - """, - ) + addInstructions( + insertIndex, + """ + sget-object v$freeRegister, $cairoNotificationEnumReference + invoke-static { v$enumMapRegister, v$freeRegister }, $EXTENSION_CLASS_DESCRIPTOR->setCairoNotificationFilledIcon(Ljava/util/EnumMap;Ljava/lang/Enum;)V + """, + ) + } } } } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/Fingerprints.kt index 6e568cd70..1a511610b 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/Fingerprints.kt @@ -7,7 +7,7 @@ import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.ClassDef -internal val BytecodePatchContext.playerControlsVisibilityEntityModelMethod by gettingFirstMethodDeclaratively { +internal val playerControlsVisibilityEntityModelMethodMatch = firstMethodComposite { name("getPlayerControlsVisibility") accessFlags(AccessFlags.PUBLIC) returnType("L") diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/PlayerControlsOverlayVisibilityPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/PlayerControlsOverlayVisibilityPatch.kt index 13eb7689d..d4eaabb6b 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/PlayerControlsOverlayVisibilityPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/PlayerControlsOverlayVisibilityPatch.kt @@ -16,7 +16,7 @@ val playerControlsOverlayVisibilityPatch = bytecodePatch { dependsOn(sharedExtensionPatch) apply { - playerControlsVisibilityEntityModelMethod.let { + playerControlsVisibilityEntityModelMethodMatch.let { it.method.apply { val startIndex = it.indices.first() val iGetReference = getInstruction(startIndex).reference diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/recyclerviewtree/hook/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/recyclerviewtree/hook/Fingerprints.kt index 51926e4bd..bbd73d846 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/recyclerviewtree/hook/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/recyclerviewtree/hook/Fingerprints.kt @@ -1,13 +1,12 @@ package app.revanced.patches.youtube.misc.recyclerviewtree.hook import app.revanced.patcher.accessFlags -import app.revanced.patcher.gettingFirstMethodDeclaratively +import app.revanced.patcher.firstMethodComposite import app.revanced.patcher.opcodes -import app.revanced.patcher.patch.BytecodePatchContext import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -internal val BytecodePatchContext.recyclerViewTreeObserverMethod by gettingFirstMethodDeclaratively { +internal val recyclerViewTreeObserverMethodMatch = firstMethodComposite("LithoRVSLCBinder") { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) opcodes( Opcode.CHECK_CAST, @@ -16,5 +15,4 @@ internal val BytecodePatchContext.recyclerViewTreeObserverMethod by gettingFirst Opcode.INVOKE_VIRTUAL, Opcode.NEW_INSTANCE, ) - strings("LithoRVSLCBinder") } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/recyclerviewtree/hook/RecyclerViewTreeHookPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/recyclerviewtree/hook/RecyclerViewTreeHookPatch.kt index c26060aa6..ed861cb1c 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/recyclerviewtree/hook/RecyclerViewTreeHookPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/recyclerviewtree/hook/RecyclerViewTreeHookPatch.kt @@ -11,12 +11,12 @@ val recyclerViewTreeHookPatch = bytecodePatch { dependsOn(sharedExtensionPatch) apply { - recyclerViewTreeObserverMethod.apply { - val insertIndex = recyclerViewTreeObserverMethod.indices.first() + 1 + recyclerViewTreeObserverMethodMatch.let { + val insertIndex = it.indices.first() + 1 val recyclerViewParameter = 2 addRecyclerViewTreeHook = { classDescriptor -> - addInstruction( + it.method.addInstruction( insertIndex, "invoke-static/range { p$recyclerViewParameter .. p$recyclerViewParameter }, " + "$classDescriptor->onFlyoutMenuCreate(Landroid/support/v7/widget/RecyclerView;)V", diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/spoof/SpoofVideoStreamsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/spoof/SpoofVideoStreamsPatch.kt index ffe6d364f..c0a31d47b 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/spoof/SpoofVideoStreamsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/spoof/SpoofVideoStreamsPatch.kt @@ -1,5 +1,6 @@ package app.revanced.patches.youtube.misc.spoof +import app.revanced.patcher.patch.BytecodePatchContext import app.revanced.patches.all.misc.resources.addResources import app.revanced.patches.shared.misc.settings.preference.ListPreference import app.revanced.patches.shared.misc.settings.preference.NonInteractivePreference @@ -13,10 +14,11 @@ import app.revanced.patches.youtube.misc.playservice.is_20_14_or_greater import app.revanced.patches.youtube.misc.playservice.versionCheckPatch import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.settingsPatch +import app.revanced.patches.youtube.shared.mainActivityOnCreateMethod val spoofVideoStreamsPatch = spoofVideoStreamsPatch( extensionClassDescriptor = "Lapp/revanced/extension/youtube/patches/spoof/SpoofVideoStreamsPatch;", - getMainActivityOnCreateMethod = mainActivityOnCreateFingerprint, + getMainActivityOnCreateMethod = BytecodePatchContext::mainActivityOnCreateMethod::get, fixMediaFetchHotConfig = { is_19_34_or_greater }, diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/shared/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/shared/Fingerprints.kt index 96b647c07..9bb669c9d 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/shared/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/shared/Fingerprints.kt @@ -78,7 +78,7 @@ internal val BytecodePatchContext.mainActivityOnCreateMethod by gettingFirstMuta parameterTypes("Landroid/os/Bundle;") } -internal val BytecodePatchContext.rollingNumberTextViewAnimationUpdateMethod by gettingFirstMethodDeclaratively { +internal val rollingNumberTextViewAnimationUpdateMethodMatch = firstMethodComposite { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("V") parameterTypes("Landroid/graphics/Bitmap;") diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/video/audio/ForceOriginalAudioPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/video/audio/ForceOriginalAudioPatch.kt index 888dbb7e5..94761f9ff 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/video/audio/ForceOriginalAudioPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/video/audio/ForceOriginalAudioPatch.kt @@ -1,11 +1,13 @@ package app.revanced.patches.youtube.video.audio +import app.revanced.patcher.patch.BytecodePatchContext import app.revanced.patches.shared.misc.audio.forceOriginalAudioPatch import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch import app.revanced.patches.youtube.misc.playservice.is_20_07_or_greater import app.revanced.patches.youtube.misc.playservice.versionCheckPatch import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.settingsPatch +import app.revanced.patches.youtube.shared.mainActivityOnCreateMethod @Suppress("unused") val forceOriginalAudioPatch = forceOriginalAudioPatch( @@ -26,7 +28,7 @@ val forceOriginalAudioPatch = forceOriginalAudioPatch( ) }, fixUseLocalizedAudioTrackFlag = { is_20_07_or_greater }, - getMainActivityOnCreateMethod = mainActivityOnCreateFingerprint, + getMainActivityOnCreateMethod = BytecodePatchContext::mainActivityOnCreateMethod::get, subclassExtensionClassDescriptor = "Lapp/revanced/extension/youtube/patches/ForceOriginalAudioPatch;", preferenceScreen = PreferenceScreen.VIDEO, ) diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/video/codecs/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/video/codecs/Fingerprints.kt index 3faf55962..72dc8f96c 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/video/codecs/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/video/codecs/Fingerprints.kt @@ -2,15 +2,15 @@ package app.revanced.patches.youtube.video.codecs import app.revanced.patcher.accessFlags import app.revanced.patcher.gettingFirstMethodDeclaratively +import app.revanced.patcher.gettingFirstMutableMethodDeclaratively import app.revanced.patcher.patch.BytecodePatchContext import app.revanced.patcher.returnType import com.android.tools.smali.dexlib2.AccessFlags -internal val BytecodePatchContext.vp9CapabilityMethod by gettingFirstMethodDeclaratively { +internal val BytecodePatchContext.vp9CapabilityMethod by gettingFirstMutableMethodDeclaratively( + "vp9_supported", + "video/x-vnd.on2.vp9", +) { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("Z") - strings( - "vp9_supported", - "video/x-vnd.on2.vp9", - ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/Fingerprints.kt index cd78c7057..02990d50b 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/Fingerprints.kt @@ -7,7 +7,7 @@ import com.android.tools.smali.dexlib2.AccessFlags /** * For targets 20.46 and later. */ -internal val BytecodePatchContext.playerParameterBuilderMethod by gettingFirstMethodDeclaratively { +internal val BytecodePatchContext.playerParameterBuilderMethod by gettingFirstMutableMethodDeclaratively { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("L") parameterTypes( @@ -33,7 +33,7 @@ internal val BytecodePatchContext.playerParameterBuilderMethod by gettingFirstMe /** * For targets 20.26 and later. */ -internal val BytecodePatchContext.playerParameterBuilder2026Method by gettingFirstMethodDeclaratively { +internal val BytecodePatchContext.playerParameterBuilder2026Method by gettingFirstMutableMethodDeclaratively { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("L") parameterTypes( @@ -60,7 +60,7 @@ internal val BytecodePatchContext.playerParameterBuilder2026Method by gettingFir /** * For targets 20.15 to 20.25 */ -internal val BytecodePatchContext.playerParameterBuilder2015Method by gettingFirstMethodDeclaratively { +internal val BytecodePatchContext.playerParameterBuilder2015Method by gettingFirstMutableMethodDeclaratively { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("L") parameterTypes( @@ -86,7 +86,7 @@ internal val BytecodePatchContext.playerParameterBuilder2015Method by gettingFir /** * For targets 20.10 to 20.14. */ -internal val BytecodePatchContext.playerParameterBuilder2010Method by gettingFirstMethodDeclaratively { +internal val BytecodePatchContext.playerParameterBuilder2010Method by gettingFirstMutableMethodDeclaratively { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("L") parameterTypes( @@ -113,7 +113,7 @@ internal val BytecodePatchContext.playerParameterBuilder2010Method by gettingFir /** * For targets 20.02 to 20.09. */ -internal val BytecodePatchContext.playerParameterBuilder2002Method by gettingFirstMethodDeclaratively { +internal val BytecodePatchContext.playerParameterBuilder2002Method by gettingFirstMutableMethodDeclaratively { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("L") parameterTypes( @@ -139,7 +139,7 @@ internal val BytecodePatchContext.playerParameterBuilder2002Method by gettingFir /** * For targets 19.25 to 19.50. */ -internal val BytecodePatchContext.playerParameterBuilder1925Method by gettingFirstMethodDeclaratively { +internal val BytecodePatchContext.playerParameterBuilder1925Method by gettingFirstMutableMethodDeclaratively { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("L") parameterTypes( @@ -164,7 +164,7 @@ internal val BytecodePatchContext.playerParameterBuilder1925Method by gettingFir /** * For targets 19.01 to 19.24. */ -internal val BytecodePatchContext.playerParameterBuilderLegacyMethod by gettingFirstMethodDeclaratively { +internal val BytecodePatchContext.playerParameterBuilderLegacyMethod by gettingFirstMutableMethodDeclaratively { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("L") parameterTypes( diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/PlayerResponseMethodHookPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/PlayerResponseMethodHookPatch.kt index c1eb87c01..5d9bbddb6 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/PlayerResponseMethodHookPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/PlayerResponseMethodHookPatch.kt @@ -40,30 +40,30 @@ val playerResponseMethodHookPatch = bytecodePatch { ) apply { - val fingerprint: Fingerprint + val method: MutableMethod if (is_20_46_or_greater) { parameterIsShortAndOpeningOrPlaying = 13 - fingerprint = playerParameterBuilderMethod + method = playerParameterBuilderMethod } else if (is_20_26_or_greater) { parameterIsShortAndOpeningOrPlaying = 13 - fingerprint = playerParameterBuilder2026Method + method = playerParameterBuilder2026Method } else if (is_20_15_or_greater) { parameterIsShortAndOpeningOrPlaying = 13 - fingerprint = playerParameterBuilder2015Method + method = playerParameterBuilder2015Method } else if (is_20_10_or_greater) { parameterIsShortAndOpeningOrPlaying = 13 - fingerprint = playerParameterBuilder2010Method + method = playerParameterBuilder2010Method } else if (is_20_02_or_greater) { parameterIsShortAndOpeningOrPlaying = 12 - fingerprint = playerParameterBuilder2002Method + method = playerParameterBuilder2002Method } else if (is_19_23_or_greater) { parameterIsShortAndOpeningOrPlaying = 12 - fingerprint = playerParameterBuilder1925Method + method = playerParameterBuilder1925Method } else { parameterIsShortAndOpeningOrPlaying = 11 - fingerprint = playerParameterBuilderLegacyMethod + method = playerParameterBuilderLegacyMethod } - playerResponseMethod = fingerprint.method + playerResponseMethod = method // On some app targets the method has too many registers pushing the parameters past v15. // If needed, move the parameters to 4-bit registers, so they can be passed to the extension. diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/video/quality/AdvancedVideoQualityMenuPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/video/quality/AdvancedVideoQualityMenuPatch.kt index cd3c46108..8ed829f26 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/video/quality/AdvancedVideoQualityMenuPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/video/quality/AdvancedVideoQualityMenuPatch.kt @@ -18,7 +18,7 @@ import app.revanced.patches.youtube.misc.recyclerviewtree.hook.recyclerViewTreeH import app.revanced.patches.youtube.misc.settings.settingsPatch import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction -internal var videoQualityBottomSheetListFragmentname = -1L +internal var videoQualityBottomSheetListFragmentTitle = -1L private set internal var videoQualityQuickMenuAdvancedMenuDescription = -1L private set @@ -47,7 +47,7 @@ internal val advancedVideoQualityMenuPatch = bytecodePatch { ) // Used for the old type of the video quality menu. - videoQualityBottomSheetListFragmentname = + videoQualityBottomSheetListFragmentTitle = ResourceType.LAYOUT["video_quality_bottom_sheet_list_fragment_title"] videoQualityQuickMenuAdvancedMenuDescription = ResourceType.STRING["video_quality_quick_menu_advanced_menu_description"]