This commit is contained in:
oSumAtrIX 2026-01-23 23:26:14 +01:00
parent e192cbae52
commit 466043132a
No known key found for this signature in database
GPG key ID: A9B3094ACDB604B4
203 changed files with 1786 additions and 1262 deletions

View file

@ -1,12 +1,17 @@
package app.revanced.patches.com.sbs.ondemand.tv
import app.revanced.patcher.accessFlags
import app.revanced.patcher.definingClass
import app.revanced.patcher.gettingFirstMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.instructions
import app.revanced.patcher.invoke
import app.revanced.patcher.name
import app.revanced.patcher.opcodes
import app.revanced.patcher.parameterTypes
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
internal val BytecodePatchContext.shouldShowAdvertisingTVMethod by gettingFirstMutableMethodDeclaratively {
import app.revanced.patcher.returnTypeinternal val BytecodePatchContext.shouldShowAdvertisingTVMethod by gettingFirstMutableMethodDeclaratively {
name("getShouldShowAdvertisingTV")
definingClass("Lcom/sbs/ondemand/common/InMemoryStorage;")
returnType("Z")
@ -16,11 +21,10 @@ internal val BytecodePatchContext.shouldShowPauseAdMethod by gettingFirstMutable
name("shouldShowPauseAd")
definingClass("Lcom/sbs/ondemand/player/viewmodels/PauseAdController;")
returnType("Z")
}
internal val BytecodePatchContext.requestAdStreamMethod by gettingFirstMutableMethodDeclaratively {
name("requestAdStream\$player_googleStoreTvRelease")
definingClass("Lcom/sbs/ondemand/player/viewmodels/AdsController;")
returnType("V")
}
}

View file

@ -3,7 +3,6 @@ package app.revanced.patches.instagram.feed
import app.revanced.patcher.classDef
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.fingerprint
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.patches.instagram.misc.extension.sharedExtensionPatch
import app.revanced.util.getReference
@ -41,13 +40,13 @@ val `Limit feed to followed profiles` by creatingBytecodePatch(
}
}
val initMainFeedRequestFingerprint = fingerprint {
val initMainFeedRequestMethod = fingerprint {
custom { method, classDef ->
method.name == "<init>" &&
classDef == mainFeedRequestClassMethod.classDef
}
}
initMainFeedRequestFingerprint.method.apply {
initMainFeedRequestMethod.apply {
// Finds the instruction where the map is being initialized in the constructor
val getHeaderIndex = indexOfFirstInstructionOrThrow {
getReference<FieldReference>().let {

View file

@ -1,11 +1,17 @@
package app.revanced.patches.instagram.hide.navigation
import app.revanced.patcher.fingerprint
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.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.AccessFlags
internal val initializeNavigationButtonsListFingerprint = fingerprint {
internal val BytecodePatchContext.initializeNavigationButtonsListMethod by gettingFirstMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
parameterTypes("Lcom/instagram/common/session/UserSession;", "Z")
returnType("Ljava/util/List;")

View file

@ -1,7 +1,6 @@
package app.revanced.patches.instagram.hide.navigation
import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.fingerprint
import app.revanced.patcher.patch.booleanOption
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.patches.instagram.misc.extension.sharedExtensionPatch
@ -21,7 +20,7 @@ private const val EXTENSION_CLASS_DESCRIPTOR =
@Suppress("unused", "ObjectPropertyName")
val `Hide navigation buttons` by creatingBytecodePatch(
description = "Hides navigation bar buttons, such as the Reels and Create button.",
use = false
use = false,
) {
compatibleWith("com.instagram.android"("401.0.0.48.79"))
@ -30,53 +29,52 @@ val `Hide navigation buttons` by creatingBytecodePatch(
val hideHome by booleanOption(
default = false,
name = "Hide Home",
description = "Permanently hides the Home button. App starts at next available tab." // On the "homecoming" / current instagram layout.
description = "Permanently hides the Home button. App starts at next available tab.", // On the "homecoming" / current instagram layout.
)
val hideReels by booleanOption(
default = true,
name = "Hide Reels",
description = "Permanently hides the Reels button."
description = "Permanently hides the Reels button.",
)
val hideDirect by booleanOption(
default = false,
name = "Hide Direct",
description = "Permanently hides the Direct button."
description = "Permanently hides the Direct button.",
)
val hideSearch by booleanOption(
default = false,
name = "Hide Search",
description = "Permanently hides the Search button."
description = "Permanently hides the Search button.",
)
val hideProfile by booleanOption(
default = false,
name = "Hide Profile",
description = "Permanently hides the Profile button."
description = "Permanently hides the Profile button.",
)
val hideCreate by booleanOption(
default = true,
name = "Hide Create",
description = "Permanently hides the Create button."
description = "Permanently hides the Create button.",
)
apply {
if (!hideHome!! && !hideReels!! && !hideDirect!! && !hideSearch!! && !hideProfile!! && !hideCreate!!) {
return@apply Logger.getLogger(this::class.java.name).warning(
"No hide navigation buttons options are enabled. No changes made."
"No hide navigation buttons options are enabled. No changes made.",
)
}
// Get the field name which contains the name of the enum for the navigation button
// ("fragment_clips", "fragment_share", ...)
val navigationButtonsEnumInitFingerprint = fingerprint {
custom { method, classDef ->
method.name == "<init>"
&& classDef == navigationButtonsEnumClassDef.classDef
method.name == "<init>" &&
classDef == navigationButtonsEnumClassDef.classDef
}
}
@ -84,68 +82,65 @@ val `Hide navigation buttons` by creatingBytecodePatch(
with(navigationButtonsEnumInitFingerprint.method) {
enumNameField = indexOfFirstInstructionOrThrow {
opcode == Opcode.IPUT_OBJECT &&
(this as TwoRegisterInstruction).registerA == 2 // p2 register.
(this as TwoRegisterInstruction).registerA == 2 // p2 register.
}.let {
getInstruction(it).getReference<FieldReference>()!!.name
}
}
initializeNavigationButtonsListFingerprint.method.apply {
initializeNavigationButtonsListMethod.apply {
val returnIndex = indexOfFirstInstructionOrThrow(Opcode.RETURN_OBJECT)
val buttonsListRegister = getInstruction<OneRegisterInstruction>(returnIndex).registerA
val freeRegister = findFreeRegister(returnIndex)
val freeRegister2 = findFreeRegister(returnIndex, freeRegister)
fun instructionsRemoveButtonByName(buttonEnumName: String): String {
return """
fun instructionsRemoveButtonByName(buttonEnumName: String): String = """
const-string v$freeRegister, "$buttonEnumName"
const-string v$freeRegister2, "$enumNameField"
invoke-static { v$buttonsListRegister, v$freeRegister, v$freeRegister2 }, $EXTENSION_CLASS_DESCRIPTOR->removeNavigationButtonByName(Ljava/util/List;Ljava/lang/String;Ljava/lang/String;)Ljava/util/List;
move-result-object v$buttonsListRegister
"""
}
if (hideHome!!) {
addInstructionsAtControlFlowLabel(
returnIndex,
instructionsRemoveButtonByName("fragment_feed")
instructionsRemoveButtonByName("fragment_feed"),
)
}
if (hideReels!!) {
addInstructionsAtControlFlowLabel(
returnIndex,
instructionsRemoveButtonByName("fragment_clips")
instructionsRemoveButtonByName("fragment_clips"),
)
}
if (hideDirect!!) {
addInstructionsAtControlFlowLabel(
returnIndex,
instructionsRemoveButtonByName("fragment_direct_tab")
instructionsRemoveButtonByName("fragment_direct_tab"),
)
}
if (hideSearch!!) {
addInstructionsAtControlFlowLabel(
returnIndex,
instructionsRemoveButtonByName("fragment_search")
instructionsRemoveButtonByName("fragment_search"),
)
}
if (hideCreate!!) {
addInstructionsAtControlFlowLabel(
returnIndex,
instructionsRemoveButtonByName("fragment_share")
instructionsRemoveButtonByName("fragment_share"),
)
}
if (hideProfile!!) {
addInstructionsAtControlFlowLabel(
returnIndex,
instructionsRemoveButtonByName("fragment_profile")
instructionsRemoveButtonByName("fragment_profile"),
)
}
}
}
}

View file

@ -14,6 +14,6 @@ val `Hide Stories from Home` by creatingBytecodePatch(
val addStoryEndIndex = getOrCreateAvatarViewMethod.indices.last()
// Remove addView of Story.
getOrCreateAvatarViewMethod.method.removeInstruction(addStoryEndIndex)
getOrCreateAvatarViewMethod.removeInstruction(addStoryEndIndex)
}
}

View file

@ -15,22 +15,21 @@ val `Enable developer menu` by creatingBytecodePatch(
It is recommended to use this patch with an alpha/beta Instagram release. Patching a stable release works, but the developer menu shows the developer flags as numbers and does not show a human readable description.
""".trimIndentMultiline(),
use = false
use = false,
) {
compatibleWith("com.instagram.android")
apply {
with(clearNotificationReceiverFingerprint.method) {
indexOfFirstInstructionReversedOrThrow(clearNotificationReceiverFingerprint.stringMatches.first().index) {
with(clearNotificationReceiverMethod) {
indexOfFirstInstructionReversedOrThrow(clearNotificationReceiverMethod.stringMatches.first().index) {
val reference = getReference<MethodReference>()
opcode in listOf(Opcode.INVOKE_STATIC, Opcode.INVOKE_STATIC_RANGE) &&
reference?.parameterTypes?.size == 1 &&
reference.parameterTypes.first() == "Lcom/instagram/common/session/UserSession;" &&
reference.returnType == "Z"
reference?.parameterTypes?.size == 1 &&
reference.parameterTypes.first() == "Lcom/instagram/common/session/UserSession;" &&
reference.returnType == "Z"
}.let { index ->
navigate(this).to(index).stop().returnEarly(true)
}
}
}
}

View file

@ -1,9 +1,7 @@
package app.revanced.patches.instagram.misc.devmenu
import app.revanced.patcher.fingerprint
internal val clearNotificationReceiverFingerprint = fingerprint {
internal val BytecodePatchContext.clearNotificationReceiverMethod by gettingFirstMethodDeclaratively {
custom { method, classDef ->
method.name == "onReceive" &&
classDef.type == "Lcom/instagram/notifications/push/ClearNotificationReceiver;"

View file

@ -2,25 +2,25 @@ package app.revanced.patches.instagram.misc.share
import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.patch.BytecodePatchContext
import com.android.tools.smali.dexlib2.mutable.MutableMethod
import app.revanced.util.indexOfFirstInstruction
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
import com.android.tools.smali.dexlib2.mutable.MutableMethod
context(BytecodePatchContext)
internal fun editShareLinksPatch(block: MutableMethod.(index: Int, register: Int) -> Unit) {
val fingerprintsToPatch = arrayOf(
permalinkResponseJsonParserFingerprint,
storyUrlResponseJsonParserFingerprint,
profileUrlResponseJsonParserFingerprint,
liveUrlResponseJsonParserFingerprint
permalinkResponseJsonParserMethod,
storyUrlResponseJsonParserMethod,
profileUrlResponseJsonParserMethod,
liveUrlResponseJsonParserMethod,
)
for (fingerprint in fingerprintsToPatch) {
fingerprint.method.apply {
val putSharingUrlIndex = indexOfFirstInstruction(
permalinkResponseJsonParserFingerprint.stringMatches.first().index,
Opcode.IPUT_OBJECT
permalinkResponseJsonParserMethod.stringMatches.first().index,
Opcode.IPUT_OBJECT,
)
val sharingUrlRegister = getInstruction<TwoRegisterInstruction>(putSharingUrlIndex).registerA

View file

@ -1,24 +1,23 @@
package app.revanced.patches.instagram.misc.share
import app.revanced.patcher.fingerprint
import com.google.common.util.concurrent.Striped.custom
internal val permalinkResponseJsonParserFingerprint = fingerprint {
internal val BytecodePatchContext.permalinkResponseJsonParserMethod by gettingFirstMethodDeclaratively {
strings("permalink", "PermalinkResponse")
custom { method, _ -> method.name == "parseFromJson" }
}
internal val storyUrlResponseJsonParserFingerprint = fingerprint {
internal val BytecodePatchContext.storyUrlResponseJsonParserMethod by gettingFirstMethodDeclaratively {
strings("story_item_to_share_url", "StoryItemUrlResponse")
custom { method, _ -> method.name == "parseFromJson" }
}
internal val profileUrlResponseJsonParserFingerprint = fingerprint {
internal val BytecodePatchContext.profileUrlResponseJsonParserMethod by gettingFirstMethodDeclaratively {
strings("profile_to_share_url", "ProfileUrlResponse")
custom { method, _ -> method.name == "parseFromJson" }
}
internal val liveUrlResponseJsonParserFingerprint = fingerprint {
internal val BytecodePatchContext.liveUrlResponseJsonParserMethod by gettingFirstMethodDeclaratively {
strings("live_to_share_url", "LiveItemLinkUrlResponse")
custom { method, _ -> method.name == "parseFromJson" }
}

View file

@ -13,7 +13,7 @@ internal const val EXTENSION_CLASS_DESCRIPTOR =
@Suppress("unused")
val `Change link sharing domain` by creatingBytecodePatch(
description = "Replaces the domain name of shared links.",
use = false
use = false,
) {
compatibleWith("com.instagram.android")
@ -22,11 +22,11 @@ val `Change link sharing domain` by creatingBytecodePatch(
val customDomainHost by stringOption(
default = "imginn.com",
name = "Domain name",
description = "The domain name to use when sharing links."
description = "The domain name to use when sharing links.",
)
apply {
getCustomShareDomainFingerprint.method.returnEarly(customDomainHost!!)
getCustomShareDomainMethod.returnEarly(customDomainHost!!)
editShareLinksPatch { index, register ->
addInstructions(
@ -34,7 +34,7 @@ val `Change link sharing domain` by creatingBytecodePatch(
"""
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->setCustomShareDomain(Ljava/lang/String;)Ljava/lang/String;
move-result-object v$register
"""
""",
)
}
}

View file

@ -1,9 +1,13 @@
package app.revanced.patches.instagram.misc.share.domain
import app.revanced.patcher.fingerprint
import app.revanced.patcher.accessFlags
import app.revanced.patcher.gettingFirstMethodDeclaratively
import app.revanced.patcher.parameterTypes
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.AccessFlags
internal val getCustomShareDomainFingerprint = fingerprint {
internal val BytecodePatchContext.getCustomShareDomainMethod by gettingFirstMethodDeclaratively {
accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC)
returnType("Ljava/lang/String;")
parameterTypes()

View file

@ -1,15 +1,22 @@
package app.revanced.patches.instagram.misc.signature
import app.revanced.patcher.fingerprint
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.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
internal val isValidSignatureClassFingerprint = fingerprint {
internal val BytecodePatchContext.isValidSignatureClassMethod by gettingFirstMethodDeclaratively {
strings("The provider for uri '", "' is not trusted: ")
}
internal val isValidSignatureMethodFingerprint = fingerprint {
internal val BytecodePatchContext.isValidSignatureMethodMethod by gettingFirstMethodDeclaratively {
parameterTypes("L", "Z")
returnType("Z")
custom { method, _ ->

View file

@ -6,14 +6,14 @@ import app.revanced.util.returnEarly
@Suppress("unused")
val `Disable signature check` by creatingBytecodePatch(
description = "Disables the signature check that can cause the app to crash on startup. " +
"Using this patch may cause issues with sharing or opening external Instagram links.",
use = false
"Using this patch may cause issues with sharing or opening external Instagram links.",
use = false,
) {
compatibleWith("com.instagram.android")
apply {
isValidSignatureMethodFingerprint
.match(isValidSignatureClassFingerprint.classDef)
isValidSignatureMethodMethod
.match(isValidSignatureClassMethod.classDef)
.method
.returnEarly(true)
}

View file

@ -1,9 +1,16 @@
package app.revanced.patches.music.ad.video
import app.revanced.patcher.fingerprint
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.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.Opcode
internal val showVideoAdsParentFingerprint = fingerprint {
internal val BytecodePatchContext.showVideoAdsParentMethod by gettingFirstMethodDeclaratively {
opcodes(
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_VIRTUAL,

View file

@ -24,8 +24,8 @@ val `Hide music video ads` by creatingBytecodePatch(
compatibleWith(
"com.google.android.apps.youtube.music"(
"7.29.52",
"8.10.52"
)
"8.10.52",
),
)
apply {
@ -35,15 +35,15 @@ val `Hide music video ads` by creatingBytecodePatch(
SwitchPreference("revanced_music_hide_video_ads"),
)
navigate(showVideoAdsParentFingerprint.originalMethod)
.to(showVideoAdsParentFingerprint.instructionMatches.first().index + 1)
navigate(showVideoAdsParentMethod.originalMethod)
.to(showVideoAdsParentMethod.instructionMatches.first().index + 1)
.stop()
.addInstructions(
0,
"""
invoke-static { p1 }, $EXTENSION_CLASS_DESCRIPTOR->showVideoAds(Z)Z
move-result p1
"""
""",
)
}
}

View file

@ -17,11 +17,11 @@ val `Enable exclusive audio playback` by creatingBytecodePatch(
compatibleWith(
"com.google.android.apps.youtube.music"(
"7.29.52",
"8.10.52"
)
"8.10.52",
),
)
apply {
allowExclusiveAudioPlaybackFingerprint.method.returnEarly(true)
allowExclusiveAudioPlaybackMethod.returnEarly(true)
}
}

View file

@ -1,10 +1,17 @@
package app.revanced.patches.music.audio.exclusiveaudio
import app.revanced.patcher.fingerprint
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.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
internal val allowExclusiveAudioPlaybackFingerprint = fingerprint {
internal val BytecodePatchContext.allowExclusiveAudioPlaybackMethod by gettingFirstMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("Z")
parameterTypes()

View file

@ -1,10 +1,17 @@
package app.revanced.patches.music.layout.compactheader
import app.revanced.patcher.fingerprint
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.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import app.revanced.util.literal
import com.android.tools.smali.dexlib2.Opcode
internal val chipCloudFingerprint = fingerprint {
internal val BytecodePatchContext.chipCloudMethod by gettingFirstMethodDeclaratively {
returnType("V")
opcodes(
Opcode.CONST,

View file

@ -43,8 +43,8 @@ val `Hide category bar` by creatingBytecodePatch(
chipCloud = ResourceType.LAYOUT["chip_cloud"]
chipCloudFingerprint.method.apply {
val targetIndex = chipCloudFingerprint.patternMatch.endIndex
chipCloudMethod.apply {
val targetIndex = chipCloudMethod.patternMatch.endIndex
val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
addInstruction(

View file

@ -22,20 +22,20 @@ private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/music/pa
@Suppress("unused")
val `Change miniplayer color` by creatingBytecodePatch(
description = "Adds an option to change the miniplayer background color to match the fullscreen player."
description = "Adds an option to change the miniplayer background color to match the fullscreen player.",
) {
dependsOn(
sharedExtensionPatch,
settingsPatch,
addResourcesPatch,
resourceMappingPatch
resourceMappingPatch,
)
compatibleWith(
"com.google.android.apps.youtube.music"(
"7.29.52",
"8.10.52"
)
"8.10.52",
),
)
apply {
@ -45,34 +45,37 @@ val `Change miniplayer color` by creatingBytecodePatch(
SwitchPreference("revanced_music_change_miniplayer_color"),
)
switchToggleColorFingerprint.match(miniPlayerConstructorFingerprint.classDef).let {
switchToggleColorMethod.match(miniPlayerConstructorMethod.classDef).let {
val relativeIndex = it.patternMatch.endIndex + 1
val invokeVirtualIndex = it.method.indexOfFirstInstructionOrThrow(
relativeIndex, Opcode.INVOKE_VIRTUAL
relativeIndex,
Opcode.INVOKE_VIRTUAL,
)
val colorMathPlayerInvokeVirtualReference = it.method
.getInstruction<ReferenceInstruction>(invokeVirtualIndex).reference
val iGetIndex = it.method.indexOfFirstInstructionOrThrow(
relativeIndex, Opcode.IGET
relativeIndex,
Opcode.IGET,
)
val colorMathPlayerIGetReference = it.method
.getInstruction<ReferenceInstruction>(iGetIndex).reference as FieldReference
val colorGreyIndex = miniPlayerConstructorFingerprint.method.indexOfFirstInstructionReversedOrThrow {
val colorGreyIndex = miniPlayerConstructorMethod.indexOfFirstInstructionReversedOrThrow {
getReference<MethodReference>()?.name == "getColor"
}
val iPutIndex = miniPlayerConstructorFingerprint.method.indexOfFirstInstructionOrThrow(
colorGreyIndex, Opcode.IPUT
val iPutIndex = miniPlayerConstructorMethod.indexOfFirstInstructionOrThrow(
colorGreyIndex,
Opcode.IPUT,
)
val colorMathPlayerIPutReference = miniPlayerConstructorFingerprint.method
val colorMathPlayerIPutReference = miniPlayerConstructorMethod
.getInstruction<ReferenceInstruction>(iPutIndex).reference
miniPlayerConstructorFingerprint.classDef.methods.single { method ->
miniPlayerConstructorMethod.classDef.methods.single { method ->
method.accessFlags == AccessFlags.PUBLIC.value or AccessFlags.FINAL.value &&
method.returnType == "V" &&
method.parameters == it.originalMethod.parameters
method.returnType == "V" &&
method.parameters == it.originalMethod.parameters
}.apply {
val insertIndex = indexOfFirstInstructionReversedOrThrow(Opcode.INVOKE_DIRECT)
val freeRegister = findFreeRegister(insertIndex)
@ -90,7 +93,7 @@ val `Change miniplayer color` by creatingBytecodePatch(
iput v$freeRegister, p0, $colorMathPlayerIPutReference
:off
nop
"""
""",
)
}
}

View file

@ -1,11 +1,18 @@
package app.revanced.patches.music.layout.miniplayercolor
import app.revanced.patcher.fingerprint
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.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
internal val miniPlayerConstructorFingerprint = fingerprint {
internal val BytecodePatchContext.miniPlayerConstructorMethod by gettingFirstMethodDeclaratively {
returnType("V")
instructions(
ResourceType.ID("mpp_player_bottom_sheet"),
@ -14,9 +21,9 @@ internal val miniPlayerConstructorFingerprint = fingerprint {
}
/**
* Matches to the class found in [miniPlayerConstructorFingerprint].
* Matches to the class found in [miniPlayerConstructorMethod].
*/
internal val switchToggleColorFingerprint = fingerprint {
internal val BytecodePatchContext.switchToggleColorMethod by gettingFirstMethodDeclaratively {
accessFlags(AccessFlags.PRIVATE, AccessFlags.FINAL)
returnType("V")
parameterTypes("L", "J")

View file

@ -1,6 +1,13 @@
package app.revanced.patches.music.layout.navigationbar
import app.revanced.patcher.fingerprint
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.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import app.revanced.util.containsLiteralInstruction
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
@ -9,7 +16,7 @@ import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
internal val tabLayoutTextFingerprint = fingerprint {
internal val BytecodePatchContext.tabLayoutTextMethod by gettingFirstMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("V")
parameterTypes("L")

View file

@ -82,7 +82,7 @@ val `Navigation bar` by creatingBytecodePatch(
),
)
tabLayoutTextFingerprint.method.apply {
tabLayoutTextMethod.apply {
// Hide navigation labels.
val constIndex = indexOfFirstLiteralInstructionOrThrow(text1)
val targetIndex = indexOfFirstInstructionOrThrow(constIndex, Opcode.CHECK_CAST)
@ -99,7 +99,7 @@ val `Navigation bar` by creatingBytecodePatch(
)
// Set navigation enum and hide navigation buttons.
val enumIndex = tabLayoutTextFingerprint.patternMatch.startIndex + 3
val enumIndex = tabLayoutTextMethod.patternMatch.startIndex + 3
val enumRegister = getInstruction<OneRegisterInstruction>(enumIndex).registerA
val insertEnumIndex = indexOfFirstInstructionOrThrow(Opcode.AND_INT_LIT8) - 2

View file

@ -1,12 +1,17 @@
package app.revanced.patches.nunl.ads
import app.revanced.patcher.*
import app.revanced.patcher.accessFlags
import app.revanced.patcher.gettingFirstMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.instructions
import app.revanced.patcher.invoke
import app.revanced.patcher.opcodes
import app.revanced.patcher.parameterTypes
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnTypeinternal
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
internal val BytecodePatchContext.jwPlayerConfigMethod by gettingFirstMutableMethodDeclaratively {
import com.android.tools.smali.dexlib2.Opcode val BytecodePatchContext.jwPlayerConfigMethod by gettingFirstMutableMethodDeclaratively {
name("advertisingConfig")
definingClass($$"Lcom/jwplayer/pub/api/configuration/PlayerConfig$Builder;")
accessFlags(AccessFlags.PUBLIC)

View file

@ -27,13 +27,13 @@ private val mipmapDirectories = mapOf(
"mipmap-hdpi" to "162x162 px",
"mipmap-xhdpi" to "216x216 px",
"mipmap-xxhdpi" to "324x324 px",
"mipmap-xxxhdpi" to "432x432 px"
"mipmap-xxxhdpi" to "432x432 px",
)
private val iconStyleNames = arrayOf(
"rounded",
"minimal",
"scaled"
"scaled",
)
private const val ORIGINAL_USER_ICON_STYLE_NAME = "original"
@ -47,7 +47,7 @@ private const val NOTIFICATION_ICON_NAME = "revanced_notification_icon"
private val USER_CUSTOM_ADAPTIVE_FILE_NAMES = arrayOf(
"$LAUNCHER_ADAPTIVE_BACKGROUND_PREFIX$CUSTOM_USER_ICON_STYLE_NAME.png",
"$LAUNCHER_ADAPTIVE_FOREGROUND_PREFIX$CUSTOM_USER_ICON_STYLE_NAME.png"
"$LAUNCHER_ADAPTIVE_FOREGROUND_PREFIX$CUSTOM_USER_ICON_STYLE_NAME.png",
)
private const val USER_CUSTOM_MONOCHROME_FILE_NAME =
@ -71,15 +71,15 @@ internal fun baseCustomBrandingPatch(
activityAliasNameWithIntents: String,
preferenceScreen: BasePreferenceScreen.Screen,
block: ResourcePatchBuilder.() -> Unit,
executeBlock: ResourcePatchContext.() -> Unit = {}
executeBlock: ResourcePatchContext.() -> Unit = {},
) = resourcePatch(
name = "Custom branding",
description = "Adds options to change the app icon and app name. " +
"Branding cannot be changed for mounted (root) installations."
"Branding cannot be changed for mounted (root) installations.",
) {
val customName by stringOption(
name = "App name",
description = "Custom app name."
description = "Custom app name.",
)
val customIcon by stringOption(
@ -99,7 +99,7 @@ internal fun baseCustomBrandingPatch(
Optionally, the path contains a 'drawable' folder with any of the monochrome icon files:
$USER_CUSTOM_MONOCHROME_FILE_NAME
$USER_CUSTOM_NOTIFICATION_ICON_FILE_NAME
""".trimIndentMultiline()
""".trimIndentMultiline(),
)
block()
@ -112,12 +112,12 @@ internal fun baseCustomBrandingPatch(
apply {
getMainActivityOnCreate().addInstruction(
0,
"invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->setBranding()V"
"invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->setBranding()V",
)
numberOfPresetAppNamesExtensionFingerprint.method.returnEarly(numberOfPresetAppNames)
numberOfPresetAppNamesExtensionMethod.returnEarly(numberOfPresetAppNames)
notificationFingerprint.method.apply {
notificationMethod.apply {
val getBuilderIndex = if (isYouTubeMusic) {
// YT Music the field is not a plain object type.
indexOfFirstInstructionOrThrow {
@ -128,7 +128,7 @@ internal fun baseCustomBrandingPatch(
val builderCastIndex = indexOfFirstInstructionOrThrow {
val reference = getReference<TypeReference>()
opcode == Opcode.CHECK_CAST &&
reference?.type == "Landroid/app/Notification\$Builder;"
reference?.type == "Landroid/app/Notification\$Builder;"
}
indexOfFirstInstructionReversedOrThrow(builderCastIndex) {
getReference<FieldReference>()?.type == "Ljava/lang/Object;"
@ -139,7 +139,7 @@ internal fun baseCustomBrandingPatch(
.getReference<FieldReference>()
findInstructionIndicesReversedOrThrow(
Opcode.RETURN_VOID
Opcode.RETURN_VOID,
).forEach { index ->
addInstructionsAtControlFlowLabel(
index,
@ -148,7 +148,7 @@ internal fun baseCustomBrandingPatch(
iget-object v0, v0, $builderFieldName
check-cast v0, Landroid/app/Notification${'$'}Builder;
invoke-static { v0 }, $EXTENSION_CLASS_DESCRIPTOR->setNotificationIcon(Landroid/app/Notification${'$'}Builder;)V
"""
""",
)
}
}
@ -166,7 +166,7 @@ internal fun baseCustomBrandingPatch(
if (customName != null || customIcon != null) {
if (setOrGetFallbackPackageName(originalAppPackageName) == originalAppPackageName) {
Logger.getLogger(this::class.java.name).warning(
"Custom branding does not work with root installation. No changes applied."
"Custom branding does not work with root installation. No changes applied.",
)
}
}
@ -181,7 +181,7 @@ internal fun baseCustomBrandingPatch(
ListPreference(
key = "revanced_custom_branding_name",
entriesKey = "revanced_custom_branding_name_custom_entries",
entryValuesKey = "revanced_custom_branding_name_custom_entry_values"
entryValuesKey = "revanced_custom_branding_name_custom_entry_values",
)
} else {
ListPreference("revanced_custom_branding_name")
@ -190,11 +190,11 @@ internal fun baseCustomBrandingPatch(
ListPreference(
key = "revanced_custom_branding_icon",
entriesKey = "revanced_custom_branding_icon_custom_entries",
entryValuesKey = "revanced_custom_branding_icon_custom_entry_values"
entryValuesKey = "revanced_custom_branding_icon_custom_entry_values",
)
} else {
ListPreference("revanced_custom_branding_icon")
}
},
)
val useCustomName = customName != null
@ -211,8 +211,8 @@ internal fun baseCustomBrandingPatch(
),
ResourceGroup(
"mipmap-anydpi",
"$LAUNCHER_RESOURCE_NAME_PREFIX$style.xml"
)
"$LAUNCHER_RESOURCE_NAME_PREFIX$style.xml",
),
)
}
@ -221,19 +221,19 @@ internal fun baseCustomBrandingPatch(
// Push notification 'small' icon.
ResourceGroup(
"drawable",
"$NOTIFICATION_ICON_NAME.xml"
"$NOTIFICATION_ICON_NAME.xml",
),
// Copy template user icon, because the aliases must be added even if no user icon is provided.
ResourceGroup(
"drawable",
USER_CUSTOM_MONOCHROME_FILE_NAME,
USER_CUSTOM_NOTIFICATION_ICON_FILE_NAME
USER_CUSTOM_NOTIFICATION_ICON_FILE_NAME,
),
ResourceGroup(
"mipmap-anydpi",
"$LAUNCHER_RESOURCE_NAME_PREFIX$CUSTOM_USER_ICON_STYLE_NAME.xml"
)
"$LAUNCHER_RESOURCE_NAME_PREFIX$CUSTOM_USER_ICON_STYLE_NAME.xml",
),
)
// Copy template icon files.
@ -244,7 +244,7 @@ internal fun baseCustomBrandingPatch(
dpi,
"$LAUNCHER_ADAPTIVE_BACKGROUND_PREFIX$CUSTOM_USER_ICON_STYLE_NAME.png",
"$LAUNCHER_ADAPTIVE_FOREGROUND_PREFIX$CUSTOM_USER_ICON_STYLE_NAME.png",
)
),
)
}
@ -256,7 +256,7 @@ internal fun baseCustomBrandingPatch(
appNameIndex: Int,
useCustomName: Boolean,
enabled: Boolean,
intents: NodeList
intents: NodeList,
): Element {
val label = if (useCustomName) {
if (customName == null) {
@ -293,7 +293,7 @@ internal fun baseCustomBrandingPatch(
} else {
for (i in 0 until intents.length) {
alias.appendChild(
intents.item(i).cloneNode(true)
intents.item(i).cloneNode(true),
)
}
}
@ -304,7 +304,7 @@ internal fun baseCustomBrandingPatch(
val application = document.getElementsByTagName("application").item(0) as Element
val intentFilters = document.childNodes.findElementByAttributeValueOrThrow(
"android:name",
activityAliasNameWithIntents
activityAliasNameWithIntents,
).childNodes
// The YT application name can appear in some places along side the system
@ -313,7 +313,7 @@ internal fun baseCustomBrandingPatch(
// use a custom name for this situation to disambiguate which app is which.
application.setAttribute(
"android:label",
"@string/revanced_custom_branding_name_entry_2"
"@string/revanced_custom_branding_name_entry_2",
)
for (appNameIndex in 1..numberOfPresetAppNames) {
@ -329,8 +329,8 @@ internal fun baseCustomBrandingPatch(
appNameIndex = appNameIndex,
useCustomName = useCustomNameLabel,
enabled = (appNameIndex == 1),
intentFilters
)
intentFilters,
),
)
// Bundled icons.
@ -342,8 +342,8 @@ internal fun baseCustomBrandingPatch(
appNameIndex = appNameIndex,
useCustomName = useCustomNameLabel,
enabled = false,
intentFilters
)
intentFilters,
),
)
}
@ -362,8 +362,8 @@ internal fun baseCustomBrandingPatch(
appNameIndex = appNameIndex,
useCustomName = useCustomNameLabel,
enabled = false,
intentFilters
)
intentFilters,
),
)
}
@ -371,7 +371,7 @@ internal fun baseCustomBrandingPatch(
// can be shown in the launcher. Can only be done after adding the new aliases.
intentFilters.findElementByAttributeValueOrThrow(
"android:name",
"android.intent.action.MAIN"
"android.intent.action.MAIN",
).removeFromParent()
}
@ -383,13 +383,13 @@ internal fun baseCustomBrandingPatch(
if (!iconPathFile.exists()) {
throw PatchException(
"The custom icon path cannot be found: " + iconPathFile.absolutePath
"The custom icon path cannot be found: " + iconPathFile.absolutePath,
)
}
if (!iconPathFile.isDirectory) {
throw PatchException(
"The custom icon path must be a folder: " + iconPathFile.absolutePath
"The custom icon path must be a folder: " + iconPathFile.absolutePath,
)
}
@ -413,7 +413,8 @@ internal fun baseCustomBrandingPatch(
if (customFiles.isNotEmpty() && customFiles.size != USER_CUSTOM_ADAPTIVE_FILE_NAMES.size) {
throw PatchException(
"Must include all required icon files " +
"but only found " + customFiles.map { it.name })
"but only found " + customFiles.map { it.name },
)
}
customFiles.forEach { imgSourceFile ->
@ -427,14 +428,14 @@ internal fun baseCustomBrandingPatch(
// Copy monochrome and small notification icon if it provided.
arrayOf(
USER_CUSTOM_MONOCHROME_FILE_NAME,
USER_CUSTOM_NOTIFICATION_ICON_FILE_NAME
USER_CUSTOM_NOTIFICATION_ICON_FILE_NAME,
).forEach { fileName ->
val relativePath = "drawable/$fileName"
val file = iconPathFile.resolve(relativePath)
if (file.exists()) {
file.copyTo(
target = resourceDirectory.resolve(relativePath),
overwrite = true
overwrite = true,
)
copiedFiles = true
}
@ -442,9 +443,9 @@ internal fun baseCustomBrandingPatch(
if (!copiedFiles) {
throw PatchException(
"Expected to find directories and files: "
+ USER_CUSTOM_ADAPTIVE_FILE_NAMES.contentToString()
+ "\nBut none were found in the provided option file path: " + iconPathFile.absolutePath
"Expected to find directories and files: " +
USER_CUSTOM_ADAPTIVE_FILE_NAMES.contentToString() +
"\nBut none were found in the provided option file path: " + iconPathFile.absolutePath,
)
}
}

View file

@ -1,9 +1,16 @@
package app.revanced.patches.shared.layout.branding
import app.revanced.patcher.fingerprint
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.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.AccessFlags
internal val numberOfPresetAppNamesExtensionFingerprint = fingerprint {
internal val BytecodePatchContext.numberOfPresetAppNamesExtensionMethod by gettingFirstMethodDeclaratively {
accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC)
returnType("I")
parameterTypes()
@ -14,7 +21,7 @@ internal val numberOfPresetAppNamesExtensionFingerprint = fingerprint {
// A much simpler fingerprint exists that can set the small icon (contains string "414843287017"),
// but that has limited usage and this fingerprint allows changing any part of the notification.
internal val notificationFingerprint = fingerprint {
internal val BytecodePatchContext.notificationMethod by gettingFirstMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
parameterTypes("L")
strings("key_action_priority")

View file

@ -2,13 +2,20 @@ package app.revanced.patches.shared.layout.theme
import app.revanced.patcher.InstructionLocation.MatchAfterImmediately
import app.revanced.patcher.InstructionLocation.MatchAfterWithin
import app.revanced.patcher.accessFlags
import app.revanced.patcher.fieldAccess
import app.revanced.patcher.fingerprint
import app.revanced.patcher.gettingFirstMethodDeclaratively
import app.revanced.patcher.instructions
import app.revanced.patcher.invoke
import app.revanced.patcher.methodCall
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
internal val lithoOnBoundsChangeFingerprint = fingerprint {
internal val BytecodePatchContext.lithoOnBoundsChangeMethod by gettingFirstMethodDeclaratively {
accessFlags(AccessFlags.PROTECTED, AccessFlags.FINAL)
returnType("V")
parameterTypes("Landroid/graphics/Rect;")

View file

@ -11,15 +11,15 @@ val lithoColorHookPatch = bytecodePatch(
) {
apply {
var insertionIndex = lithoOnBoundsChangeFingerprint.patternMatch.endIndex - 1
var insertionIndex = lithoOnBoundsChangeMethod.patternMatch.endIndex - 1
lithoColorOverrideHook = { targetMethodClass, targetMethodName ->
lithoOnBoundsChangeFingerprint.method.addInstructions(
lithoOnBoundsChangeMethod.addInstructions(
insertionIndex,
"""
invoke-static { p1 }, $targetMethodClass->$targetMethodName(I)I
move-result p1
"""
""",
)
insertionIndex += 2
}

View file

@ -1,10 +1,17 @@
package app.revanced.patches.shared.misc.fix.verticalscroll
import app.revanced.patcher.fingerprint
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.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
internal val canScrollVerticallyFingerprint = fingerprint {
internal val BytecodePatchContext.canScrollVerticallyMethod by gettingFirstMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("Z")
parameterTypes()

View file

@ -10,7 +10,7 @@ val verticalScrollPatch = bytecodePatch(
) {
apply {
canScrollVerticallyFingerprint.let {
canScrollVerticallyMethod.let {
it.method.apply {
val moveResultIndex = it.instructionMatches.last().index
val moveResultRegister = getInstruction<OneRegisterInstruction>(moveResultIndex).registerA

View file

@ -1,9 +1,16 @@
package app.revanced.patches.shared.misc.gms
import app.revanced.patcher.fingerprint
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.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.AccessFlags
internal val googlePlayUtilityFingerprint = fingerprint {
internal val BytecodePatchContext.googlePlayUtilityMethod by gettingFirstMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
returnType("I")
parameterTypes("L", "I")
@ -14,14 +21,14 @@ internal val googlePlayUtilityFingerprint = fingerprint {
)
}
internal val serviceCheckFingerprint = fingerprint {
internal val BytecodePatchContext.serviceCheckMethod by gettingFirstMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
returnType("V")
parameterTypes("L", "I")
strings("Google Play Services not available")
}
internal val gmsCoreSupportFingerprint = fingerprint {
internal val BytecodePatchContext.gmsCoreSupportMethod by gettingFirstMethodDeclaratively {
accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC)
returnType("Ljava/lang/String;")
parameterTypes()
@ -30,7 +37,7 @@ internal val gmsCoreSupportFingerprint = fingerprint {
}
}
internal val originalPackageNameExtensionFingerprint = fingerprint {
internal val BytecodePatchContext.originalPackageNameExtensionMethod by gettingFirstMethodDeclaratively {
accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC)
returnType("Ljava/lang/String;")
parameterTypes()

View file

@ -57,14 +57,14 @@ fun gmsCoreSupportPatch(
) = bytecodePatch(
name = "GmsCore support", // TODO
description = "Allows the app to work without root by using a different package name when patched " +
"using a GmsCore instead of Google Play Services.",
"using a GmsCore instead of Google Play Services.",
) {
val gmsCoreVendorGroupIdOption = stringOption(
default = "app.revanced",
values =
mapOf(
"ReVanced" to "app.revanced",
),
mapOf(
"ReVanced" to "app.revanced",
),
name = "GmsCore vendor group ID",
description = "The vendor's group ID for GmsCore.",
required = true,
@ -124,10 +124,11 @@ fun gmsCoreSupportPatch(
in PERMISSIONS,
in ACTIONS,
in AUTHORITIES,
-> referencedString.replace("com.google", gmsCoreVendorGroupId!!)
-> referencedString.replace("com.google", gmsCoreVendorGroupId!!)
// No vendor prefix for whatever reason...
"subscribedfeeds" -> "$gmsCoreVendorGroupId.subscribedfeeds"
else -> null
}
@ -159,7 +160,7 @@ fun gmsCoreSupportPatch(
when (string) {
"$fromPackageName.SuggestionProvider",
"$fromPackageName.fileprovider",
-> string.replace(fromPackageName, toPackageName)
-> string.replace(fromPackageName, toPackageName)
else -> null
}
@ -203,25 +204,25 @@ fun gmsCoreSupportPatch(
// Return these methods early to prevent the app from crashing.
getEarlyReturnMethods().forEach { it.returnEarly() }
serviceCheckFingerprint.method.returnEarly()
serviceCheckMethod.returnEarly()
// Google Play Utility is not present in all apps, so we need to check if it's present.
if (googlePlayUtilityFingerprint.methodOrNull != null) {
googlePlayUtilityFingerprint.method.returnEarly(0)
if (googlePlayUtilityMethodOrNull != null) {
googlePlayUtilityMethod.returnEarly(0)
}
// Set original and patched package names for extension to use.
originalPackageNameExtensionFingerprint.method.returnEarly(fromPackageName)
originalPackageNameExtensionMethod.returnEarly(fromPackageName)
// Verify GmsCore is installed and whitelisted for power optimizations and background usage.
getMainActivityOnCreateMethod().addInstruction(
0,
"invoke-static/range { p0 .. p0 }, $EXTENSION_CLASS_DESCRIPTOR->" +
"checkGmsCore(Landroid/app/Activity;)V"
"checkGmsCore(Landroid/app/Activity;)V",
)
// Change the vendor of GmsCore in the extension.
gmsCoreSupportFingerprint.method.returnEarly(gmsCoreVendorGroupId!!)
gmsCoreSupportMethod.returnEarly(gmsCoreVendorGroupId!!)
executeBlock()
}

View file

@ -8,19 +8,19 @@ import java.util.logging.Logger
@Suppress("unused")
val `Disable Pairip license check` by creatingBytecodePatch(
description = "Disables Play Integrity API (Pairip) client-side license check.",
use = false
use = false,
) {
apply {
if (processLicenseResponseFingerprint.methodOrNull == null || validateLicenseResponseFingerprint.methodOrNull == null) {
if (processLicenseResponseMethodOrNull == null || validateLicenseResponseMethodOrNull == 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).
processLicenseResponseFingerprint.method.addInstruction(0, "const/4 p1, 0x0")
processLicenseResponseMethod.addInstruction(0, "const/4 p1, 0x0")
// Short-circuit the license response validation.
validateLicenseResponseFingerprint.method.returnEarly()
validateLicenseResponseMethod.returnEarly()
}
}

View file

@ -1,17 +1,15 @@
package app.revanced.patches.shared.misc.pairip.license
import app.revanced.patcher.fingerprint
internal val processLicenseResponseFingerprint = fingerprint {
internal val BytecodePatchContext.processLicenseResponseMethod by gettingFirstMethodDeclaratively {
custom { method, classDef ->
classDef.type == "Lcom/pairip/licensecheck/LicenseClient;" &&
method.name == "processResponse"
method.name == "processResponse"
}
}
internal val validateLicenseResponseFingerprint = fingerprint {
internal val BytecodePatchContext.validateLicenseResponseMethod by gettingFirstMethodDeclaratively {
custom { method, classDef ->
classDef.type == "Lcom/pairip/licensecheck/ResponseValidator;" &&
method.name == "validateResponse"
method.name == "validateResponse"
}
}

View file

@ -1,10 +1,17 @@
package app.revanced.patches.shared.misc.settings
import app.revanced.patcher.fingerprint
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.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 themeLightColorResourceNameFingerprint = fingerprint {
internal val BytecodePatchContext.themeLightColorResourceNameMethod by gettingFirstMethodDeclaratively {
accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC)
returnType("Ljava/lang/String;")
parameterTypes()
@ -13,7 +20,7 @@ internal val themeLightColorResourceNameFingerprint = fingerprint {
}
}
internal val themeDarkColorResourceNameFingerprint = fingerprint {
internal val BytecodePatchContext.themeDarkColorResourceNameMethod by gettingFirstMethodDeclaratively {
accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC)
returnType("Ljava/lang/String;")
parameterTypes()

View file

@ -17,8 +17,8 @@ import app.revanced.util.insertFirst
import app.revanced.util.returnEarly
import org.w3c.dom.Node
private var lightThemeColor : String? = null
private var darkThemeColor : String? = null
private var lightThemeColor: String? = null
private var darkThemeColor: String? = null
/**
* Sets the default theme colors used in various ReVanced specific settings menus.
@ -33,10 +33,10 @@ fun overrideThemeColors(lightThemeColorString: String?, darkThemeColorString: St
private val settingsColorPatch = bytecodePatch {
afterDependents {
if (lightThemeColor != null) {
themeLightColorResourceNameFingerprint.method.returnEarly(lightThemeColor!!)
themeLightColorResourceNameMethod.returnEarly(lightThemeColor!!)
}
if (darkThemeColor != null) {
themeDarkColorResourceNameFingerprint.method.returnEarly(darkThemeColor!!)
themeDarkColorResourceNameMethod.returnEarly(darkThemeColor!!)
}
}
}
@ -48,28 +48,31 @@ private val settingsColorPatch = bytecodePatch {
* File names that do not exist are ignored and not processed.
* @param preferences A set of preferences to add to the ReVanced fragment.
*/
fun settingsPatch (
fun settingsPatch(
rootPreferences: List<Pair<BasePreference, String>>? = null,
preferences: Set<BasePreference>,
) = resourcePatch {
dependsOn(
addResourcesPatch,
settingsColorPatch,
addBrandLicensePatch
addBrandLicensePatch,
)
apply {
copyResources(
"settings",
ResourceGroup("xml",
ResourceGroup(
"xml",
"revanced_prefs.xml",
"revanced_prefs_icons.xml",
"revanced_prefs_icons_bold.xml"
"revanced_prefs_icons_bold.xml",
),
ResourceGroup("menu",
"revanced_search_menu.xml"
ResourceGroup(
"menu",
"revanced_search_menu.xml",
),
ResourceGroup("drawable",
ResourceGroup(
"drawable",
// CustomListPreference resources.
"revanced_ic_dialog_alert.xml",
// Search resources.
@ -84,7 +87,8 @@ fun settingsPatch (
"revanced_settings_toolbar_arrow_left.xml",
"revanced_settings_toolbar_arrow_left_bold.xml",
),
ResourceGroup("layout",
ResourceGroup(
"layout",
"revanced_custom_list_item_checked.xml",
// Color picker.
"revanced_color_dot_widget.xml",
@ -98,8 +102,8 @@ fun settingsPatch (
"revanced_preference_search_result_list.xml",
"revanced_preference_search_result_regular.xml",
"revanced_preference_search_result_switch.xml",
"revanced_settings_with_toolbar.xml"
)
"revanced_settings_with_toolbar.xml",
),
)
addResources("shared", "misc.settings.settingsResourcePatch")

View file

@ -3,13 +3,15 @@ package app.revanced.patches.shared.misc.spoof
import app.revanced.patcher.accessFlags
import app.revanced.patcher.custom
import app.revanced.patcher.extensions.methodReference
import app.revanced.patcher.fingerprint
import app.revanced.patcher.firstMethodComposite
import app.revanced.patcher.gettingFirstMethodDeclaratively
import app.revanced.patcher.immutableClassDef
import app.revanced.patcher.instructions
import app.revanced.patcher.invoke
import app.revanced.patcher.method
import app.revanced.patcher.opcodes
import app.revanced.patcher.parameterTypes
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import app.revanced.util.indexOfFirstInstruction
import com.android.tools.smali.dexlib2.AccessFlags
@ -80,7 +82,7 @@ internal val buildRequestMethodMatch = firstMethodComposite {
}
}
internal val protobufClassParseByteBufferFingerprint = fingerprint {
internal val BytecodePatchContext.protobufClassParseByteBufferMethod by gettingFirstMethodDeclaratively {
accessFlags(AccessFlags.PROTECTED, AccessFlags.STATIC)
returnType("L")
parameterTypes("L", "Ljava/nio/ByteBuffer;")
@ -110,7 +112,7 @@ internal val createStreamingDataMethodMatch = firstMethodComposite {
}
}
internal val buildMediaDataSourceFingerprint = fingerprint {
internal val BytecodePatchContext.buildMediaDataSourceMethod by gettingFirstMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
parameterTypes(
"Landroid/net/Uri;",
@ -145,7 +147,7 @@ internal val mediaFetchEnumConstructorMethodMatch = firstMethodComposite {
)
}
internal val nerdsStatsVideoFormatBuilderFingerprint = fingerprint {
internal val BytecodePatchContext.nerdsStatsVideoFormatBuilderMethod by gettingFirstMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
returnType("Ljava/lang/String;")
parameterTypes("L")
@ -154,7 +156,7 @@ internal val nerdsStatsVideoFormatBuilderFingerprint = fingerprint {
)
}
internal val patchIncludedExtensionMethodFingerprint = fingerprint {
internal val BytecodePatchContext.patchIncludedExtensionMethodMethod by gettingFirstMethodDeclaratively {
returnType("Z")
parameterTypes()
custom { method, classDef ->

View file

@ -1,7 +1,6 @@
package app.revanced.patches.shared.misc.spoof
import app.revanced.patcher.extensions.*
import app.revanced.patcher.fingerprint
import app.revanced.patcher.patch.BytecodePatchBuilder
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.patch.bytecodePatch
@ -55,7 +54,7 @@ internal fun spoofVideoStreamsPatch(
// region Enable extension helper method used by other patches
patchIncludedExtensionMethodFingerprint.method.returnEarly(true)
patchIncludedExtensionMethodMethod.returnEarly(true)
// endregion
@ -128,7 +127,7 @@ internal fun spoofVideoStreamsPatch(
"$resultMethodType->$setStreamDataMethodName($videoDetailsClass)V",
)
val protobufClass = protobufClassParseByteBufferFingerprint.method.definingClass
val protobufClass = protobufClassParseByteBufferMethod.definingClass
val setStreamingDataIndex = createStreamingDataMethodMatch.indices.first()
val playerProtoClass = getInstruction(setStreamingDataIndex + 1)
@ -212,7 +211,7 @@ internal fun spoofVideoStreamsPatch(
// Requesting streams intended for other platforms with a body tuned for Android could be the cause of 400 errors.
// A proper fix may include modifying the request body to match the platforms expected body.
buildMediaDataSourceFingerprint.method.apply {
buildMediaDataSourceMethod.apply {
val targetIndex = instructions.lastIndex
// Instructions are added just before the method returns,
@ -238,7 +237,7 @@ internal fun spoofVideoStreamsPatch(
// region Append spoof info.
nerdsStatsVideoFormatBuilderFingerprint.method.apply {
nerdsStatsVideoFormatBuilderMethod.apply {
findInstructionIndicesReversedOrThrow(Opcode.RETURN_OBJECT).forEach { index ->
val register = getInstruction<OneRegisterInstruction>(index).registerA

View file

@ -15,7 +15,7 @@ val `Remove badge tab` by creatingBytecodePatch(
val arrayTabs = listOf("Log", "HealthCare")
apply {
createTabsFingerprint.method.apply {
createTabsMethod.apply {
removeInstructions(0, 2)
val arrayRegister = 0

View file

@ -1,6 +1,13 @@
package app.revanced.patches.songpal.badge
import app.revanced.patcher.fingerprint
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.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.instruction.ReferenceInstruction
@ -8,7 +15,7 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
import com.android.tools.smali.dexlib2.immutable.reference.ImmutableMethodReference
// Located @ ub.i0.h#p (9.5.0)
internal val createTabsFingerprint = fingerprint {
internal val BytecodePatchContext.createTabsMethod by gettingFirstMethodDeclaratively {
accessFlags(AccessFlags.PRIVATE)
returnType("Ljava/util/List;")
custom { method, _ ->
@ -26,7 +33,7 @@ internal val createTabsFingerprint = fingerprint {
}
// Located @ com.sony.songpal.mdr.vim.activity.MdrRemoteBaseActivity.e#run (9.5.0)
internal val showNotificationFingerprint = fingerprint {
internal val BytecodePatchContext.showNotificationMethod by gettingFirstMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC)
returnType("V")
custom { method, _ ->

View file

@ -10,6 +10,6 @@ val `Remove notification badge` by creatingBytecodePatch(
compatibleWith("com.sony.songpal.mdr"("10.1.0"))
apply {
showNotificationFingerprint.method.addInstructions(0, "return-void")
showNotificationMethod.addInstructions(0, "return-void")
}
}

View file

@ -19,10 +19,10 @@ private val customThemeBytecodePatch = bytecodePatch {
dependsOn(sharedExtensionPatch)
apply {
val colorSpaceUtilsClassDef = colorSpaceUtilsClassFingerprint.originalClassDef
val colorSpaceUtilsClassDef = colorSpaceUtilsClassMethod.originalClassDef
// Hook a util method that converts ARGB to RGBA in the sRGB color space to replace hardcoded accent colors.
convertArgbToRgbaFingerprint.match(colorSpaceUtilsClassDef).method.apply {
convertArgbToRgbaMethod.match(colorSpaceUtilsClassDef).method.apply {
addInstructions(
0,
"""
@ -30,21 +30,21 @@ private val customThemeBytecodePatch = bytecodePatch {
invoke-static { p0 }, $EXTENSION_CLASS_DESCRIPTOR->replaceColor(I)I
move-result p0
int-to-long p0, p0
"""
""",
)
}
// Lottie JSON parser method. It parses the JSON Lottie animation into its own class,
// including the solid color of it.
parseLottieJsonFingerprint.method.apply {
parseLottieJsonMethod.apply {
val invokeParseColorIndex = indexOfFirstInstructionOrThrow {
val reference = getReference<MethodReference>()
reference?.definingClass == "Landroid/graphics/Color;"
&& reference.name == "parseColor"
reference?.definingClass == "Landroid/graphics/Color;" &&
reference.name == "parseColor"
}
val parsedColorRegister = getInstruction<OneRegisterInstruction>(invokeParseColorIndex + 1).registerA
val replaceColorDescriptor = "$EXTENSION_CLASS_DESCRIPTOR->replaceColor(I)I"
val replaceColorDescriptor = "$EXTENSION_CLASS_DESCRIPTOR->replaceColor(I)I"
addInstructions(
invokeParseColorIndex + 2,
@ -52,16 +52,16 @@ private val customThemeBytecodePatch = bytecodePatch {
# Use invoke-static/range because the register number is too large.
invoke-static/range { v$parsedColorRegister .. v$parsedColorRegister }, $replaceColorDescriptor
move-result v$parsedColorRegister
"""
""",
)
}
// Lottie animated color parser.
parseAnimatedColorFingerprint.method.apply {
parseAnimatedColorMethod.apply {
val invokeArgbIndex = indexOfFirstInstructionOrThrow {
val reference = getReference<MethodReference>()
reference?.definingClass == "Landroid/graphics/Color;"
&& reference.name == "argb"
reference?.definingClass == "Landroid/graphics/Color;" &&
reference.name == "argb"
}
val argbColorRegister = getInstruction<OneRegisterInstruction>(invokeArgbIndex + 1).registerA
@ -70,7 +70,7 @@ private val customThemeBytecodePatch = bytecodePatch {
"""
invoke-static { v$argbColorRegister }, $EXTENSION_CLASS_DESCRIPTOR->replaceColor(I)I
move-result v$argbColorRegister
"""
""",
)
}
}
@ -97,7 +97,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 +105,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 +120,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,
)
@ -155,7 +155,7 @@ val customThemePatch = resourcePatch(
"sthlm_blk", "sthlm_blk_grad_start",
// Misc.
"image_placeholder_color",
-> backgroundColor
-> backgroundColor
// "About the artist" background color in song player.
"gray_15",
@ -164,17 +164,17 @@ val customThemePatch = resourcePatch(
// Playlist list background in home page.
"opacity_white_10",
// "What's New" pills background.
"dark_base_background_tinted_highlight"
-> backgroundColorSecondary
"dark_base_background_tinted_highlight",
-> backgroundColorSecondary
"dark_brightaccent_background_base",
"dark_base_text_brightaccent",
"green_light",
"spotify_green_157"
-> accentColor
"spotify_green_157",
-> accentColor
"dark_brightaccent_background_press"
-> accentColorPressed
"dark_brightaccent_background_press",
-> accentColorPressed
else -> continue
}

View file

@ -1,24 +1,31 @@
package app.revanced.patches.spotify.layout.theme
import app.revanced.patcher.fingerprint
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.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import app.revanced.util.containsLiteralInstruction
import com.android.tools.smali.dexlib2.AccessFlags
internal val colorSpaceUtilsClassFingerprint = fingerprint {
internal val BytecodePatchContext.colorSpaceUtilsClassMethod by gettingFirstMethodDeclaratively {
strings("The specified color must be encoded in an RGB color space.") // Partial string match.
}
internal val convertArgbToRgbaFingerprint = fingerprint {
internal val BytecodePatchContext.convertArgbToRgbaMethod by gettingFirstMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC, AccessFlags.FINAL)
returnType("J")
parameterTypes("J")
}
internal val parseLottieJsonFingerprint = fingerprint {
internal val BytecodePatchContext.parseLottieJsonMethod by gettingFirstMethodDeclaratively {
strings("Unsupported matte type: ")
}
internal val parseAnimatedColorFingerprint = fingerprint {
internal val BytecodePatchContext.parseAnimatedColorMethod by gettingFirstMethodDeclaratively {
parameterTypes("L", "F")
returnType("Ljava/lang/Object;")
custom { method, _ ->

View file

@ -1,7 +1,5 @@
package app.revanced.patches.spotify.misc.extension
import app.revanced.patcher.fingerprint
internal val loadOrbitLibraryFingerprint = fingerprint {
internal val BytecodePatchContext.loadOrbitLibraryMethod by gettingFirstMethodDeclaratively {
strings("orbit_library_load", "orbit-jni-spotify")
}

View file

@ -14,7 +14,7 @@ internal val loadOrbitLibraryHook = extensionHook {
// FIXME: Creating this is a mess and needs refactoring.
extensionHook(
getInsertIndex = {
loadOrbitLibraryFingerprint.stringMatches.last().index
loadOrbitLibraryMethod.stringMatches.last().index
},
getContextRegister = { method ->
val contextReferenceIndex = method.indexOfFirstInstruction {
@ -25,6 +25,6 @@ internal val loadOrbitLibraryHook = extensionHook {
"v$contextRegister"
},
fingerprint = loadOrbitLibraryFingerprint,
fingerprint = loadOrbitLibraryMethod,
)
}

View file

@ -1,14 +1,21 @@
package app.revanced.patches.spotify.misc.fix.login
import app.revanced.patcher.fingerprint
import app.revanced.patcher.accessFlags
import app.revanced.patcher.gettingFirstMethodDeclaratively
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.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import app.revanced.util.literal
internal val katanaProxyLoginMethodHandlerClassFingerprint = fingerprint {
internal val BytecodePatchContext.katanaProxyLoginMethodHandlerClassMethod by gettingFirstMethodDeclaratively {
strings("katana_proxy_auth")
}
internal val katanaProxyLoginMethodTryAuthorizeFingerprint = fingerprint {
internal val BytecodePatchContext.katanaProxyLoginMethodTryAuthorizeMethod by gettingFirstMethodDeclaratively {
strings("e2e")
literal { 0 }
}

View file

@ -6,7 +6,7 @@ import app.revanced.util.returnEarly
@Suppress("unused")
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")
@ -17,10 +17,10 @@ val `Fix Facebook login` by creatingBytecodePatch(
// Override the Facebook SDK to always handle the login using the web browser, which does not perform
// signature checks.
val katanaProxyLoginMethodHandlerClass = katanaProxyLoginMethodHandlerClassFingerprint.originalClassDef
val katanaProxyLoginMethodHandlerClass = katanaProxyLoginMethodHandlerClassMethod.originalClassDef
// 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.
katanaProxyLoginMethodTryAuthorizeFingerprint
katanaProxyLoginMethodTryAuthorizeMethod
.match(katanaProxyLoginMethodHandlerClass)
.method
.returnEarly(0)

View file

@ -3,7 +3,6 @@ package app.revanced.patches.spotify.misc.lyrics
import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.extensions.replaceInstruction
import app.revanced.patcher.fingerprint
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.patcher.patch.stringOption
import app.revanced.util.getReference
@ -60,7 +59,7 @@ val `Change lyrics provider` by creatingBytecodePatch(
}
apply {
val httpClientBuilderMethod = httpClientBuilderFingerprint.originalMethod
val httpClientBuilderMethod = httpClientBuilderMethod.originalMethod
// region Create a modified copy of the HTTP client builder method with the custom lyrics provider host.
@ -83,7 +82,7 @@ val `Change lyrics provider` by creatingBytecodePatch(
)
// Add the patched method to the class.
httpClientBuilderFingerprint.classDef.methods.add(this)
httpClientBuilderMethod.classDef.methods.add(this)
}
}

View file

@ -1,11 +1,18 @@
package app.revanced.patches.spotify.misc.lyrics
import app.revanced.patcher.fingerprint
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.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
internal val httpClientBuilderFingerprint = fingerprint {
internal val BytecodePatchContext.httpClientBuilderMethod by gettingFirstMethodDeclaratively {
strings("client == null", "scheduler == null")
}

View file

@ -1,11 +1,18 @@
package app.revanced.patches.spotify.misc.privacy
import app.revanced.patcher.fingerprint
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.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 shareCopyUrlFingerprint = fingerprint {
internal val BytecodePatchContext.shareCopyUrlMethod by gettingFirstMethodDeclaratively {
returnType("Ljava/lang/Object;")
parameterTypes("Ljava/lang/Object;")
strings("clipboard", "Spotify Link")
@ -14,7 +21,7 @@ internal val shareCopyUrlFingerprint = fingerprint {
}
}
internal val oldShareCopyUrlFingerprint = fingerprint {
internal val BytecodePatchContext.oldShareCopyUrlMethod by gettingFirstMethodDeclaratively {
returnType("Ljava/lang/Object;")
parameterTypes("Ljava/lang/Object;")
strings("clipboard", "createNewSession failed")
@ -23,7 +30,7 @@ internal val oldShareCopyUrlFingerprint = fingerprint {
}
}
internal val formatAndroidShareSheetUrlFingerprint = fingerprint {
internal val BytecodePatchContext.formatAndroidShareSheetUrlMethod by gettingFirstMethodDeclaratively {
returnType("Ljava/lang/String;")
parameterTypes("L", "Ljava/lang/String;")
opcodes(
@ -38,7 +45,7 @@ internal val formatAndroidShareSheetUrlFingerprint = fingerprint {
}
}
internal val oldFormatAndroidShareSheetUrlFingerprint = fingerprint {
internal val BytecodePatchContext.oldFormatAndroidShareSheetUrlMethod by gettingFirstMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC)
returnType("Ljava/lang/String;")
parameterTypes("Lcom/spotify/share/social/sharedata/ShareData;", "Ljava/lang/String;")

View file

@ -24,12 +24,12 @@ val `Sanitize sharing links` by creatingBytecodePatch(
apply {
val extensionMethodDescriptor = "$EXTENSION_CLASS_DESCRIPTOR->" +
"sanitizeSharingLink(Ljava/lang/String;)Ljava/lang/String;"
"sanitizeSharingLink(Ljava/lang/String;)Ljava/lang/String;"
val copyFingerprint = if (shareCopyUrlFingerprint.originalMethodOrNull != null) {
shareCopyUrlFingerprint
val copyFingerprint = if (shareCopyUrlMethod.originalMethodOrNull != null) {
shareCopyUrlMethod
} else {
oldShareCopyUrlFingerprint
oldShareCopyUrlMethod
}
copyFingerprint.method.apply {
@ -43,14 +43,14 @@ val `Sanitize sharing links` by creatingBytecodePatch(
"""
invoke-static { v$urlRegister }, $extensionMethodDescriptor
move-result-object v$urlRegister
"""
""",
)
}
// Android native share sheet is used for all other quick share types (X, WhatsApp, etc).
val shareUrlParameter: String
val shareSheetFingerprint = if (formatAndroidShareSheetUrlFingerprint.originalMethodOrNull != null) {
val methodAccessFlags = formatAndroidShareSheetUrlFingerprint.originalMethod
val shareSheetFingerprint = if (formatAndroidShareSheetUrlMethod.originalMethodOrNull != null) {
val methodAccessFlags = formatAndroidShareSheetUrlMethod.originalMethod
shareUrlParameter = if (AccessFlags.STATIC.isSet(methodAccessFlags.accessFlags)) {
// In newer implementations the method is static, so p0 is not `this`.
"p1"
@ -60,10 +60,10 @@ val `Sanitize sharing links` by creatingBytecodePatch(
"p2"
}
formatAndroidShareSheetUrlFingerprint
formatAndroidShareSheetUrlMethod
} else {
shareUrlParameter = "p2"
oldFormatAndroidShareSheetUrlFingerprint
oldFormatAndroidShareSheetUrlMethod
}
shareSheetFingerprint.method.addInstructions(
@ -71,7 +71,7 @@ val `Sanitize sharing links` by creatingBytecodePatch(
"""
invoke-static { $shareUrlParameter }, $extensionMethodDescriptor
move-result-object $shareUrlParameter
"""
""",
)
}
}

View file

@ -1,9 +1,16 @@
package app.revanced.patches.spotify.misc.widgets
import app.revanced.patcher.fingerprint
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.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.Opcode
internal val canBindAppWidgetPermissionFingerprint = fingerprint {
internal val BytecodePatchContext.canBindAppWidgetPermissionMethod by gettingFirstMethodDeclaratively {
strings("android.permission.BIND_APPWIDGET")
opcodes(Opcode.AND_INT_LIT8)
}

View file

@ -13,6 +13,6 @@ val `Fix third party launchers widgets` by creatingBytecodePatch(
// Only system app launchers are granted the BIND_APPWIDGET permission.
// Override the method that checks for it to always return true, as this permission is not actually required
// for the widgets to work.
canBindAppWidgetPermissionFingerprint.method.returnEarly(true)
canBindAppWidgetPermissionMethod.returnEarly(true)
}
}

View file

@ -1,10 +1,13 @@
package app.revanced.patches.spotify.shared
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.accessFlags
import app.revanced.patcher.definingClass
import app.revanced.patcher.fingerprint
import app.revanced.patcher.gettingFirstMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.instructions
import app.revanced.patcher.invoke
import app.revanced.patcher.name
import app.revanced.patcher.opcodes
import app.revanced.patcher.parameterTypes
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType

View file

@ -1,20 +1,18 @@
package app.revanced.patches.strava.mediaupload
import app.revanced.patcher.fingerprint
internal val getCompressionQualityFingerprint = fingerprint {
internal val BytecodePatchContext.getCompressionQualityMethod by gettingFirstMethodDeclaratively {
custom { method, _ ->
method.name == "getCompressionQuality"
}
}
internal val getMaxDurationFingerprint = fingerprint {
internal val BytecodePatchContext.getMaxDurationMethod by gettingFirstMethodDeclaratively {
custom { method, _ ->
method.name == "getMaxDuration"
}
}
internal val getMaxSizeFingerprint = fingerprint {
internal val BytecodePatchContext.getMaxSizeMethod by gettingFirstMethodDeclaratively {
custom { method, _ ->
method.name == "getMaxSize"
}

View file

@ -31,15 +31,15 @@ val `Overwrite media upload parameters` by creatingBytecodePatch(
val mediaUploadParametersClass = firstClassDef { type.endsWith("/MediaUploadParameters;") }
compressionQuality?.let { compressionQuality ->
getCompressionQualityFingerprint.match(mediaUploadParametersClass).method.returnEarly(compressionQuality / 100f)
getCompressionQualityMethod.match(mediaUploadParametersClass).method.returnEarly(compressionQuality / 100f)
}
maxDuration?.let { maxDuration ->
getMaxDurationFingerprint.match(mediaUploadParametersClass).method.returnEarly(maxDuration)
getMaxDurationMethod.match(mediaUploadParametersClass).method.returnEarly(maxDuration)
}
maxSize?.let {
getMaxSizeFingerprint.match(mediaUploadParametersClass).method.returnEarly(it)
getMaxSizeMethod.match(mediaUploadParametersClass).method.returnEarly(it)
}
}
}

View file

@ -1,16 +1,23 @@
package app.revanced.patches.ticktick.misc.themeunlock
import app.revanced.patcher.accessFlags
import app.revanced.patcher.definingClass
import app.revanced.patcher.gettingFirstMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.instructions
import app.revanced.patcher.invoke
import app.revanced.patcher.name
import app.revanced.patcher.opcodes
import app.revanced.patcher.parameterTypes
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
internal val BytecodePatchContext.checkLockedThemesFingerprint by gettingFirstMutableMethodDeclaratively {
name("isLockedTheme")
definingClass("Theme;"::endsWith)
}
internal val BytecodePatchContext.setThemeFingerprint by gettingFirstMutableMethodDeclaratively {
internal val BytecodePatchContext.setThemeMethod by gettingFirstMutableMethodDeclaratively {
name("lambda\$updateUserBtn\$1")
definingClass("ThemePreviewActivity;"::endsWith)
}

View file

@ -19,6 +19,6 @@ val `Unlock themes` by creatingBytecodePatch(
""",
)
setThemeFingerprint.removeInstructions(0, 10)
setThemeMethod.removeInstructions(0, 10)
}
}

View file

@ -5,7 +5,7 @@ import app.revanced.patcher.extensions.instructions
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.patches.tiktok.misc.extension.sharedExtensionPatch
import app.revanced.patches.tiktok.misc.settings.Settings
import app.revanced.patches.tiktok.misc.settings.settingsStatusLoadFingerprint
import app.revanced.patches.tiktok.misc.settings.settingsStatusLoadMethod
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
@ -14,7 +14,7 @@ private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/tiktok/f
@Suppress("unused")
val `Feed filter` by creatingBytecodePatch(
description = "Removes ads, livestreams, stories, image videos " +
"and videos with a specific amount of views or likes from the feed.",
"and videos with a specific amount of views or likes from the feed.",
) {
dependsOn(
sharedExtensionPatch,
@ -29,20 +29,19 @@ val `Feed filter` by creatingBytecodePatch(
apply {
arrayOf(
feedApiServiceLIZMethod to "$EXTENSION_CLASS_DESCRIPTOR->filter(Lcom/ss/android/ugc/aweme/feed/model/FeedItemList;)V",
followFeedMethod to "$EXTENSION_CLASS_DESCRIPTOR->filter(Lcom/ss/android/ugc/aweme/follow/presenter/FollowFeedList;)V"
followFeedMethod to "$EXTENSION_CLASS_DESCRIPTOR->filter(Lcom/ss/android/ugc/aweme/follow/presenter/FollowFeedList;)V",
).forEach { (method, filterSignature) ->
val returnInstruction = method.instructions.first { it.opcode == Opcode.RETURN_OBJECT }
val register = (returnInstruction as OneRegisterInstruction).registerA
method.addInstruction(
returnInstruction.location.index,
"invoke-static { v$register }, $filterSignature"
"invoke-static { v$register }, $filterSignature",
)
}
settingsStatusLoadFingerprint.method.addInstruction(
settingsStatusLoadMethod.addInstruction(
0,
"invoke-static {}, Lapp/revanced/extension/tiktok/settings/SettingsStatus;->enableFeedFilter()V",
)
}
}

View file

@ -5,7 +5,7 @@ import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.addInstructionsWithLabels
import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.patches.tiktok.shared.onRenderFirstFrameFingerprint
import app.revanced.patches.tiktok.shared.onRenderFirstFrameMethod
import app.revanced.util.indexOfFirstInstructionOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
@ -29,7 +29,7 @@ val `Remember clear display` by creatingBytecodePatch(
addInstructions(
isEnabledIndex,
"invoke-static { v$isEnabledRegister }, " +
"Lapp/revanced/extension/tiktok/cleardisplay/RememberClearDisplayPatch;->rememberClearDisplayState(Z)V",
"Lapp/revanced/extension/tiktok/cleardisplay/RememberClearDisplayPatch;->rememberClearDisplayState(Z)V",
)
// endregion
@ -37,7 +37,7 @@ val `Remember clear display` by creatingBytecodePatch(
// region Override the "Clear display" configuration load event to load the state of clear display.
val clearDisplayEventClass = parameters[0].type
onRenderFirstFrameFingerprint.method.addInstructionsWithLabels(
onRenderFirstFrameMethod.addInstructionsWithLabels(
0,
"""
# Create a new clearDisplayEvent and post it to the EventBus (https://github.com/greenrobot/EventBus)
@ -60,7 +60,7 @@ val `Remember clear display` by creatingBytecodePatch(
invoke-direct { v0, v1, v2, v3, v4 }, $clearDisplayEventClass-><init>(ILjava/lang/String;Ljava/lang/String;Z)V
invoke-virtual { v0 }, $clearDisplayEventClass->post()Lcom/ss/android/ugc/governance/eventbus/IEvent;
""",
ExternalLabel("clear_display_disabled", onRenderFirstFrameFingerprint.method.getInstruction(0)),
ExternalLabel("clear_display_disabled", onRenderFirstFrameMethod.getInstruction(0)),
)
// endregion

View file

@ -4,7 +4,7 @@ import app.revanced.patcher.extensions.*
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.patches.tiktok.misc.extension.sharedExtensionPatch
import app.revanced.patches.tiktok.misc.settings.Settings
import app.revanced.patches.tiktok.misc.settings.settingsStatusLoadFingerprint
import app.revanced.patches.tiktok.misc.settings.settingsStatusLoadMethod
import app.revanced.util.findInstructionIndicesReversedOrThrow
import app.revanced.util.getReference
import app.revanced.util.returnEarly
@ -70,7 +70,7 @@ val Downloads by creatingBytecodePatch(
}
}
settingsStatusLoadFingerprint.method.addInstruction(
settingsStatusLoadMethod.addInstruction(
0,
"invoke-static {}, Lapp/revanced/extension/tiktok/settings/SettingsStatus;->enableDownload()V",
)

View file

@ -5,8 +5,8 @@ import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.patches.tiktok.shared.getEnterFromFingerprint
import app.revanced.patches.tiktok.shared.onRenderFirstFrameFingerprint
import app.revanced.patches.tiktok.shared.getEnterFromMethod
import app.revanced.patches.tiktok.shared.onRenderFirstFrameMethod
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.returnEarly
@ -38,12 +38,12 @@ val `Playback speed` by creatingBytecodePatch(
// By default, the playback speed will reset to 1.0 at the start of each video.
// Instead, override it with the desired playback speed.
onRenderFirstFrameFingerprint.method.addInstructions(
onRenderFirstFrameMethod.addInstructions(
0,
"""
# Video playback location (e.g. home page, following page or search result page) retrieved using getEnterFrom method.
const/4 v0, 0x1
invoke-virtual { p0, v0 }, ${getEnterFromFingerprint.originalMethod}
invoke-virtual { p0, v0 }, ${getEnterFromMethod.originalMethod}
move-result-object v0
# Model of current video retrieved using getCurrentAweme method.

View file

@ -12,8 +12,8 @@ val `Disable login requirement` by creatingBytecodePatch {
apply {
listOf(
mandatoryLoginServiceFingerprint,
mandatoryLoginService2Fingerprint,
mandatoryLoginServiceMethod,
mandatoryLoginService2Method,
).forEach { fingerprint ->
fingerprint.method.addInstructions(
0,

View file

@ -1,15 +1,13 @@
package app.revanced.patches.tiktok.misc.login.disablerequirement
import app.revanced.patcher.fingerprint
internal val mandatoryLoginServiceFingerprint = fingerprint {
internal val BytecodePatchContext.mandatoryLoginServiceMethod by gettingFirstMethodDeclaratively {
custom { method, classDef ->
classDef.endsWith("/MandatoryLoginService;") &&
method.name == "enableForcedLogin"
}
}
internal val mandatoryLoginService2Fingerprint = fingerprint {
internal val BytecodePatchContext.mandatoryLoginService2Method by gettingFirstMethodDeclaratively {
custom { method, classDef ->
classDef.endsWith("/MandatoryLoginService;") &&
method.name == "shouldShowForcedLogin"

View file

@ -1,33 +1,31 @@
package app.revanced.patches.tiktok.misc.settings
import app.revanced.patcher.fingerprint
internal val addSettingsEntryFingerprint = fingerprint {
internal val BytecodePatchContext.addSettingsEntryMethod by gettingFirstMethodDeclaratively {
custom { method, classDef ->
classDef.endsWith("/SettingNewVersionFragment;") &&
method.name == "initUnitManger"
}
}
internal val adPersonalizationActivityOnCreateFingerprint = fingerprint {
internal val BytecodePatchContext.adPersonalizationActivityOnCreateMethod by gettingFirstMethodDeclaratively {
custom { method, classDef ->
classDef.endsWith("/AdPersonalizationActivity;") &&
method.name == "onCreate"
}
}
internal val settingsEntryFingerprint = fingerprint {
internal val BytecodePatchContext.settingsEntryMethod by gettingFirstMethodDeclaratively {
strings("pls pass item or extends the EventUnit")
}
internal val settingsEntryInfoFingerprint = fingerprint {
internal val BytecodePatchContext.settingsEntryInfoMethod by gettingFirstMethodDeclaratively {
strings(
"ExposeItem(title=",
", icon=",
)
}
internal val settingsStatusLoadFingerprint = fingerprint {
internal val BytecodePatchContext.settingsStatusLoadMethod by gettingFirstMethodDeclaratively {
custom { method, classDef ->
classDef.endsWith("Lapp/revanced/extension/tiktok/settings/SettingsStatus;") &&
method.name == "load"

View file

@ -28,23 +28,23 @@ val Settings by creatingBytecodePatch(
apply {
val initializeSettingsMethodDescriptor =
"$EXTENSION_CLASS_DESCRIPTOR->initialize(" +
"Lcom/bytedance/ies/ugc/aweme/commercialize/compliance/personalization/AdPersonalizationActivity;" +
")Z"
"Lcom/bytedance/ies/ugc/aweme/commercialize/compliance/personalization/AdPersonalizationActivity;" +
")Z"
val createSettingsEntryMethodDescriptor =
"$EXTENSION_CLASS_DESCRIPTOR->createSettingsEntry(" +
"Ljava/lang/String;" +
"Ljava/lang/String;" +
")Ljava/lang/Object;"
"Ljava/lang/String;" +
"Ljava/lang/String;" +
")Ljava/lang/Object;"
fun String.toClassName(): String = substring(1, this.length - 1).replace("/", ".")
// Find the class name of classes which construct a settings entry
val settingsButtonClass = settingsEntryFingerprint.originalClassDef.type.toClassName()
val settingsButtonInfoClass = settingsEntryInfoFingerprint.originalClassDef.type.toClassName()
val settingsButtonClass = settingsEntryMethod.originalClassDef.type.toClassName()
val settingsButtonInfoClass = settingsEntryInfoMethod.originalClassDef.type.toClassName()
// Create a settings entry for 'revanced settings' and add it to settings fragment
addSettingsEntryFingerprint.method.apply {
addSettingsEntryMethod.apply {
val markIndex = implementation!!.instructions.indexOfFirst {
it.opcode == Opcode.IGET_OBJECT && ((it as Instruction22c).reference as FieldReference).name == "headerUnit"
}
@ -67,13 +67,13 @@ val Settings by creatingBytecodePatch(
const-string v1, "$settingsButtonInfoClass"
invoke-static {v0, v1}, $createSettingsEntryMethodDescriptor
move-result-object v0
check-cast v0, ${settingsEntryFingerprint.originalClassDef.type}
check-cast v0, ${settingsEntryMethod.originalClassDef.type}
""",
)
}
// Initialize the settings menu once the replaced setting entry is clicked.
adPersonalizationActivityOnCreateFingerprint.method.apply {
adPersonalizationActivityOnCreateMethod.apply {
val initializeSettingsIndex = implementation!!.instructions.indexOfFirst {
it.opcode == Opcode.INVOKE_SUPER
} + 1

View file

@ -6,7 +6,7 @@ import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.patches.tiktok.misc.extension.sharedExtensionPatch
import app.revanced.patches.tiktok.misc.settings.Settings
import app.revanced.patches.tiktok.misc.settings.settingsStatusLoadFingerprint
import app.revanced.patches.tiktok.misc.settings.settingsStatusLoadMethod
import app.revanced.util.findMutableMethodOf
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
@ -91,7 +91,7 @@ val `SIM spoof` by creatingBytecodePatch(
}
// Enable patch in settings.
settingsStatusLoadFingerprint.method.addInstruction(
settingsStatusLoadMethod.addInstruction(
0,
"invoke-static {}, Lapp/revanced/extension/tiktok/settings/SettingsStatus;->enableSimSpoof()V",
)

View file

@ -1,10 +1,17 @@
package app.revanced.patches.tiktok.shared
import app.revanced.patcher.fingerprint
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.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
internal val getEnterFromFingerprint = fingerprint {
internal val BytecodePatchContext.getEnterFromMethod by gettingFirstMethodDeclaratively {
returnType("Ljava/lang/String;")
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
parameterTypes("Z")
@ -22,7 +29,7 @@ internal val getEnterFromFingerprint = fingerprint {
}
}
internal val onRenderFirstFrameFingerprint = fingerprint {
internal val BytecodePatchContext.onRenderFirstFrameMethod by gettingFirstMethodDeclaratively {
strings("method_enable_viewpager_preload_duration")
custom { _, classDef ->
classDef.endsWith("/BaseListFragmentPanel;")

View file

@ -1,9 +1,16 @@
package app.revanced.patches.tudortmund.lockscreen
import app.revanced.patcher.fingerprint
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.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.AccessFlags
internal val brightnessFingerprint = fingerprint {
internal val BytecodePatchContext.brightnessMethod by gettingFirstMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC)
returnType("V")
parameterTypes()

View file

@ -24,7 +24,7 @@ val `Show on lockscreen` by creatingBytecodePatch(
compatibleWith("de.tudortmund.app")
apply {
brightnessFingerprint.method.apply {
brightnessMethod.apply {
// Find the instruction where the brightness value is loaded into a register
val brightnessInstruction = instructions.firstNotNullOf { instruction ->
if (instruction.opcode != Opcode.IGET_OBJECT) return@firstNotNullOf null
@ -61,10 +61,10 @@ val `Show on lockscreen` by creatingBytecodePatch(
replaceInstruction(
windowIndex,
"invoke-static { v$activityRegister, v$brightnessRegister }, " +
"$EXTENSION_CLASS_DESCRIPTOR->" +
"getWindow" +
"(Landroidx/appcompat/app/AppCompatActivity;F)" +
"Landroid/view/Window;",
"$EXTENSION_CLASS_DESCRIPTOR->" +
"getWindow" +
"(Landroidx/appcompat/app/AppCompatActivity;F)" +
"Landroid/view/Window;",
)
// Normally, the brightness is loaded into a register after the getWindow call.

View file

@ -10,7 +10,7 @@ val `Disable blog notification reminder` by creatingBytecodePatch(
compatibleWith("com.tumblr")
apply {
isBlogNotifyEnabledFingerprint.method.addInstructions(
isBlogNotifyEnabledMethod.addInstructions(
0,
"""
# Return false for BlogNotifyCtaDialog.isEnabled() method.

View file

@ -1,11 +1,9 @@
package app.revanced.patches.tumblr.annoyances.notifications
import app.revanced.patcher.fingerprint
// The BlogNotifyCtaDialog asks you if you want to enable notifications for a blog.
// It shows whenever you visit a certain blog for the second time and disables itself
// if it was shown a total of 3 times (stored in app storage).
// This targets the BlogNotifyCtaDialog.isEnabled() method to let it always return false.
internal val isBlogNotifyEnabledFingerprint = fingerprint {
internal val BytecodePatchContext.isBlogNotifyEnabledMethod by gettingFirstMethodDeclaratively {
strings("isEnabled --> ", "blog_notify_enabled")
}

View file

@ -1,6 +1,13 @@
package app.revanced.patches.tumblr.featureflags
import app.revanced.patcher.fingerprint
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.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
@ -13,7 +20,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 getFeatureValueFingerprint = fingerprint {
internal val BytecodePatchContext.getFeatureValueMethod by gettingFirstMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("Ljava/lang/String;")
parameterTypes("L", "Z")

View file

@ -3,11 +3,11 @@ package app.revanced.patches.tumblr.featureflags
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.addInstructionsWithLabels
import app.revanced.patcher.patch.bytecodePatch
import com.android.tools.smali.dexlib2.mutable.MutableMethod.Companion.toMutable
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
import com.android.tools.smali.dexlib2.mutable.MutableMethod.Companion.toMutable
/**
* Override a feature flag with a value.
@ -24,15 +24,15 @@ val overrideFeatureFlagsPatch = bytecodePatch(
) {
apply {
val configurationClass = getFeatureValueFingerprint.originalMethod.definingClass
val featureClass = getFeatureValueFingerprint.originalMethod.parameterTypes[0].toString()
val configurationClass = getFeatureValueMethod.originalMethod.definingClass
val featureClass = getFeatureValueMethod.originalMethod.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(
getFeatureValueFingerprint.originalMethod.definingClass,
getFeatureValueMethod.originalMethod.definingClass,
"getValueOverride",
listOf(ImmutableMethodParameter(featureClass, null, "feature")),
"Ljava/lang/String;",
@ -62,15 +62,15 @@ val overrideFeatureFlagsPatch = bytecodePatch(
""",
)
}.also { helperMethod ->
getFeatureValueFingerprint.classDef.methods.add(helperMethod)
getFeatureValueMethod.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 = getFeatureValueFingerprint.instructionMatches.first().index
getFeatureValueFingerprint.method.addInstructionsWithLabels(
val getFeatureIndex = getFeatureValueMethod.instructionMatches.first().index
getFeatureValueMethod.addInstructionsWithLabels(
getFeatureIndex,
"""
# Call the Helper Method with the Feature

View file

@ -1,12 +1,19 @@
package app.revanced.patches.tumblr.fixes
import app.revanced.patcher.fingerprint
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.patch.BytecodePatchContext
import app.revanced.patcher.returnType
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 addQueryParamFingerprint = fingerprint {
internal val BytecodePatchContext.addQueryParamMethod by gettingFirstMethodDeclaratively {
parameterTypes("Ljava/lang/String;", "Ljava/lang/String;", "Z")
strings("Malformed URL. Base: ", ", Relative: ")
}
@ -14,7 +21,7 @@ internal val addQueryParamFingerprint = fingerprint {
// 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 httpPathParserFingerprint = fingerprint {
internal val BytecodePatchContext.httpPathParserMethod by gettingFirstMethodDeclaratively {
opcodes(
Opcode.IPUT_OBJECT,
Opcode.IPUT_BOOLEAN,

View file

@ -6,7 +6,7 @@ import app.revanced.patcher.patch.creatingBytecodePatch
@Suppress("unused")
val `Fix old versions` by creatingBytecodePatch(
description = "Fixes old versions of the app (v33.2 and earlier) breaking due to Tumblr removing remnants of Tumblr" +
" Live from the API, which causes many requests to fail. This patch has no effect on newer versions of the app.",
" Live from the API, which causes many requests to fail. This patch has no effect on newer versions of the app.",
use = false,
) {
compatibleWith("com.tumblr")
@ -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) {
httpPathParserFingerprint.method.addInstructions(
httpPathParserFingerprint.instructionMatches.last().index + 1,
httpPathParserMethod.addInstructions(
httpPathParserMethod.instructionMatches.last().index + 1,
"""
# urlPath = urlPath.replace(liveQueryParameter, "")
const-string p1, "$liveQueryParameter"
@ -38,7 +38,7 @@ val `Fix old versions` by creatingBytecodePatch(
// which would result in the path "api/me/inf0?fields[blog]=${value}"
// Here we make sure that this value doesn't contain the broken query parameters.
for (liveQueryParameter in liveQueryParameters) {
addQueryParamFingerprint.method.addInstructions(
addQueryParamMethod.addInstructions(
0,
"""
# queryParameterValue = queryParameterValue.replace(liveQueryParameter, "")

View file

@ -24,9 +24,9 @@ val filterTimelineObjectsPatch = bytecodePatch(
dependsOn(sharedExtensionPatch)
apply {
val filterInsertIndex = timelineFilterExtensionFingerprint.instructionMatches.first().index
val filterInsertIndex = timelineFilterExtensionMethod.instructionMatches.first().index
timelineFilterExtensionFingerprint.method.apply {
timelineFilterExtensionMethod.apply {
val addInstruction = getInstruction<BuilderInstruction35c>(filterInsertIndex + 1)
val filterListRegister = addInstruction.registerC
@ -48,8 +48,8 @@ val filterTimelineObjectsPatch = bytecodePatch(
}
arrayOf(
timelineConstructorFingerprint to 1,
postsResponseConstructorFingerprint to 2,
timelineConstructorMethod to 1,
postsResponseConstructorMethod to 2,
).forEach { (fingerprint, timelineObjectsRegister) ->
fingerprint.method.addInstructions(
0,

View file

@ -1,12 +1,19 @@
package app.revanced.patches.tumblr.timelinefilter
import app.revanced.patcher.fingerprint
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.patch.BytecodePatchContext
import app.revanced.patcher.returnType
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 TimelineConstructorFingerprint.
internal val postsResponseConstructorFingerprint = fingerprint {
// The same applies here as with the TimelineConstructorMethod.
internal val BytecodePatchContext.postsResponseConstructorMethod by gettingFirstMethodDeclaratively {
accessFlags(AccessFlags.CONSTRUCTOR, AccessFlags.PUBLIC)
custom { method, classDef -> classDef.endsWith("/PostsResponse;") && method.parameters.size == 4 }
}
@ -14,7 +21,7 @@ internal val postsResponseConstructorFingerprint = fingerprint {
// This is the constructor of the Timeline class.
// It receives the List<TimelineObject> as an argument with a @Json annotation, so this should be the first time
// that the List<TimelineObject> is exposed in non-library code.
internal val timelineConstructorFingerprint = fingerprint {
internal val BytecodePatchContext.timelineConstructorMethod by gettingFirstMethodDeclaratively {
strings("timelineObjectsList")
custom { method, classDef ->
classDef.endsWith("/Timeline;") && method.parameters[0].type == "Ljava/util/List;"
@ -24,7 +31,7 @@ internal val timelineConstructorFingerprint = fingerprint {
// This fingerprints the extension TimelineFilterPatch.filterTimeline method.
// The opcode fingerprint is searching for
// if ("BLOCKED_OBJECT_DUMMY".equals(elementType)) iterator.remove();
internal val timelineFilterExtensionFingerprint = fingerprint {
internal val BytecodePatchContext.timelineFilterExtensionMethod by gettingFirstMethodDeclaratively {
opcodes(
Opcode.CONST_STRING, // "BLOCKED_OBJECT_DUMMY"
Opcode.INVOKE_VIRTUAL, // HashSet.add(^)

View file

@ -1,6 +1,5 @@
package app.revanced.patches.twitch.misc.settings
import app.revanced.patcher.Fingerprint
import app.revanced.patcher.extensions.ExternalLabel
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.addInstructionsWithLabels
@ -98,9 +97,9 @@ val Settings by creatingBytecodePatch(
name,
MENU_ITEM_ENUM_CLASS_DESCRIPTOR,
AccessFlags.PUBLIC.value or
AccessFlags.FINAL.value or
AccessFlags.ENUM.value or
AccessFlags.STATIC.value,
AccessFlags.FINAL.value or
AccessFlags.ENUM.value or
AccessFlags.STATIC.value,
null,
null,
null,

View file

@ -1,10 +1,17 @@
package app.revanced.patches.twitter.interaction.downloads
import app.revanced.patcher.fingerprint
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.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
internal val buildMediaOptionsSheetFingerprint = fingerprint {
internal val BytecodePatchContext.buildMediaOptionsSheetMethod by gettingFirstMethodDeclaratively {
opcodes(
Opcode.IF_EQ,
Opcode.SGET_OBJECT,
@ -14,12 +21,12 @@ internal val buildMediaOptionsSheetFingerprint = fingerprint {
strings("mediaEntity", "media_options_sheet")
}
internal val constructMediaOptionsSheetFingerprint = fingerprint {
internal val BytecodePatchContext.constructMediaOptionsSheetMethod by gettingFirstMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
strings("captionsState")
}
internal val showDownloadVideoUpsellBottomSheetFingerprint = fingerprint {
internal val BytecodePatchContext.showDownloadVideoUpsellBottomSheetMethod by gettingFirstMethodDeclaratively {
returnType("Z")
strings("mediaEntity", "url")
opcodes(Opcode.IF_EQZ)

View file

@ -1,6 +1,5 @@
package app.revanced.patches.twitter.interaction.downloads
import app.revanced.patcher.Fingerprint
import app.revanced.patcher.extensions.*
import app.revanced.patcher.patch.creatingBytecodePatch
import com.android.tools.smali.dexlib2.Opcode
@ -20,7 +19,7 @@ val `Unlock downloads` by creatingBytecodePatch(
}
// Allow downloads for non-premium users.
showDownloadVideoUpsellBottomSheetFingerprint.patch {
showDownloadVideoUpsellBottomSheetMethod.patch {
val checkIndex = instructionMatches.first().index
val register = method.getInstruction<OneRegisterInstruction>(checkIndex).registerA
@ -28,7 +27,7 @@ val `Unlock downloads` by creatingBytecodePatch(
}
// Force show the download menu item.
constructMediaOptionsSheetFingerprint.patch {
constructMediaOptionsSheetMethod.patch {
val showDownloadButtonIndex = method.instructions.lastIndex - 1
val register = method.getInstruction<TwoRegisterInstruction>(showDownloadButtonIndex).registerA
@ -36,7 +35,7 @@ val `Unlock downloads` by creatingBytecodePatch(
}
// Make GIFs downloadable.
buildMediaOptionsSheetFingerprint.let {
buildMediaOptionsSheetMethod.let {
it.method.apply {
val checkMediaTypeIndex = it.instructionMatches.first().index
val checkMediaTypeInstruction = getInstruction<TwoRegisterInstruction>(checkMediaTypeIndex)

View file

@ -30,7 +30,7 @@ internal val domainNameOption = stringOption(
InetAddress.getByName(it)
} catch (_: UnknownHostException) {
Logger.getLogger(this::class.java.name).warning(
"Host \"$it\" did not resolve to any domain."
"Host \"$it\" did not resolve to any domain.",
)
} catch (_: Exception) {
// Must ignore any kind of exception. Trying to resolve network
@ -61,7 +61,7 @@ internal val changeLinkSharingDomainResourcePatch = resourcePatch {
@Suppress("unused")
val `Change link sharing domain` by creatingBytecodePatch(
description = "Replaces the domain name of shared links. Using this patch can prevent making posts that quote other posts.",
use = false
use = false,
) {
dependsOn(
sharedExtensionPatch,
@ -71,28 +71,28 @@ val `Change link sharing domain` by creatingBytecodePatch(
"com.twitter.android"(
"10.60.0-release.0",
"10.86.0-release.0",
)
),
)
val domainName by domainNameOption()
apply {
// Replace the domain name in the link sharing extension methods.
linkSharingDomainHelperFingerprint.method.returnEarly(domainName!!)
linkSharingDomainHelperMethod.returnEarly(domainName!!)
// Replace the domain name when copying a link with "Copy link" button.
linkBuilderFingerprint.method.addInstructions(
linkBuilderMethod.addInstructions(
0,
"""
invoke-static { p0, p1, p2 }, $EXTENSION_CLASS_DESCRIPTOR->formatLink(JLjava/lang/String;)Ljava/lang/String;
move-result-object p0
return-object p0
"""
""",
)
// TODO remove this once changeLinkSharingDomainResourcePatch is restored
// Replace the domain name in the "Share via..." dialog.
linkResourceGetterFingerprint.method.apply {
linkResourceGetterMethod.apply {
val templateIdConstIndex = indexOfFirstInstructionOrThrow(Opcode.CONST)
// Format the link with the new domain name register (1 instruction below the const).
@ -103,7 +103,7 @@ val `Change link sharing domain` by creatingBytecodePatch(
replaceInstruction(
formatLinkCallIndex,
"invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->" +
"formatResourceLink([Ljava/lang/Object;)Ljava/lang/String;",
"formatResourceLink([Ljava/lang/Object;)Ljava/lang/String;",
)
}
}

View file

@ -1,21 +1,28 @@
package app.revanced.patches.twitter.misc.links
import app.revanced.patcher.fingerprint
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.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.AccessFlags
internal val sanitizeSharingLinksFingerprint = fingerprint {
internal val BytecodePatchContext.sanitizeSharingLinksMethod by gettingFirstMethodDeclaratively {
returnType("Ljava/lang/String;")
strings("<this>", "shareParam", "sessionToken")
}
// Returns a shareable link string based on a tweet ID and a username.
internal val linkBuilderFingerprint = fingerprint {
internal val BytecodePatchContext.linkBuilderMethod by gettingFirstMethodDeclaratively {
strings("/%1\$s/status/%2\$d")
}
// TODO remove this once changeLinkSharingDomainResourcePatch is restored
// Returns a shareable link for the "Share via..." dialog.
internal val linkResourceGetterFingerprint = fingerprint {
internal val BytecodePatchContext.linkResourceGetterMethod by gettingFirstMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
parameterTypes("Landroid/content/res/Resources;")
custom { _, classDef ->
@ -25,7 +32,7 @@ internal val linkResourceGetterFingerprint = fingerprint {
}
}
internal val linkSharingDomainHelperFingerprint = fingerprint {
internal val BytecodePatchContext.linkSharingDomainHelperMethod by gettingFirstMethodDeclaratively {
custom { method, classDef ->
method.name == "getShareDomain" && classDef.type == EXTENSION_CLASS_DESCRIPTOR
}

View file

@ -11,11 +11,11 @@ val `Sanitize sharing links` by creatingBytecodePatch(
"com.twitter.android"(
"10.60.0-release.0",
"10.86.0-release.0",
)
),
)
apply {
sanitizeSharingLinksFingerprint.method.addInstructions(
sanitizeSharingLinksMethod.addInstructions(
0,
"""
# Method takes in a link (string, param 0) and then appends the tracking query params,

View file

@ -1,7 +1,5 @@
package app.revanced.patches.viber.ads
import app.revanced.patcher.fingerprint
internal val findAdStringFingerprint = fingerprint {
internal val BytecodePatchContext.findAdStringMethod by gettingFirstMethodDeclaratively {
strings("viber_plus_debug_ads_free_flag")
}

View file

@ -1,7 +1,6 @@
package app.revanced.patches.viber.ads
import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.fingerprint
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
import app.revanced.util.returnEarly
@ -16,10 +15,10 @@ val `Hide Ads` by creatingBytecodePatch(
compatibleWith("com.viber.voip"("25.9.2.0", "26.1.2.0"))
apply {
val method = findAdStringFingerprint.method
val method = findAdStringMethod
// Find the ads free string index
val stringIndex = findAdStringFingerprint.stringMatches.first().index
val stringIndex = findAdStringMethod.stringMatches.first().index
// Search backwards from the string to find the `new-instance` (TypeReference) instruction
val typeRefIndex =

View file

@ -1,8 +1,14 @@
package app.revanced.patches.viber.misc.navbar
import app.revanced.patcher.fingerprint
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.patch.BytecodePatchContext
import app.revanced.patcher.returnType
internal val tabIdClassFingerprint = fingerprint {
internal val BytecodePatchContext.tabIdClassMethod by gettingFirstMethodDeclaratively {
strings("shouldShowTabId")
}
@ -11,6 +17,6 @@ internal val shouldShowTabIdMethodFingerprint get() = fingerprint {
parameterTypes("I", "I")
returnType("Z")
custom { methodDef, classDef ->
classDef == tabIdClassFingerprint.classDef
classDef == tabIdClassMethod.classDef
}
}

View file

@ -1,6 +1,13 @@
package app.revanced.patches.youtube.ad.general
import app.revanced.patcher.fingerprint
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.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import app.revanced.util.containsLiteralInstruction
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionReversed
@ -8,7 +15,7 @@ import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
internal val fullScreenEngagementAdContainerFingerprint = fingerprint {
internal val BytecodePatchContext.fullScreenEngagementAdContainerMethod by gettingFirstMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("V")
parameterTypes()

View file

@ -84,7 +84,7 @@ val `Hide ads` by creatingBytecodePatch(
apply {
// Hide end screen store banner.
fullScreenEngagementAdContainerFingerprint.method.apply {
fullScreenEngagementAdContainerMethod.apply {
val addListIndex = indexOfAddListInstruction(this)
val addListInstruction = getInstruction<FiveRegisterInstruction>(addListIndex)
val listRegister = addListInstruction.registerC

View file

@ -1,10 +1,17 @@
package app.revanced.patches.youtube.ad.getpremium
import app.revanced.patcher.fingerprint
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.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
internal val getPremiumViewFingerprint = fingerprint {
internal val BytecodePatchContext.getPremiumViewMethod by gettingFirstMethodDeclaratively {
accessFlags(AccessFlags.PROTECTED, AccessFlags.FINAL)
returnType("V")
parameterTypes("I", "I")

View file

@ -29,7 +29,7 @@ val hideGetPremiumPatch = bytecodePatch(
"20.14.43",
"20.21.37",
"20.31.40",
)
),
)
apply {
@ -39,8 +39,8 @@ val hideGetPremiumPatch = bytecodePatch(
SwitchPreference("revanced_hide_get_premium"),
)
getPremiumViewFingerprint.method.apply {
val startIndex = getPremiumViewFingerprint.instructionMatches.first().index
getPremiumViewMethod.apply {
val startIndex = getPremiumViewMethod.instructionMatches.first().index
val measuredWidthRegister = getInstruction<TwoRegisterInstruction>(startIndex).registerA
val measuredHeightInstruction = getInstruction<TwoRegisterInstruction>(startIndex + 1)

View file

@ -1,8 +1,6 @@
package app.revanced.patches.youtube.ad.video
import app.revanced.patcher.fingerprint
internal val loadVideoAdsFingerprint = fingerprint {
internal val BytecodePatchContext.loadVideoAdsMethod by gettingFirstMethodDeclaratively {
strings(
"TriggerBundle doesn't have the required metadata specified by the trigger ",
"Ping migration no associated ping bindings for activated trigger: ",

View file

@ -26,7 +26,7 @@ val `Video ads` by creatingBytecodePatch(
"20.14.43",
"20.21.37",
"20.31.40",
)
),
)
apply {
@ -36,7 +36,7 @@ val `Video ads` by creatingBytecodePatch(
SwitchPreference("revanced_hide_video_ads"),
)
loadVideoAdsFingerprint.method.addInstructionsWithLabels(
loadVideoAdsMethod.addInstructionsWithLabels(
0,
"""
invoke-static { }, Lapp/revanced/extension/youtube/patches/VideoAdsPatch;->shouldShowAds()Z
@ -44,7 +44,7 @@ val `Video ads` by creatingBytecodePatch(
if-nez v0, :show_video_ads
return-void
""",
ExternalLabel("show_video_ads", loadVideoAdsFingerprint.method.getInstruction(0)),
ExternalLabel("show_video_ads", loadVideoAdsMethod.getInstruction(0)),
)
}
}

View file

@ -1,9 +1,16 @@
package app.revanced.patches.youtube.interaction.dialog
import app.revanced.patcher.fingerprint
import app.revanced.patcher.accessFlags
import app.revanced.patcher.gettingFirstMethodDeclaratively
import app.revanced.patcher.instructions
import app.revanced.patcher.invoke
import app.revanced.patcher.methodCall
import app.revanced.patcher.opcodes
import app.revanced.patcher.parameterTypes
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
internal val createDialogFingerprint = fingerprint {
internal val BytecodePatchContext.createDialogMethod by gettingFirstMethodDeclaratively {
returnType("V")
parameterTypes("L", "L", "Ljava/lang/String;")
instructions(

View file

@ -16,7 +16,7 @@ private const val EXTENSION_CLASS_DESCRIPTOR =
val `Remove viewer discretion dialog` by creatingBytecodePatch(
description = "Adds an option to remove the dialog that appears when opening a video that has been age-restricted " +
"by accepting it automatically. This does not bypass the age restriction.",
"by accepting it automatically. This does not bypass the age restriction.",
) {
dependsOn(
sharedExtensionPatch,
@ -30,7 +30,7 @@ val `Remove viewer discretion dialog` by creatingBytecodePatch(
"20.14.43",
"20.21.37",
"20.31.40",
)
),
)
apply {
@ -40,7 +40,7 @@ val `Remove viewer discretion dialog` by creatingBytecodePatch(
SwitchPreference("revanced_remove_viewer_discretion_dialog"),
)
createDialogFingerprint.let {
createDialogMethod.let {
it.method.apply {
val showDialogIndex = it.instructionMatches.last().index // TODO
val dialogRegister = getInstruction<FiveRegisterInstruction>(showDialogIndex).registerC

View file

@ -1,7 +1,6 @@
package app.revanced.patches.youtube.interaction.doubletap
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.fingerprint
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch
@ -57,7 +56,7 @@ val `Disable double tap actions` by creatingBytecodePatch(
val doubleTapInfoGetSeekSourceFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
parameterTypes("Z")
returnType(seekTypeEnumFingerprint.originalClassDef.type)
returnType(seekTypeEnumMethod.originalClassDef.type)
opcodes(
Opcode.IF_EQZ,
Opcode.SGET_OBJECT,
@ -79,7 +78,7 @@ val `Disable double tap actions` by creatingBytecodePatch(
""",
)
doubleTapInfoCtorFingerprint.match(
doubleTapInfoCtorMethod.match(
doubleTapInfoGetSeekSourceFingerprint.classDef,
).method.addInstructions(
0,

View file

@ -1,9 +1,16 @@
package app.revanced.patches.youtube.interaction.doubletap
import app.revanced.patcher.fingerprint
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.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.AccessFlags
internal val seekTypeEnumFingerprint = fingerprint {
internal val BytecodePatchContext.seekTypeEnumMethod by gettingFirstMethodDeclaratively {
accessFlags(AccessFlags.STATIC, AccessFlags.CONSTRUCTOR)
strings(
"SEEK_SOURCE_SEEK_TO_NEXT_CHAPTER",
@ -11,7 +18,7 @@ internal val seekTypeEnumFingerprint = fingerprint {
)
}
internal val doubleTapInfoCtorFingerprint = fingerprint {
internal val BytecodePatchContext.doubleTapInfoCtorMethod by gettingFirstMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
parameterTypes(
"Landroid/view/MotionEvent;",

View file

@ -62,7 +62,7 @@ internal const val BUTTON_DESCRIPTOR = "Lapp/revanced/extension/youtube/videopla
@Suppress("unused")
val Downloads by creatingBytecodePatch(
description = "Adds support to download videos with an external downloader app " +
"using the in-app download button or a video player action button.",
"using the in-app download button or a video player action button.",
) {
dependsOn(
downloadsResourcePatch,
@ -76,7 +76,7 @@ val Downloads by creatingBytecodePatch(
"20.14.43",
"20.21.37",
"20.31.40",
)
),
)
apply {
@ -86,10 +86,10 @@ val Downloads by creatingBytecodePatch(
// Main activity is used to launch downloader intent.
mainActivityOnCreateMethod.addInstruction(
0,
"invoke-static/range { p0 .. p0 }, ${EXTENSION_CLASS_DESCRIPTOR}->setMainActivity(Landroid/app/Activity;)V"
"invoke-static/range { p0 .. p0 }, ${EXTENSION_CLASS_DESCRIPTOR}->setMainActivity(Landroid/app/Activity;)V",
)
offlineVideoEndpointFingerprint.method.apply {
offlineVideoEndpointMethod.apply {
addInstructionsWithLabels(
0,
"""

View file

@ -1,10 +1,17 @@
package app.revanced.patches.youtube.interaction.downloads
import app.revanced.patcher.accessFlags
import app.revanced.patcher.addString
import app.revanced.patcher.fingerprint
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.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.AccessFlags
internal val offlineVideoEndpointFingerprint = fingerprint {
internal val BytecodePatchContext.offlineVideoEndpointMethod by gettingFirstMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("V")
parameterTypes(

View file

@ -1,9 +1,9 @@
package app.revanced.patches.youtube.interaction.seekbar
import app.revanced.patcher.extensions.ExternalLabel
import app.revanced.patcher.extensions.addInstructionsWithLabels
import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.extensions.ExternalLabel
import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
@ -34,30 +34,32 @@ val enableSeekbarTappingPatch = bytecodePatch(
)
// Find the required methods to tap the seekbar.
val seekbarTappingMethods = onTouchEventHandlerFingerprint.let {
val seekbarTappingMethods = onTouchEventHandlerMethod.let {
fun getReference(index: Int) = it.method.getInstruction<ReferenceInstruction>(index)
.reference as MethodReference
listOf(
getReference(it.instructionMatches.first().index),
getReference(it.instructionMatches.last().index)
getReference(it.instructionMatches.last().index),
)
}
seekbarTappingFingerprint.let {
seekbarTappingMethod.let {
val insertIndex = it.instructionMatches.last().index + 1
it.method.apply {
val thisInstanceRegister = getInstruction<FiveRegisterInstruction>(
insertIndex - 1
insertIndex - 1,
).registerC
val xAxisRegister = this.getInstruction<FiveRegisterInstruction>(
it.instructionMatches[2].index
it.instructionMatches[2].index,
).registerD
val freeRegister = findFreeRegister(
insertIndex, thisInstanceRegister, xAxisRegister
insertIndex,
thisInstanceRegister,
xAxisRegister,
)
val oMethod = seekbarTappingMethods[0]

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