mirror of
https://github.com/inotia00/revanced-patches.git
synced 2025-05-28 12:50:19 +02:00
build(revanced-patcher): bump version
This commit is contained in:
parent
8958c3870f
commit
0f5350e691
@ -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")
|
||||
|
@ -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")
|
||||
|
@ -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) }
|
||||
)
|
||||
|
||||
|
@ -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
|
||||
"""
|
||||
|
@ -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 {
|
||||
|
||||
|
@ -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) }
|
||||
)
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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"),
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
@ -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) }
|
||||
)
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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) }
|
||||
)
|
||||
|
||||
|
@ -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 {
|
||||
|
||||
|
@ -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) }
|
||||
)
|
||||
|
||||
|
@ -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")
|
||||
|
@ -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 {
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
@ -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")
|
||||
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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 {
|
||||
|
||||
|
@ -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)))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
||||
|
@ -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) }
|
||||
)
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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)}
|
||||
)
|
@ -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)}
|
||||
)
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
||||
|
@ -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(
|
||||
|
@ -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) }
|
||||
)
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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, """
|
||||
|
@ -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)}
|
||||
)
|
||||
|
||||
|
@ -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) }
|
||||
)
|
@ -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"
|
||||
|
@ -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()
|
||||
|
@ -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(
|
@ -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;") }
|
||||
)
|
@ -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) }
|
||||
)
|
30
src/main/kotlin/app/revanced/util/bytecode/BytecodeUtils.kt
Normal file
30
src/main/kotlin/app/revanced/util/bytecode/BytecodeUtils.kt
Normal 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
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user