build(revanced-patcher): bump version

This commit is contained in:
inotia00 2023-05-09 18:37:49 +09:00
parent 8958c3870f
commit 0f5350e691
43 changed files with 485 additions and 567 deletions

View File

@ -20,7 +20,7 @@ repositories {
}
dependencies {
implementation("app.revanced:revanced-patcher:7.0.0")
implementation("app.revanced:revanced-patcher:7.1.1")
implementation("app.revanced:multidexlib2:2.5.3-a3836654")
// Required for meta
implementation("com.google.code.gson:gson:2.10.1")

View File

@ -5,7 +5,7 @@ import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.*
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
@ -25,23 +25,19 @@ import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
@YouTubeMusicCompatibility
@Version("0.0.1")
class DisableAutoCaptionsPatch : BytecodePatch(
listOf(
SubtitleTrackFingerprint
)
listOf(SubtitleTrackFingerprint)
) {
override fun execute(context: BytecodeContext): PatchResult {
SubtitleTrackFingerprint.result?.mutableMethod?.let {
with (it.implementation!!.instructions) {
val index = size - 1
val register = (elementAt(index) as OneRegisterInstruction).registerA
it.addInstructions(
index, """
val index = it.implementation!!.instructions.size - 1
val register = it.instruction<OneRegisterInstruction>(index).registerA
it.addInstructions(
index, """
invoke-static {v$register}, $MUSIC_LAYOUT->disableAutoCaptions(Z)Z
move-result v$register
"""
)
}
)
} ?: return SubtitleTrackFingerprint.toErrorResult()
MusicSettingsPatch.addMusicPreference(CategoryType.LAYOUT, "revanced_disable_auto_captions", "false")

View File

@ -2,8 +2,8 @@ package app.revanced.patches.music.layout.blacknavbar.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.music.misc.resourceid.patch.SharedResourceIdPatch
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
import app.revanced.patches.music.misc.resourceid.patch.SharedResourceIdPatch.Companion.colorGreyId
import app.revanced.util.bytecode.isWideLiteralExists
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@ -16,11 +16,6 @@ object TabLayoutFingerprint : MethodFingerprint(
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT
),
customFingerprint = { methodDef ->
methodDef.implementation?.instructions?.any {
it.opcode.ordinal == Opcode.CONST.ordinal &&
(it as? WideLiteralInstruction)?.wideLiteral == SharedResourceIdPatch.colorGreyLabelId
} == true
}
customFingerprint = { it.isWideLiteralExists(colorGreyId) }
)

View File

@ -18,7 +18,7 @@ import app.revanced.patches.music.misc.settings.resource.patch.MusicSettingsPatc
import app.revanced.patches.shared.annotation.YouTubeMusicCompatibility
import app.revanced.util.enum.CategoryType
import app.revanced.util.integrations.Constants.MUSIC_LAYOUT
import org.jf.dexlib2.iface.instruction.formats.Instruction11x
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
@Patch
@Name("enable-black-navbar")
@ -32,21 +32,17 @@ import org.jf.dexlib2.iface.instruction.formats.Instruction11x
@YouTubeMusicCompatibility
@Version("0.0.1")
class BlackNavbarPatch : BytecodePatch(
listOf(
TabLayoutFingerprint
)
listOf(TabLayoutFingerprint)
) {
override fun execute(context: BytecodeContext): PatchResult {
TabLayoutFingerprint.result?.let {
with (it.mutableMethod) {
val endIndex = it.scanResult.patternScanResult!!.endIndex
val insertIndex = endIndex + 1
val targetRegister = (instruction(endIndex) as Instruction11x).registerA
it.mutableMethod.apply {
val targetIndex = it.scanResult.patternScanResult!!.endIndex
val targetRegister = instruction<OneRegisterInstruction>(targetIndex).registerA
addInstructions(
insertIndex, """
targetIndex + 1, """
invoke-static {}, $MUSIC_LAYOUT->enableBlackNavbar()I
move-result v$targetRegister
"""

View File

@ -25,9 +25,7 @@ import app.revanced.util.integrations.Constants.MUSIC_LAYOUT
@YouTubeMusicCompatibility
@Version("0.0.1")
class HideCastButtonPatch : BytecodePatch(
listOf(
HideCastButtonParentFingerprint
)
listOf(HideCastButtonParentFingerprint)
) {
override fun execute(context: BytecodeContext): PatchResult {

View File

@ -0,0 +1,18 @@
package app.revanced.patches.music.layout.categorybar.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.music.misc.resourceid.patch.SharedResourceIdPatch.Companion.chipCloudId
import app.revanced.util.bytecode.isWideLiteralExists
import org.jf.dexlib2.Opcode
object ChipCloudFingerprint : MethodFingerprint(
returnType = "V",
opcodes = listOf(
Opcode.CONST,
Opcode.CONST_4,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT
),
customFingerprint = { it.isWideLiteralExists(chipCloudId) }
)

View File

@ -1,82 +1,54 @@
package app.revanced.patches.music.layout.categorybar.patch
import app.revanced.extensions.findMutableMethodOf
import app.revanced.extensions.toResult
import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.extensions.instruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.music.layout.categorybar.fingerprints.ChipCloudFingerprint
import app.revanced.patches.music.misc.resourceid.patch.SharedResourceIdPatch
import app.revanced.patches.music.misc.settings.resource.patch.MusicSettingsPatch
import app.revanced.patches.shared.annotation.YouTubeMusicCompatibility
import app.revanced.patches.shared.patch.mapping.ResourceMappingPatch
import app.revanced.util.enum.CategoryType
import app.revanced.util.integrations.Constants.MUSIC_LAYOUT
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.instruction.formats.Instruction21c
import org.jf.dexlib2.iface.instruction.formats.Instruction31i
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
@Patch
@Name("hide-category-bar")
@Description("Hides the music category bar at the top of the homepage.")
@DependsOn(
[
ResourceMappingPatch::class,
SharedResourceIdPatch::class,
MusicSettingsPatch::class
]
)
@YouTubeMusicCompatibility
@Version("0.0.1")
class CategoryBarPatch : BytecodePatch() {
// list of resource names to get the id of
private val resourceIds = arrayOf(
"layout" to "chip_cloud"
).map { (type, name) ->
ResourceMappingPatch
.resourceMappings
.single { it.type == type && it.name == name }.id
}
private var patchSuccessArray = Array(resourceIds.size) {false}
class CategoryBarPatch : BytecodePatch(
listOf(ChipCloudFingerprint)
) {
override fun execute(context: BytecodeContext): PatchResult {
context.classes.forEach { classDef ->
classDef.methods.forEach { method ->
with(method.implementation) {
this?.instructions?.forEachIndexed { index, instruction ->
when (instruction.opcode) {
Opcode.CONST -> {
when ((instruction as Instruction31i).wideLiteral) {
resourceIds[0] -> { // compact header
val insertIndex = index + 4
val invokeInstruction = instructions.elementAt(insertIndex)
if (invokeInstruction.opcode != Opcode.CHECK_CAST) return@forEachIndexed
ChipCloudFingerprint.result?.let {
it.mutableMethod.apply {
val targetIndex = it.scanResult.patternScanResult!!.endIndex
val targetRegister = instruction<OneRegisterInstruction>(targetIndex).registerA
val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method)
val register = (invokeInstruction as Instruction21c).registerA
mutableMethod.addInstruction(
insertIndex,
"invoke-static { v$register }, $MUSIC_LAYOUT->hideCategoryBar(Landroid/view/View;)V"
)
MusicSettingsPatch.addMusicPreference(CategoryType.LAYOUT, "revanced_hide_category_bar", "true")
patchSuccessArray[0] = true
}
}
}
else -> return@forEachIndexed
}
}
}
addInstruction(
targetIndex + 1,
"invoke-static { v$targetRegister }, $MUSIC_LAYOUT->hideCategoryBar(Landroid/view/View;)V"
)
}
}
return toResult(patchSuccessArray.indexOf(false))
} ?: return ChipCloudFingerprint.toErrorResult()
MusicSettingsPatch.addMusicPreference(CategoryType.LAYOUT, "revanced_hide_category_bar", "true")
return PatchResultSuccess()
}
}

View File

@ -1,11 +1,11 @@
package app.revanced.patches.music.layout.miniplayercolor.fingerprints
package app.revanced.patches.music.layout.colormatchplayer.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
object MiniplayerColorFingerprint : MethodFingerprint(
object ColorMatchPlayerFingerprint : MethodFingerprint(
returnType = "V",
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("L", "J"),

View File

@ -0,0 +1,86 @@
package app.revanced.patches.music.layout.colormatchplayer.patch
import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.instruction
import app.revanced.patcher.extensions.removeInstruction
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.music.layout.colormatchplayer.fingerprints.ColorMatchPlayerFingerprint
import app.revanced.patches.music.misc.settings.resource.patch.MusicSettingsPatch
import app.revanced.patches.shared.annotation.YouTubeMusicCompatibility
import app.revanced.patches.shared.fingerprints.ColorMatchPlayerParentFingerprint
import app.revanced.util.enum.CategoryType
import app.revanced.util.integrations.Constants.MUSIC_LAYOUT
import org.jf.dexlib2.iface.instruction.Instruction
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
@Patch
@Name("enable-color-match-player")
@Description("Matches the fullscreen player color with the minimized one.")
@DependsOn([MusicSettingsPatch::class])
@YouTubeMusicCompatibility
@Version("0.0.1")
class ColorMatchPlayerPatch : BytecodePatch(
listOf(ColorMatchPlayerParentFingerprint)
) {
override fun execute(context: BytecodeContext): PatchResult {
ColorMatchPlayerParentFingerprint.result?.let { parentResult ->
ColorMatchPlayerFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.let {
it.mutableMethod.apply {
targetMethod = parentResult.mutableMethod
val insertIndex = it.scanResult.patternScanResult!!.startIndex + 1
val jumpInstruction = instruction<Instruction>(insertIndex)
val type = it.classDef.type
addInstructions(
insertIndex, """
invoke-static {}, $MUSIC_LAYOUT->enableColorMatchPlayer()Z
move-result v2
if-eqz v2, :off
iget v0, p0, ${descriptor(4)}
if-eq v0, v2, :abswitch
iput v2, p0, ${descriptor(4)}
iget-object v0, p0, ${descriptor(5)}
invoke-virtual {v0, v2, p2, p3}, ${descriptor(6)}
:abswitch
iget v0, p0, ${descriptor(10)}
if-eq v0, v1, :exit
iput v1, p0, ${descriptor(10)}
iget-object v0, p0, ${descriptor(11)}
invoke-virtual {v0, v1, p2, p3}, ${descriptor(12)}
goto :exit
:off
invoke-direct {p0}, ${type}->${parentResult.mutableMethod.name}()V
""", listOf(ExternalLabel("exit", jumpInstruction))
)
removeInstruction(insertIndex - 1)
}
} ?: return ColorMatchPlayerFingerprint.toErrorResult()
} ?: return ColorMatchPlayerParentFingerprint.toErrorResult()
MusicSettingsPatch.addMusicPreference(CategoryType.LAYOUT, "revanced_enable_color_match_player", "true")
return PatchResultSuccess()
}
private companion object {
private lateinit var targetMethod: MutableMethod
fun descriptor(index: Int):String {
return (targetMethod.instruction(index) as ReferenceInstruction).reference.toString()
}
}
}

View File

@ -2,8 +2,8 @@ package app.revanced.patches.music.layout.compactdialog.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.music.misc.resourceid.patch.SharedResourceIdPatch
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
import app.revanced.patches.music.misc.resourceid.patch.SharedResourceIdPatch.Companion.dialogSolidId
import app.revanced.util.bytecode.isWideLiteralExists
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@ -16,11 +16,6 @@ object DialogSolidFingerprint : MethodFingerprint(
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_STATIC
),
customFingerprint = { methodDef ->
methodDef.implementation?.instructions?.any {
it.opcode.ordinal == Opcode.CONST.ordinal &&
(it as? WideLiteralInstruction)?.wideLiteral == SharedResourceIdPatch.dialogSolidLabelId
} == true
}
customFingerprint = { it.isWideLiteralExists(dialogSolidId) }
)

View File

@ -20,6 +20,7 @@ import app.revanced.patches.shared.annotation.YouTubeMusicCompatibility
import app.revanced.util.enum.CategoryType
import app.revanced.util.integrations.Constants.MUSIC_LAYOUT
@Patch
@Name("enable-compact-dialog")
@Description("Enable compact dialog on phone.")
@ -32,9 +33,7 @@ import app.revanced.util.integrations.Constants.MUSIC_LAYOUT
@YouTubeMusicCompatibility
@Version("0.0.1")
class CompactDialogPatch : BytecodePatch(
listOf(
DialogSolidFingerprint
)
listOf(DialogSolidFingerprint)
) {
override fun execute(context: BytecodeContext): PatchResult {
DialogSolidFingerprint.result?.let {

View File

@ -2,19 +2,15 @@ package app.revanced.patches.music.layout.floatingbutton.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.util.bytecode.isNarrowLiteralExists
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.instruction.NarrowLiteralInstruction
object FloatingButtonParentFingerprint : MethodFingerprint(
returnType = "V",
access = AccessFlags.PROTECTED or AccessFlags.FINAL,
parameters = listOf("L"),
opcodes = listOf(Opcode.INVOKE_DIRECT),
customFingerprint = { methodDef ->
methodDef.implementation!!.instructions.any {
((it as? NarrowLiteralInstruction)?.narrowLiteral == 259982244)
}
}
customFingerprint = { it.isNarrowLiteralExists(259982244) }
)

View File

@ -33,9 +33,7 @@ import app.revanced.util.integrations.Constants.MUSIC_LAYOUT
@YouTubeMusicCompatibility
@Version("0.0.1")
class NewPlaylistButtonPatch : BytecodePatch(
listOf(
FloatingButtonParentFingerprint
)
listOf(FloatingButtonParentFingerprint)
) {
override fun execute(context: BytecodeContext): PatchResult {

View File

@ -2,8 +2,8 @@ package app.revanced.patches.music.layout.landscapemode.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.music.misc.resourceid.patch.SharedResourceIdPatch
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
import app.revanced.patches.music.misc.resourceid.patch.SharedResourceIdPatch.Companion.isTabletId
import app.revanced.util.bytecode.isWideLiteralExists
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@ -16,11 +16,6 @@ object TabletIdentifierFingerprint : MethodFingerprint(
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT
),
customFingerprint = { methodDef ->
methodDef.implementation?.instructions?.any {
it.opcode.ordinal == Opcode.CONST.ordinal &&
(it as? WideLiteralInstruction)?.wideLiteral == SharedResourceIdPatch.isTabletLabelId
} == true
}
customFingerprint = { it.isWideLiteralExists(isTabletId) }
)

View File

@ -30,18 +30,16 @@ import app.revanced.util.integrations.Constants.MUSIC_LAYOUT
@YouTubeMusicCompatibility
@Version("0.0.1")
class LandScapeModePatch : BytecodePatch(
listOf(
TabletIdentifierFingerprint
)
listOf(TabletIdentifierFingerprint)
) {
override fun execute(context: BytecodeContext): PatchResult {
TabletIdentifierFingerprint.result?.let {
it.mutableMethod.addInstructions(
it.scanResult.patternScanResult!!.endIndex + 1, """
invoke-static {p0}, $MUSIC_LAYOUT->enableLandScapeMode(Z)Z
move-result p0
"""
)
invoke-static {p0}, $MUSIC_LAYOUT->enableLandScapeMode(Z)Z
move-result p0
"""
)
} ?: return TabletIdentifierFingerprint.toErrorResult()
MusicSettingsPatch.addMusicPreference(CategoryType.LAYOUT, "revanced_enable_landscape_mode", "true")

View File

@ -25,9 +25,7 @@ import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
@YouTubeMusicCompatibility
@Version("0.0.1")
class MinimizedPlayerPatch : BytecodePatch(
listOf(
MinimizedPlayerFingerprint
)
listOf(MinimizedPlayerFingerprint)
) {
override fun execute(context: BytecodeContext): PatchResult {

View File

@ -1,109 +0,0 @@
package app.revanced.patches.music.layout.miniplayercolor.patch
import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.removeInstruction
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.music.layout.miniplayercolor.fingerprints.MiniplayerColorFingerprint
import app.revanced.patches.music.misc.settings.resource.patch.MusicSettingsPatch
import app.revanced.patches.shared.annotation.YouTubeMusicCompatibility
import app.revanced.patches.shared.fingerprints.MiniplayerColorParentFingerprint
import app.revanced.util.enum.CategoryType
import app.revanced.util.integrations.Constants.MUSIC_LAYOUT
import org.jf.dexlib2.iface.instruction.Instruction
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.reference.FieldReference
import org.jf.dexlib2.iface.reference.MethodReference
@Patch
@Name("enable-color-match-player")
@Description("Matches the fullscreen player color with the minimized one.")
@DependsOn([MusicSettingsPatch::class])
@YouTubeMusicCompatibility
@Version("0.0.1")
class MiniplayerColorPatch : BytecodePatch(
listOf(
MiniplayerColorFingerprint, MiniplayerColorParentFingerprint
)
) {
override fun execute(context: BytecodeContext): PatchResult {
MiniplayerColorParentFingerprint.result?.let { parentResult ->
with (parentResult.mutableMethod.implementation!!.instructions) {
firstReference =
(elementAt(4) as ReferenceInstruction).reference as FieldReference
secondReference =
(elementAt(5) as ReferenceInstruction).reference as FieldReference
thirdReference =
(elementAt(6) as ReferenceInstruction).reference as MethodReference
fourthReference =
(elementAt(10) as ReferenceInstruction).reference as FieldReference
fifthReference =
(elementAt(11) as ReferenceInstruction).reference as FieldReference
sixthReference =
(elementAt(12) as ReferenceInstruction).reference as MethodReference
}
MiniplayerColorFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.let {
with (it.mutableMethod) {
val insertIndex = it.scanResult.patternScanResult!!.startIndex + 1
val jumpInstruction = implementation!!.instructions[insertIndex] as Instruction
val type = it.classDef.type
addInstructions(
insertIndex, """
invoke-static {}, $MUSIC_LAYOUT->enableColorMatchPlayer()Z
move-result v2
if-eqz v2, :off
iget v0, p0, ${type}->${firstReference.name}:${firstReference.type}
if-eq v0, v2, :abswitch
iput v2, p0, ${type}->${firstReference.name}:${firstReference.type}
iget-object v0, p0, ${type}->${secondReference.name}:${secondReference.type}
invoke-virtual {v0, v2, p2, p3}, $thirdReference
:abswitch
iget v0, p0, ${type}->${fourthReference.name}:${fourthReference.type}
if-eq v0, v1, :exit
iput v1, p0, ${type}->${fourthReference.name}:${fourthReference.type}
iget-object v0, p0, ${type}->${fifthReference.name}:${fifthReference.type}
invoke-virtual {v0, v1, p2, p3}, $sixthReference
goto :exit
:off
invoke-direct {p0}, ${type}->${parentResult.mutableMethod.name}()V
""", listOf(ExternalLabel("exit", jumpInstruction))
)
removeInstruction(insertIndex - 1)
}
} ?: return MiniplayerColorFingerprint.toErrorResult()
} ?: return MiniplayerColorParentFingerprint.toErrorResult()
MusicSettingsPatch.addMusicPreference(CategoryType.LAYOUT, "revanced_enable_color_match_player", "true")
return PatchResultSuccess()
}
private companion object {
private lateinit var firstReference: FieldReference
private lateinit var secondReference: FieldReference
private lateinit var thirdReference: MethodReference
private lateinit var fourthReference: FieldReference
private lateinit var fifthReference: FieldReference
private lateinit var sixthReference: MethodReference
}
}

View File

@ -5,7 +5,9 @@ import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.*
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.instruction
import app.revanced.patcher.extensions.removeInstruction
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
@ -15,12 +17,11 @@ import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.music.layout.zenmode.fingerprints.ZenModeFingerprint
import app.revanced.patches.music.misc.settings.resource.patch.MusicSettingsPatch
import app.revanced.patches.shared.annotation.YouTubeMusicCompatibility
import app.revanced.patches.shared.fingerprints.MiniplayerColorParentFingerprint
import app.revanced.patches.shared.fingerprints.ColorMatchPlayerParentFingerprint
import app.revanced.util.enum.CategoryType
import app.revanced.util.integrations.Constants.MUSIC_LAYOUT
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.reference.FieldReference
@Patch
@Name("enable-zen-mode")
@ -29,24 +30,21 @@ import org.jf.dexlib2.iface.reference.FieldReference
@YouTubeMusicCompatibility
@Version("0.0.1")
class ZenModePatch : BytecodePatch(
listOf(
ZenModeFingerprint, MiniplayerColorParentFingerprint
)
listOf(ColorMatchPlayerParentFingerprint)
) {
override fun execute(context: BytecodeContext): PatchResult {
MiniplayerColorParentFingerprint.result?.let { parentResult ->
ColorMatchPlayerParentFingerprint.result?.let { parentResult ->
ZenModeFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.let {
with (it.mutableMethod) {
val instructions = this.implementation!!.instructions
it.mutableMethod.apply {
val startIndex = it.scanResult.patternScanResult!!.startIndex
val firstRegister = (instruction(startIndex) as OneRegisterInstruction).registerA
val secondRegister = (instruction(startIndex + 2) as OneRegisterInstruction).registerA
val firstRegister = instruction<OneRegisterInstruction>(startIndex).registerA
val secondRegister = instruction<OneRegisterInstruction>(startIndex + 2).registerA
val dummyRegister = secondRegister + 1
val referenceIndex = it.scanResult.patternScanResult!!.endIndex + 1
val fieldReference = (instructions.elementAt(referenceIndex) as ReferenceInstruction).reference as FieldReference
val targetReference = (instruction(referenceIndex) as ReferenceInstruction).reference.toString()
val insertIndex = referenceIndex + 1
@ -60,13 +58,13 @@ class ZenModePatch : BytecodePatch(
const v$firstRegister, -0xbfbfc0
const v$secondRegister, -0xbfbfc0
:off
sget-object v0, ${fieldReference.type}->${fieldReference.name}:${fieldReference.type}
sget-object v0, $targetReference
"""
)
removeInstruction(referenceIndex)
}
} ?: return ZenModeFingerprint.toErrorResult()
} ?: return MiniplayerColorParentFingerprint.toErrorResult()
} ?: return ColorMatchPlayerParentFingerprint.toErrorResult()
MusicSettingsPatch.addMusicPreference(CategoryType.LAYOUT, "revanced_enable_zen_mode", "false")

View File

@ -25,10 +25,14 @@ class ClientSpoofMusicPatch : BytecodePatch(
override fun execute(context: BytecodeContext): PatchResult {
UserAgentHeaderBuilderFingerprint.result?.let {
with (it.mutableMethod) {
it.mutableMethod.apply {
val insertIndex = it.scanResult.patternScanResult!!.endIndex - 1
val packageNameRegister = (instruction(insertIndex) as FiveRegisterInstruction).registerD
addInstruction(insertIndex, "const-string v$packageNameRegister, \"$MUSIC_PACKAGE_NAME\"")
val packageNameRegister = instruction<FiveRegisterInstruction>(insertIndex).registerD
addInstruction(
insertIndex,
"const-string v$packageNameRegister, \"$MUSIC_PACKAGE_NAME\""
)
}
} ?: return UserAgentHeaderBuilderFingerprint.toErrorResult()

View File

@ -38,28 +38,26 @@ class CodecsUnlockPatch : BytecodePatch(
override fun execute(context: BytecodeContext): PatchResult {
AllCodecsParentFingerprint.result?.let { parentResult ->
AllCodecsFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.let { result ->
allCodecsMethod =
context.toMethodWalker(result.method)
.nextMethod(result.scanResult.patternScanResult!!.endIndex)
AllCodecsFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.let {
allCodecsMethod = context.toMethodWalker(it.method)
.nextMethod(it.scanResult.patternScanResult!!.endIndex)
.getMethod()
} ?: return AllCodecsFingerprint.toErrorResult()
} ?: return AllCodecsParentFingerprint.toErrorResult()
CodecsLockFingerprint.result?.let { result ->
val endIndex = result.scanResult.patternScanResult!!.endIndex
with(result.mutableMethod) {
val register = (instruction(endIndex) as OneRegisterInstruction).registerA
CodecsLockFingerprint.result?.let {
it.mutableMethod.apply {
val targetIndex = it.scanResult.patternScanResult!!.endIndex
val targetRegister = instruction<OneRegisterInstruction>(targetIndex).registerA
addInstructions(
endIndex + 1, """
targetIndex + 1, """
invoke-static {}, $MUSIC_MISC_PATH/OpusCodecPatch;->enableOpusCodec()Z
move-result v7
if-eqz v7, :mp4a
invoke-static {}, ${allCodecsMethod.definingClass}->${allCodecsMethod.name}()Ljava/util/Set;
move-result-object v$register
""", listOf(ExternalLabel("mp4a", instruction(endIndex + 1)))
move-result-object v$targetRegister
""", listOf(ExternalLabel("mp4a", instruction(targetIndex + 1)))
)
}
} ?: return CodecsLockFingerprint.toErrorResult()

View File

@ -20,9 +20,7 @@ import app.revanced.patches.shared.annotation.YouTubeMusicCompatibility
@YouTubeMusicCompatibility
@Version("0.0.1")
class ExclusiveAudioPatch : BytecodePatch(
listOf(
AudioOnlyEnablerFingerprint
)
listOf(AudioOnlyEnablerFingerprint)
) {
override fun execute(context: BytecodeContext): PatchResult {

View File

@ -11,64 +11,56 @@ import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.shared.annotation.YouTubeMusicCompatibility
import app.revanced.patches.shared.fingerprints.LithoFingerprint
import app.revanced.util.bytecode.getNarrowLiteralIndex
import app.revanced.util.integrations.Constants.MUSIC_ADS_PATH
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.builder.instruction.BuilderInstruction21c
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction
import org.jf.dexlib2.iface.instruction.formats.Instruction31i
import org.jf.dexlib2.iface.reference.FieldReference
import org.jf.dexlib2.iface.reference.MethodReference
@YouTubeMusicCompatibility
@Version("0.0.1")
class MusicLithoFilterPatch : BytecodePatch(
listOf(
LithoFingerprint
)
listOf(LithoFingerprint)
) {
override fun execute(context: BytecodeContext): PatchResult {
LithoFingerprint.result?.let { result ->
val endIndex = result.scanResult.patternScanResult!!.endIndex
val method = result.mutableMethod
LithoFingerprint.result?.let {
it.mutableMethod.apply {
val targetInstruction = implementation!!.instructions
with (method.implementation!!.instructions) {
val bufferIndex = indexOfFirst {
it.opcode == Opcode.CONST &&
(it as Instruction31i).narrowLiteral == 168777401
}
val bufferRegister = (method.instruction(bufferIndex) as Instruction31i).registerA
val targetIndex = indexOfFirst {
it.opcode == Opcode.CONST_STRING &&
(it as BuilderInstruction21c).reference.toString() == "Element missing type extension"
val endIndex = it.scanResult.patternScanResult!!.endIndex
val bufferIndex = getNarrowLiteralIndex(168777401)
val bufferRegister = instruction<OneRegisterInstruction>(bufferIndex).registerA
val targetIndex = targetInstruction.indexOfFirst { instruction ->
instruction.opcode == Opcode.CONST_STRING &&
(instruction as BuilderInstruction21c).reference.toString() == "Element missing type extension"
} + 2
val builderMethodDescriptor = (elementAt(targetIndex) as ReferenceInstruction).reference as MethodReference
val emptyComponentFieldDescriptor = (elementAt(targetIndex + 2) as ReferenceInstruction).reference as FieldReference
val builderMethodDescriptor = (instruction(targetIndex) as ReferenceInstruction).reference as MethodReference
val emptyComponentFieldDescriptor = (instruction(targetIndex + 2) as ReferenceInstruction).reference as FieldReference
val identifierRegister = instruction<OneRegisterInstruction>(endIndex).registerA
val identifierRegister = (method.instruction(endIndex) as OneRegisterInstruction).registerA
filter { instruction ->
targetInstruction.filter { instruction ->
val fieldReference = (instruction as? ReferenceInstruction)?.reference as? FieldReference
fieldReference?.let { it.type == "Ljava/lang/StringBuilder;" } == true
fieldReference?.let { reference -> reference.type == "Ljava/lang/StringBuilder;" } == true
}.forEach { instruction ->
val insertIndex = indexOf(instruction)
val stringBuilderRegister = (method.instruction(insertIndex) as TwoRegisterInstruction).registerA
val insertIndex = targetInstruction.indexOf(instruction)
val stringBuilderRegister = instruction<TwoRegisterInstruction>(insertIndex).registerA
method.addInstructions(
insertIndex, // right after setting the component.pathBuilder field,
"""
invoke-static {v$stringBuilderRegister, v$identifierRegister}, $MUSIC_ADS_PATH/MusicLithoFilterPatch;->filter(Ljava/lang/StringBuilder;Ljava/lang/String;)Z
move-result v$bufferRegister
if-eqz v$bufferRegister, :not_an_ad
move-object/from16 v$identifierRegister, p1
invoke-static {v$identifierRegister}, $builderMethodDescriptor
move-result-object v0
iget-object v0, v0, $emptyComponentFieldDescriptor
return-object v0
""", listOf(ExternalLabel("not_an_ad", method.instruction(insertIndex)))
addInstructions(
insertIndex, """
invoke-static {v$stringBuilderRegister, v$identifierRegister}, $MUSIC_ADS_PATH/MusicLithoFilterPatch;->filter(Ljava/lang/StringBuilder;Ljava/lang/String;)Z
move-result v$bufferRegister
if-eqz v$bufferRegister, :not_an_ad
move-object/from16 v$identifierRegister, p1
invoke-static {v$identifierRegister}, $builderMethodDescriptor
move-result-object v0
iget-object v0, v0, $emptyComponentFieldDescriptor
return-object v0
""", listOf(ExternalLabel("not_an_ad", instruction(insertIndex)))
)
}
}

View File

@ -19,9 +19,7 @@ import app.revanced.patches.shared.annotation.YouTubeMusicCompatibility
@YouTubeMusicCompatibility
@Version("0.0.1")
class MinimizedPlaybackPatch : BytecodePatch(
listOf(
MinimizedPlaybackManagerFingerprint
)
listOf(MinimizedPlaybackManagerFingerprint)
) {
override fun execute(context: BytecodeContext): PatchResult {

View File

@ -0,0 +1,22 @@
package app.revanced.patches.music.misc.premium.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.music.misc.resourceid.patch.SharedResourceIdPatch.Companion.privacyTosFooterId
import app.revanced.util.bytecode.isWideLiteralExists
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
object AccountMenuFooterFingerprint : MethodFingerprint(
returnType = "L",
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
opcodes = listOf(
Opcode.CONST,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CHECK_CAST,
Opcode.INVOKE_VIRTUAL,
Opcode.IGET_OBJECT
),
customFingerprint = { it.isWideLiteralExists(privacyTosFooterId) }
)

View File

@ -1,6 +1,5 @@
package app.revanced.patches.music.misc.premium.patch
import app.revanced.extensions.findMutableMethodOf
import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
@ -8,48 +7,43 @@ import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.data.toMethodWalker
import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.extensions.instruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patches.music.misc.premium.fingerprints.AccountMenuFooterFingerprint
import app.revanced.patches.music.misc.premium.fingerprints.HideGetPremiumFingerprint
import app.revanced.patches.music.misc.resourceid.patch.SharedResourceIdPatch
import app.revanced.patches.music.misc.resourceid.patch.SharedResourceIdPatch.Companion.privacyTosFooterId
import app.revanced.patches.shared.annotation.YouTubeMusicCompatibility
import app.revanced.patches.shared.patch.mapping.ResourceMappingPatch
import app.revanced.util.bytecode.getWideLiteralIndex
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction
import org.jf.dexlib2.iface.instruction.formats.Instruction31i
import org.jf.dexlib2.iface.reference.FieldReference
import org.jf.dexlib2.iface.reference.Reference
@Patch
@Name("hide-get-premium")
@Description("Removes all \"Get Premium\" evidences from the avatar menu.")
@DependsOn([ResourceMappingPatch::class])
@DependsOn([SharedResourceIdPatch::class])
@YouTubeMusicCompatibility
@Version("0.0.1")
class HideGetPremiumPatch : BytecodePatch(
listOf(
AccountMenuFooterFingerprint,
HideGetPremiumFingerprint
)
) {
// list of resource names to get the id of
private val resourceIds = arrayOf(
"id" to "privacy_tos_footer"
).map { (type, name) ->
ResourceMappingPatch
.resourceMappings
.single { it.type == type && it.name == name }.id
}
override fun execute(context: BytecodeContext): PatchResult {
HideGetPremiumFingerprint.result?.let {
with (it.mutableMethod) {
it.mutableMethod.apply {
val insertIndex = it.scanResult.patternScanResult!!.startIndex
val register = (implementation!!.instructions[insertIndex] as TwoRegisterInstruction).registerA
val register = instruction<TwoRegisterInstruction>(insertIndex).registerA
addInstruction(
insertIndex + 1,
@ -58,54 +52,40 @@ class HideGetPremiumPatch : BytecodePatch(
}
} ?: return HideGetPremiumFingerprint.toErrorResult()
context.classes.forEach { classDef ->
classDef.methods.forEach { method ->
with(method.implementation) {
this?.instructions?.forEachIndexed { index, instruction ->
when (instruction.opcode) {
Opcode.CONST -> {
when ((instruction as Instruction31i).wideLiteral) {
resourceIds[0] -> {
val viewIndex = index + 5
val viewInstruction = instructions.elementAt(viewIndex)
if (viewInstruction.opcode != Opcode.IGET_OBJECT) return@forEachIndexed
val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method)
AccountMenuFooterFingerprint.result?.let {
it.mutableMethod.apply {
val targetIndex = getWideLiteralIndex(privacyTosFooterId) + 4
targetReference = instruction<ReferenceInstruction>(targetIndex + 1).reference
val viewReference = (viewInstruction as? ReferenceInstruction)?.reference as? FieldReference
with (context
.toMethodWalker(this)
.nextMethod(targetIndex, true)
.getMethod() as MutableMethod
) {
this.implementation!!.instructions.apply {
for ((index, instruction) in withIndex()) {
if (instruction.opcode != Opcode.IGET_OBJECT) continue
with (context
.toMethodWalker(mutableMethod)
.nextMethod(viewIndex - 1, true)
.getMethod() as MutableMethod
) {
val viewInstructions = implementation!!.instructions
if (instruction<ReferenceInstruction>(index).reference == targetReference) {
val targetRegister = instruction<OneRegisterInstruction>(index + 2).registerA
for ((targetIndex, targetInstruction) in viewInstructions.withIndex()) {
if (targetInstruction.opcode != Opcode.IGET_OBJECT) continue
addInstruction(
index,
"const/16 v$targetRegister, 0x8"
)
val indexReference = (targetInstruction as ReferenceInstruction).reference as FieldReference
if (indexReference == viewReference) {
val targetRegister = (viewInstructions.elementAt(targetIndex + 2) as OneRegisterInstruction).registerA
addInstruction(
targetIndex,
"const/16 v$targetRegister, 0x8"
)
break
}
}
}
}
}
break
}
else -> return@forEachIndexed
}
}
}
}
}
} ?: return AccountMenuFooterFingerprint.toErrorResult()
return PatchResultSuccess()
}
private companion object{
lateinit var targetReference: Reference
}
}

View File

@ -1,17 +1,11 @@
package app.revanced.patches.music.misc.quality.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.music.misc.resourceid.patch.SharedResourceIdPatch
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
import app.revanced.patches.music.misc.resourceid.patch.SharedResourceIdPatch.Companion.qualityAutoId
import app.revanced.util.bytecode.isWideLiteralExists
object MusicVideoQualitySetterParentFingerprint : MethodFingerprint(
returnType = "V",
parameters = listOf("L"),
customFingerprint = { methodDef ->
methodDef.implementation?.instructions?.any {
it.opcode.ordinal == Opcode.CONST.ordinal &&
(it as? WideLiteralInstruction)?.wideLiteral == SharedResourceIdPatch.qualityAutoLabelId
} == true
}
customFingerprint = { it.isWideLiteralExists(qualityAutoId)}
)

View File

@ -1,17 +1,11 @@
package app.revanced.patches.music.misc.quality.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.music.misc.resourceid.patch.SharedResourceIdPatch
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
import app.revanced.patches.music.misc.resourceid.patch.SharedResourceIdPatch.Companion.qualityTitleId
import app.revanced.util.bytecode.isWideLiteralExists
object MusicVideoQualitySettingsParentFingerprint : MethodFingerprint(
returnType = "L",
parameters = listOf(),
customFingerprint = { methodDef ->
methodDef.implementation?.instructions?.any {
it.opcode.ordinal == Opcode.CONST.ordinal &&
(it as? WideLiteralInstruction)?.wideLiteral == SharedResourceIdPatch.qualityTitleLabelId
} == true
}
customFingerprint = { it.isWideLiteralExists(qualityTitleId)}
)

View File

@ -25,6 +25,7 @@ import app.revanced.util.integrations.Constants.MUSIC_MISC_PATH
import org.jf.dexlib2.builder.instruction.BuilderInstruction21c
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.reference.FieldReference
import org.jf.dexlib2.iface.reference.Reference
@Patch
@Name("remember-video-quality")
@ -48,46 +49,48 @@ class VideoQualityPatch : BytecodePatch(
override fun execute(context: BytecodeContext): PatchResult {
MusicVideoQualitySetterParentFingerprint.result?.let { parentResult ->
MusicVideoQualitySetterFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.let { result ->
val endIndex = result.scanResult.patternScanResult!!.endIndex
val instructions = result.method.implementation!!.instructions
MusicVideoQualitySetterFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.let {
it.mutableMethod.apply {
val endIndex = it.scanResult.patternScanResult!!.endIndex
qualityFieldReference =
(instructions.elementAt(endIndex) as ReferenceInstruction).reference as FieldReference
qualityReference = instruction<ReferenceInstruction>(endIndex).reference
qualityFieldReference = qualityReference as FieldReference
qIndexMethodName =
context.classes.single { it.type == qualityFieldReference.type }.methods.single { it.parameterTypes.first() == "I" }.name
qIndexMethodName = context
.classes.single { classDef -> classDef.type == qualityFieldReference.type }
.methods.single { method -> method.parameterTypes.first() == "I" }.name
}
} ?: return MusicVideoQualitySetterFingerprint.toErrorResult()
} ?: return MusicVideoQualitySetterParentFingerprint.toErrorResult()
MusicVideoQualitySettingsParentFingerprint.result?.let { parentResult ->
MusicVideoQualitySettingsFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.let {
it.mutableMethod.addInstructions(
0, """
const-string v0, "$qIndexMethodName"
sput-object v0, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->qIndexMethod:Ljava/lang/String;
iget-object v0, p0, ${it.classDef.type}->${qualityFieldReference.name}:${qualityFieldReference.type}
invoke-static {p1, p2, v0}, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->setVideoQuality([Ljava/lang/Object;ILjava/lang/Object;)I
move-result p2
"""
)
} ?: return MusicVideoQualitySettingsFingerprint.toErrorResult()
MusicVideoQualitySettingsFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.mutableMethod?.addInstructions(
0, """
const-string v0, "$qIndexMethodName"
sput-object v0, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->qIndexMethod:Ljava/lang/String;
iget-object v0, p0, $qualityReference
invoke-static {p1, p2, v0}, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->setVideoQuality([Ljava/lang/Object;ILjava/lang/Object;)I
move-result p2
"""
) ?: return MusicVideoQualitySettingsFingerprint.toErrorResult()
} ?: return MusicVideoQualitySettingsParentFingerprint.toErrorResult()
UserQualityChangeFingerprint.result?.let {
val endIndex = it.scanResult.patternScanResult!!.endIndex
val qualityChangedClass =
context.findClass((it.mutableMethod.instruction(endIndex) as BuilderInstruction21c)
.reference.toString())!!
.mutableClass
it.mutableMethod.apply {
val endIndex = it.scanResult.patternScanResult!!.endIndex
val qualityChangedClass =
context.findClass((instruction<BuilderInstruction21c>(endIndex))
.reference.toString())!!
.mutableClass
for (method in qualityChangedClass.methods) {
with (qualityChangedClass.findMutableMethodOf(method)) {
if (this.name == "onItemClick") {
addInstruction(
0,
"invoke-static {p3}, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->userChangedQuality(I)V"
)
for (method in qualityChangedClass.methods) {
with (qualityChangedClass.findMutableMethodOf(method)) {
if (this.name == "onItemClick") {
addInstruction(
0,
"invoke-static {p3}, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->userChangedQuality(I)V"
)
}
}
}
}
@ -104,6 +107,6 @@ class VideoQualityPatch : BytecodePatch(
private lateinit var qIndexMethodName: String
private lateinit var qualityFieldReference: FieldReference
private lateinit var qualityReference: Reference
}
}

View File

@ -18,13 +18,15 @@ import app.revanced.util.enum.ResourceType.*
@Version("0.0.1")
class SharedResourceIdPatch : ResourcePatch {
internal companion object {
var colorGreyLabelId: Long = -1
var dialogSolidLabelId: Long = -1
var disabledIconLabelId: Long = -1
var isTabletLabelId: Long = -1
var notifierShelfLabelId: Long = -1
var qualityAutoLabelId: Long = -1
var qualityTitleLabelId: Long = -1
var chipCloudId: Long = -1
var colorGreyId: Long = -1
var dialogSolidId: Long = -1
var disabledIconId: Long = -1
var isTabletId: Long = -1
var notifierShelfId: Long = -1
var privacyTosFooterId: Long = -1
var qualityAutoId: Long = -1
var qualityTitleId: Long = -1
}
override fun execute(context: ResourceContext): PatchResult {
@ -33,13 +35,15 @@ class SharedResourceIdPatch : ResourcePatch {
.resourceMappings
.single { it.type == type.value && it.name == name }.id
colorGreyLabelId = find(COLOR, "ytm_color_grey_12")
dialogSolidLabelId = find(STYLE, "Theme.YouTubeMusic.Dialog.Solid")
disabledIconLabelId = find(DIMEN, "disabled_icon_alpha")
isTabletLabelId = find(BOOL, "is_tablet")
notifierShelfLabelId = find(LAYOUT, "music_notifier_shelf")
qualityAutoLabelId = find(STRING, "quality_auto")
qualityTitleLabelId = find(STRING, "quality_title")
chipCloudId = find(LAYOUT, "chip_cloud")
colorGreyId = find(COLOR, "ytm_color_grey_12")
dialogSolidId = find(STYLE, "Theme.YouTubeMusic.Dialog.Solid")
disabledIconId = find(DIMEN, "disabled_icon_alpha")
isTabletId = find(BOOL, "is_tablet")
notifierShelfId = find(LAYOUT, "music_notifier_shelf")
privacyTosFooterId = find(ID, "privacy_tos_footer")
qualityAutoId = find(STRING, "quality_auto")
qualityTitleId = find(STRING, "quality_title")
return PatchResultSuccess()
}

View File

@ -30,9 +30,10 @@ class MusicSettingsBytecodePatch : BytecodePatch(
override fun execute(context: BytecodeContext): PatchResult {
SettingsHeadersFragmentFingerprint.result?.let {
with(it.mutableMethod) {
it.mutableMethod.apply {
val targetIndex = it.scanResult.patternScanResult!!.endIndex
val targetRegister = (instruction(targetIndex) as OneRegisterInstruction).registerA
val targetRegister = instruction<OneRegisterInstruction>(targetIndex).registerA
addInstruction(
targetIndex + 1,
"invoke-static {v$targetRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->setActivity(Ljava/lang/Object;)V"
@ -41,10 +42,11 @@ class MusicSettingsBytecodePatch : BytecodePatch(
} ?: return SettingsHeadersFragmentFingerprint.toErrorResult()
PreferenceFingerprint.result?.let {
with(it.mutableMethod) {
it.mutableMethod.apply {
val targetIndex = it.scanResult.patternScanResult!!.endIndex
val keyRegister = (instruction(targetIndex) as FiveRegisterInstruction).registerD
val valueRegister = (instruction(targetIndex) as FiveRegisterInstruction).registerE
val keyRegister = instruction<FiveRegisterInstruction>(targetIndex).registerD
val valueRegister = instruction<FiveRegisterInstruction>(targetIndex).registerE
addInstruction(
targetIndex,
"invoke-static {v$keyRegister, v$valueRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->onPreferenceChanged(Ljava/lang/String;Z)V"

View File

@ -44,7 +44,6 @@ class MusicSettingsPatch : AbstractSettingsResourcePatch(
/**
* Copy colors
*/
context.xmlEditor["res/values/colors.xml"].use { editor ->
val resourcesNode = editor.file.getElementsByTagName("resources").item(0) as Element

View File

@ -45,7 +45,7 @@ class ShareButtonHookPatch : BytecodePatch(
) {
override fun execute(context: BytecodeContext): PatchResult {
SharePanelFingerprint.result?.let {
with (it.mutableMethod) {
it.mutableMethod.apply {
val targetIndex = it.scanResult.patternScanResult!!.startIndex
addInstructions(

View File

@ -2,8 +2,8 @@ package app.revanced.patches.music.misc.shuffle.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.music.misc.resourceid.patch.SharedResourceIdPatch
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
import app.revanced.patches.music.misc.resourceid.patch.SharedResourceIdPatch.Companion.disabledIconId
import app.revanced.util.bytecode.isWideLiteralExists
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@ -18,12 +18,6 @@ object ShuffleClassFingerprint : MethodFingerprint(
Opcode.INVOKE_VIRTUAL,
Opcode.RETURN_VOID
),
customFingerprint = { methodDef ->
methodDef.name == "<init>" &&
methodDef.implementation?.instructions?.any {
it.opcode.ordinal == Opcode.CONST.ordinal &&
(it as? WideLiteralInstruction)?.wideLiteral == SharedResourceIdPatch.disabledIconLabelId
} == true
}
customFingerprint = { it.name == "<init>" && it.isWideLiteralExists(disabledIconId) }
)

View File

@ -6,7 +6,10 @@ import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.*
import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.instruction
import app.revanced.patcher.extensions.or
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
@ -23,9 +26,10 @@ import app.revanced.patches.shared.annotation.YouTubeMusicCompatibility
import app.revanced.util.enum.CategoryType
import app.revanced.util.integrations.Constants.MUSIC_MISC_PATH
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.dexbacked.reference.DexBackedMethodReference
import org.jf.dexlib2.iface.instruction.Instruction
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.reference.FieldReference
import org.jf.dexlib2.iface.reference.Reference
import org.jf.dexlib2.immutable.ImmutableField
import org.jf.dexlib2.immutable.ImmutableMethod
import org.jf.dexlib2.immutable.ImmutableMethodImplementation
@ -51,31 +55,31 @@ class EnforceShufflePatch : BytecodePatch(
) {
override fun execute(context: BytecodeContext): PatchResult {
ShuffleClassReferenceFingerprint.result?.let { result ->
val startIndex = result.scanResult.patternScanResult!!.startIndex
val endIndex = result.scanResult.patternScanResult!!.endIndex
SHUFFLE_CLASS = result.classDef.type
with (result.mutableMethod.implementation!!.instructions) {
firstRef = (elementAt(startIndex) as ReferenceInstruction).reference as FieldReference
secondRef = (elementAt(startIndex + 1) as ReferenceInstruction).reference as DexBackedMethodReference
thirdRef = (elementAt(endIndex) as ReferenceInstruction).reference as FieldReference
this.filter { instruction ->
val fieldReference = (instruction as? ReferenceInstruction)?.reference as? FieldReference
fieldReference?.let { it.type == "Landroid/widget/ImageView;" } == true
}.forEach { instruction ->
fourthRef = (instruction as ReferenceInstruction).reference as FieldReference
ShuffleClassReferenceFingerprint.result?.let {
it.mutableMethod.apply {
val startIndex = it.scanResult.patternScanResult!!.startIndex
val endIndex = it.scanResult.patternScanResult!!.endIndex
val imageViewIndex = implementation!!.instructions.indexOfFirst { instruction ->
((instruction as? ReferenceInstruction)?.reference as? FieldReference)?.type == "Landroid/widget/ImageView;"
}
SHUFFLE_CLASS = it.classDef.type
shuffleReference1 = instruction(startIndex).descriptor
shuffleReference2 = instruction(startIndex + 1).descriptor
shuffleReference3 = instruction(endIndex).descriptor
shuffleReference4 = instruction(imageViewIndex).descriptor
}
} ?: return ShuffleClassReferenceFingerprint.toErrorResult()
ShuffleClassFingerprint.result?.let {
it.mutableMethod.addInstruction(
it.scanResult.patternScanResult!!.endIndex,
"sput-object p0, $MUSIC_PLAYBACK_CONTROLS_CLASS_DESCRIPTOR->shuffleclass:$SHUFFLE_CLASS"
)
it.mutableMethod.apply {
addInstruction(
it.scanResult.patternScanResult!!.endIndex,
"sput-object p0, $MUSIC_PLAYBACK_CONTROLS_CLASS_DESCRIPTOR->shuffleclass:$SHUFFLE_CLASS"
)
}
context.traverseClassHierarchy(it.mutableClass) {
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL
@ -93,68 +97,70 @@ class EnforceShufflePatch : BytecodePatch(
}
} ?: return ShuffleClassFingerprint.toErrorResult()
MusicPlaybackControlsFingerprint.result?.let {
with (it.mutableMethod.implementation!!.instructions) {
fifthRef = (elementAt(0) as ReferenceInstruction).reference as FieldReference
sixthRef = (elementAt(1) as ReferenceInstruction).reference as DexBackedMethodReference
it.mutableMethod.apply {
shuffleReference5 = instruction(0).descriptor
shuffleReference6 = instruction(1).descriptor
addInstructions(
0, """
invoke-virtual {v0, v1}, $MUSIC_PLAYBACK_CONTROLS_CLASS_DESCRIPTOR->buttonHook(Z)V
return-void
"""
)
}
it.mutableClass.staticFields.add(
ImmutableField(
it.mutableMethod.definingClass,
"shuffleclass",
SHUFFLE_CLASS,
AccessFlags.PUBLIC or AccessFlags.STATIC,
null,
null,
null
).toMutable()
)
it.mutableClass.apply {
staticFields.add(
ImmutableField(
it.mutableMethod.definingClass,
"shuffleclass",
SHUFFLE_CLASS,
AccessFlags.PUBLIC or AccessFlags.STATIC,
null,
null,
null
).toMutable()
)
it.mutableMethod.addInstructions(
0,
"""
invoke-virtual {v0, v1}, $MUSIC_PLAYBACK_CONTROLS_CLASS_DESCRIPTOR->buttonHook(Z)V
return-void
"""
)
val shuffleFieldReference = shuffleReference3 as FieldReference
it.mutableClass.methods.add(
ImmutableMethod(
it.classDef.type,
"buttonHook",
listOf(ImmutableMethodParameter("Z", null, null)),
"V",
AccessFlags.PUBLIC or AccessFlags.FINAL,
null,
null,
ImmutableMethodImplementation(
5, """
methods.add(
ImmutableMethod(
it.classDef.type,
"buttonHook",
listOf(ImmutableMethodParameter("Z", null, null)),
"V",
AccessFlags.PUBLIC or AccessFlags.FINAL,
null,
null,
ImmutableMethodImplementation(
5, """
invoke-static {}, $MUSIC_MISC_PATH/ForceShufflePatch;->enableForceShuffle()Z
move-result v0
if-eqz v0, :cond_0
new-instance v0, $SHUFFLE_CLASS
sget-object v0, $MUSIC_PLAYBACK_CONTROLS_CLASS_DESCRIPTOR->shuffleclass:$SHUFFLE_CLASS
iget-object v1, v0, $SHUFFLE_CLASS->${firstRef.name}:${firstRef.type}
invoke-interface {v1}, $secondRef
iget-object v1, v0, $shuffleReference1
invoke-interface {v1}, $shuffleReference2
move-result-object v1
check-cast v1, ${thirdRef.definingClass}
iget-object v1, v1, ${thirdRef.definingClass}->${thirdRef.name}:${thirdRef.type}
invoke-virtual {v1}, ${thirdRef.type}->ordinal()I
check-cast v1, ${shuffleFieldReference.definingClass}
iget-object v1, v1, $shuffleReference3
invoke-virtual {v1}, ${shuffleFieldReference.type}->ordinal()I
move-result v1
iget-object v2, v0, $SHUFFLE_CLASS->${fourthRef.name}:Landroid/widget/ImageView;
iget-object v2, v0, $shuffleReference4
invoke-virtual {v2}, Landroid/widget/ImageView;->performClick()Z
if-eqz v1, :cond_0
invoke-virtual {v2}, Landroid/widget/ImageView;->performClick()Z
:cond_0
iput-boolean v4, v3, $MUSIC_PLAYBACK_CONTROLS_CLASS_DESCRIPTOR->${fifthRef.name}:${fifthRef.type}
invoke-virtual {v3}, $sixthRef
iput-boolean v4, v3, $shuffleReference5
invoke-virtual {v3}, $shuffleReference6
return-void
""".toInstructions(), null, null
)
).toMutable()
)
)
).toMutable()
)
}
} ?: return MusicPlaybackControlsFingerprint.toErrorResult()
MusicSettingsPatch.addMusicPreference(CategoryType.MISC, "revanced_enable_force_shuffle", "true")
@ -162,18 +168,19 @@ class EnforceShufflePatch : BytecodePatch(
return PatchResultSuccess()
}
companion object {
private companion object {
const val MUSIC_PLAYBACK_CONTROLS_CLASS_DESCRIPTOR =
"Lcom/google/android/apps/youtube/music/watchpage/MusicPlaybackControls;"
private lateinit var SHUFFLE_CLASS: String
lateinit var SHUFFLE_CLASS: String
lateinit var shuffleReference1: Reference
lateinit var shuffleReference2: Reference
lateinit var shuffleReference3: Reference
lateinit var shuffleReference4: Reference
lateinit var shuffleReference5: Reference
lateinit var shuffleReference6: Reference
private lateinit var firstRef: FieldReference
private lateinit var secondRef: DexBackedMethodReference
private lateinit var thirdRef: FieldReference
private lateinit var fourthRef: FieldReference
private lateinit var fifthRef: FieldReference
private lateinit var sixthRef: DexBackedMethodReference
val Instruction.descriptor
get() = (this as ReferenceInstruction).reference
}
}

View File

@ -6,13 +6,14 @@ import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.instruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.music.misc.tastebuilder.fingerprints.TasteBuilderConstructorFingerprint
import app.revanced.patches.shared.annotation.YouTubeMusicCompatibility
import org.jf.dexlib2.iface.instruction.formats.Instruction22c
import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction
@Patch
@Name("hide-taste-builder")
@ -20,15 +21,13 @@ import org.jf.dexlib2.iface.instruction.formats.Instruction22c
@YouTubeMusicCompatibility
@Version("0.0.1")
class RemoveTasteBuilderPatch : BytecodePatch(
listOf(
TasteBuilderConstructorFingerprint
)
listOf(TasteBuilderConstructorFingerprint)
) {
override fun execute(context: BytecodeContext): PatchResult {
TasteBuilderConstructorFingerprint.result?.let {
with (it.mutableMethod) {
it.mutableMethod.apply {
val insertIndex = it.scanResult.patternScanResult!!.endIndex - 8
val register = (implementation!!.instructions[insertIndex] as Instruction22c).registerA
val register = instruction<TwoRegisterInstruction>(insertIndex).registerA
addInstructions(
insertIndex, """

View File

@ -2,8 +2,8 @@ package app.revanced.patches.music.misc.upgradebutton.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.music.misc.resourceid.patch.SharedResourceIdPatch
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
import app.revanced.patches.music.misc.resourceid.patch.SharedResourceIdPatch.Companion.notifierShelfId
import app.revanced.util.bytecode.isWideLiteralExists
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@ -16,11 +16,6 @@ object NotifierShelfFingerprint : MethodFingerprint(
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT
),
customFingerprint = { methodDef ->
methodDef.implementation?.instructions?.any {
it.opcode.ordinal == Opcode.CONST.ordinal &&
(it as? WideLiteralInstruction)?.wideLiteral == SharedResourceIdPatch.notifierShelfLabelId
} == true
}
customFingerprint = { it.isWideLiteralExists(notifierShelfId)}
)

View File

@ -2,9 +2,9 @@ package app.revanced.patches.music.misc.upgradebutton.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.util.bytecode.isNarrowLiteralExists
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.instruction.NarrowLiteralInstruction
object PivotBarConstructorFingerprint : MethodFingerprint(
returnType = "V",
@ -13,10 +13,5 @@ object PivotBarConstructorFingerprint : MethodFingerprint(
Opcode.IPUT_OBJECT,
Opcode.RETURN_VOID
),
customFingerprint = { methodDef ->
methodDef.name == "<init>"
&& methodDef.implementation!!.instructions.any {
((it as? NarrowLiteralInstruction)?.narrowLiteral == 117501096)
}
}
customFingerprint = { it.name == "<init>" && it.isNarrowLiteralExists(117501096) }
)

View File

@ -22,7 +22,6 @@ import app.revanced.util.integrations.Constants.INTEGRATIONS_PATH
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction
import org.jf.dexlib2.iface.reference.FieldReference
@Patch
@Name("hide-upgrade-button")
@ -43,20 +42,12 @@ class RemoveUpgradeButtonPatch : BytecodePatch(
) {
override fun execute(context: BytecodeContext): PatchResult {
PivotBarConstructorFingerprint.result?.let {
with (it.mutableMethod) {
it.mutableMethod.apply {
val targetIndex = it.scanResult.patternScanResult!!.startIndex
val targetRegisterA = instruction<TwoRegisterInstruction>(targetIndex).registerA
val targetRegisterB = instruction<TwoRegisterInstruction>(targetIndex).registerB
val targetRegisterA = (instruction(targetIndex) as TwoRegisterInstruction).registerA
val targetRegisterB = (instruction(targetIndex) as TwoRegisterInstruction).registerB
val replaceReference =
(instruction(targetIndex) as ReferenceInstruction).reference as FieldReference
val replaceReferenceToCall = replaceReference.definingClass +
"->" +
replaceReference.name +
":" +
replaceReference.type
val replaceReference = instruction<ReferenceInstruction>(targetIndex).reference.toString()
replaceInstruction(
targetIndex,
@ -69,16 +60,16 @@ class RemoveUpgradeButtonPatch : BytecodePatch(
if-le v1, v2, :dismiss
invoke-interface {v$targetRegisterA, v2}, Ljava/util/List;->remove(I)Ljava/lang/Object;
:dismiss
iput-object v$targetRegisterA, v$targetRegisterB, $replaceReferenceToCall
iput-object v$targetRegisterA, v$targetRegisterB, $replaceReference
"""
)
}
} ?: return PivotBarConstructorFingerprint.toErrorResult()
NotifierShelfFingerprint.result?.let {
with (it.mutableMethod) {
it.mutableMethod.apply {
val targetIndex = it.scanResult.patternScanResult!!.endIndex
val targetRegister = (instruction(targetIndex) as OneRegisterInstruction).registerA
val targetRegister = instruction<OneRegisterInstruction>(targetIndex).registerA
addInstruction(
targetIndex + 1,
"invoke-static {v$targetRegister}, $INTEGRATIONS_PATH/adremover/AdRemoverAPI;->HideViewWithLayout1dp(Landroid/view/View;)V"

View File

@ -20,18 +20,15 @@ import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
@YouTubeMusicCompatibility
@Version("0.0.1")
class MusicVideoIdPatch : BytecodePatch(
listOf(
MusicVideoIdFingerprint
)
listOf(MusicVideoIdFingerprint)
) {
override fun execute(context: BytecodeContext): PatchResult {
MusicVideoIdFingerprint.result?.let {
insertIndex = it.scanResult.patternScanResult!!.endIndex
with (it.mutableMethod) {
it.mutableMethod.apply {
insertIndex = it.scanResult.patternScanResult!!.endIndex
insertMethod = this
videoIdRegister = (implementation!!.instructions[insertIndex] as OneRegisterInstruction).registerA
videoIdRegister = instruction<OneRegisterInstruction>(insertIndex).registerA
}
offset++ // offset so setVideoId is called before any injected call
} ?: return MusicVideoIdFingerprint.toErrorResult()

View File

@ -5,7 +5,7 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
object MiniplayerColorParentFingerprint : MethodFingerprint(
object ColorMatchPlayerParentFingerprint : MethodFingerprint(
returnType = "V",
access = AccessFlags.PRIVATE or AccessFlags.FINAL,
opcodes = listOf(

View File

@ -4,7 +4,5 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
object LayoutConstructorFingerprint : MethodFingerprint(
strings = listOf("1.0x"),
customFingerprint = {
it.definingClass.endsWith("YouTubeControlsOverlay;")
}
customFingerprint = { it.definingClass.endsWith("YouTubeControlsOverlay;") }
)

View File

@ -2,8 +2,8 @@ package app.revanced.patches.shared.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourceIdPatch
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourceIdPatch.Companion.imageOnlyTabId
import app.revanced.util.bytecode.isWideLiteralExists
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@ -14,10 +14,5 @@ object PivotBarCreateButtonViewFingerprint : MethodFingerprint(
Opcode.MOVE_OBJECT,
Opcode.INVOKE_DIRECT_RANGE, // unique instruction anchor
),
customFingerprint = { methodDef ->
methodDef.implementation?.instructions?.any {
it.opcode.ordinal == Opcode.CONST.ordinal &&
(it as? WideLiteralInstruction)?.wideLiteral == SharedResourceIdPatch.imageOnlyTabId
} == true
}
customFingerprint = { it.isWideLiteralExists(imageOnlyTabId) }
)

View File

@ -0,0 +1,30 @@
package app.revanced.util.bytecode
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.Method
import org.jf.dexlib2.iface.instruction.NarrowLiteralInstruction
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
fun Method.getNarrowLiteralIndex(value: Int): Int {
return implementation?.let {
it.instructions.indexOfFirst { instruction ->
instruction.opcode == Opcode.CONST && (instruction as NarrowLiteralInstruction).narrowLiteral == value
}
} ?: -1
}
fun Method.isNarrowLiteralExists(value: Int): Boolean {
return getNarrowLiteralIndex(value) != -1
}
fun Method.getWideLiteralIndex(value: Long): Int {
return implementation?.let {
it.instructions.indexOfFirst { instruction ->
instruction.opcode == Opcode.CONST && (instruction as WideLiteralInstruction).wideLiteral == value
}
} ?: -1
}
fun Method.isWideLiteralExists(value: Long): Boolean {
return getWideLiteralIndex(value) != -1
}