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 { 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") implementation("app.revanced:multidexlib2:2.5.3-a3836654")
// Required for meta // Required for meta
implementation("com.google.code.gson:gson:2.10.1") 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.Name
import app.revanced.patcher.annotation.Version import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext 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.BytecodePatch
import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.PatchResultSuccess
@ -25,23 +25,19 @@ import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
@YouTubeMusicCompatibility @YouTubeMusicCompatibility
@Version("0.0.1") @Version("0.0.1")
class DisableAutoCaptionsPatch : BytecodePatch( class DisableAutoCaptionsPatch : BytecodePatch(
listOf( listOf(SubtitleTrackFingerprint)
SubtitleTrackFingerprint
)
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
SubtitleTrackFingerprint.result?.mutableMethod?.let { SubtitleTrackFingerprint.result?.mutableMethod?.let {
with (it.implementation!!.instructions) { val index = it.implementation!!.instructions.size - 1
val index = size - 1 val register = it.instruction<OneRegisterInstruction>(index).registerA
val register = (elementAt(index) as OneRegisterInstruction).registerA it.addInstructions(
it.addInstructions( index, """
index, """
invoke-static {v$register}, $MUSIC_LAYOUT->disableAutoCaptions(Z)Z invoke-static {v$register}, $MUSIC_LAYOUT->disableAutoCaptions(Z)Z
move-result v$register move-result v$register
""" """
) )
}
} ?: return SubtitleTrackFingerprint.toErrorResult() } ?: return SubtitleTrackFingerprint.toErrorResult()
MusicSettingsPatch.addMusicPreference(CategoryType.LAYOUT, "revanced_disable_auto_captions", "false") 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.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.music.misc.resourceid.patch.SharedResourceIdPatch import app.revanced.patches.music.misc.resourceid.patch.SharedResourceIdPatch.Companion.colorGreyId
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction import app.revanced.util.bytecode.isWideLiteralExists
import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
@ -16,11 +16,6 @@ object TabLayoutFingerprint : MethodFingerprint(
Opcode.INVOKE_STATIC, Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT Opcode.MOVE_RESULT
), ),
customFingerprint = { methodDef -> customFingerprint = { it.isWideLiteralExists(colorGreyId) }
methodDef.implementation?.instructions?.any {
it.opcode.ordinal == Opcode.CONST.ordinal &&
(it as? WideLiteralInstruction)?.wideLiteral == SharedResourceIdPatch.colorGreyLabelId
} == true
}
) )

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

View File

@ -25,9 +25,7 @@ import app.revanced.util.integrations.Constants.MUSIC_LAYOUT
@YouTubeMusicCompatibility @YouTubeMusicCompatibility
@Version("0.0.1") @Version("0.0.1")
class HideCastButtonPatch : BytecodePatch( class HideCastButtonPatch : BytecodePatch(
listOf( listOf(HideCastButtonParentFingerprint)
HideCastButtonParentFingerprint
)
) { ) {
override fun execute(context: BytecodeContext): PatchResult { 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 package app.revanced.patches.music.layout.categorybar.patch
import app.revanced.extensions.findMutableMethodOf import app.revanced.extensions.toErrorResult
import app.revanced.extensions.toResult
import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstruction import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.extensions.instruction
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult 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.DependsOn
import app.revanced.patcher.patch.annotations.Patch 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.music.misc.settings.resource.patch.MusicSettingsPatch
import app.revanced.patches.shared.annotation.YouTubeMusicCompatibility 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.enum.CategoryType
import app.revanced.util.integrations.Constants.MUSIC_LAYOUT import app.revanced.util.integrations.Constants.MUSIC_LAYOUT
import org.jf.dexlib2.Opcode import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
import org.jf.dexlib2.iface.instruction.formats.Instruction21c
import org.jf.dexlib2.iface.instruction.formats.Instruction31i
@Patch @Patch
@Name("hide-category-bar") @Name("hide-category-bar")
@Description("Hides the music category bar at the top of the homepage.") @Description("Hides the music category bar at the top of the homepage.")
@DependsOn( @DependsOn(
[ [
ResourceMappingPatch::class, SharedResourceIdPatch::class,
MusicSettingsPatch::class MusicSettingsPatch::class
] ]
) )
@YouTubeMusicCompatibility @YouTubeMusicCompatibility
@Version("0.0.1") @Version("0.0.1")
class CategoryBarPatch : BytecodePatch() { class CategoryBarPatch : BytecodePatch(
listOf(ChipCloudFingerprint)
// 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}
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
context.classes.forEach { classDef -> ChipCloudFingerprint.result?.let {
classDef.methods.forEach { method -> it.mutableMethod.apply {
with(method.implementation) { val targetIndex = it.scanResult.patternScanResult!!.endIndex
this?.instructions?.forEachIndexed { index, instruction -> val targetRegister = instruction<OneRegisterInstruction>(targetIndex).registerA
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
val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method) addInstruction(
targetIndex + 1,
val register = (invokeInstruction as Instruction21c).registerA "invoke-static { v$targetRegister }, $MUSIC_LAYOUT->hideCategoryBar(Landroid/view/View;)V"
)
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
}
}
}
} }
} } ?: return ChipCloudFingerprint.toErrorResult()
return toResult(patchSuccessArray.indexOf(false))
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.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
object MiniplayerColorFingerprint : MethodFingerprint( object ColorMatchPlayerFingerprint : MethodFingerprint(
returnType = "V", returnType = "V",
access = AccessFlags.PUBLIC or AccessFlags.FINAL, access = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("L", "J"), 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.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.music.misc.resourceid.patch.SharedResourceIdPatch import app.revanced.patches.music.misc.resourceid.patch.SharedResourceIdPatch.Companion.dialogSolidId
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction import app.revanced.util.bytecode.isWideLiteralExists
import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
@ -16,11 +16,6 @@ object DialogSolidFingerprint : MethodFingerprint(
Opcode.MOVE_RESULT_OBJECT, Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_STATIC Opcode.INVOKE_STATIC
), ),
customFingerprint = { methodDef -> customFingerprint = { it.isWideLiteralExists(dialogSolidId) }
methodDef.implementation?.instructions?.any {
it.opcode.ordinal == Opcode.CONST.ordinal &&
(it as? WideLiteralInstruction)?.wideLiteral == SharedResourceIdPatch.dialogSolidLabelId
} == true
}
) )

View File

@ -20,6 +20,7 @@ import app.revanced.patches.shared.annotation.YouTubeMusicCompatibility
import app.revanced.util.enum.CategoryType import app.revanced.util.enum.CategoryType
import app.revanced.util.integrations.Constants.MUSIC_LAYOUT import app.revanced.util.integrations.Constants.MUSIC_LAYOUT
@Patch @Patch
@Name("enable-compact-dialog") @Name("enable-compact-dialog")
@Description("Enable compact dialog on phone.") @Description("Enable compact dialog on phone.")
@ -32,9 +33,7 @@ import app.revanced.util.integrations.Constants.MUSIC_LAYOUT
@YouTubeMusicCompatibility @YouTubeMusicCompatibility
@Version("0.0.1") @Version("0.0.1")
class CompactDialogPatch : BytecodePatch( class CompactDialogPatch : BytecodePatch(
listOf( listOf(DialogSolidFingerprint)
DialogSolidFingerprint
)
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
DialogSolidFingerprint.result?.let { 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.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.util.bytecode.isNarrowLiteralExists
import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.instruction.NarrowLiteralInstruction
object FloatingButtonParentFingerprint : MethodFingerprint( object FloatingButtonParentFingerprint : MethodFingerprint(
returnType = "V", returnType = "V",
access = AccessFlags.PROTECTED or AccessFlags.FINAL, access = AccessFlags.PROTECTED or AccessFlags.FINAL,
parameters = listOf("L"), parameters = listOf("L"),
opcodes = listOf(Opcode.INVOKE_DIRECT), opcodes = listOf(Opcode.INVOKE_DIRECT),
customFingerprint = { methodDef -> customFingerprint = { it.isNarrowLiteralExists(259982244) }
methodDef.implementation!!.instructions.any {
((it as? NarrowLiteralInstruction)?.narrowLiteral == 259982244)
}
}
) )

View File

@ -33,9 +33,7 @@ import app.revanced.util.integrations.Constants.MUSIC_LAYOUT
@YouTubeMusicCompatibility @YouTubeMusicCompatibility
@Version("0.0.1") @Version("0.0.1")
class NewPlaylistButtonPatch : BytecodePatch( class NewPlaylistButtonPatch : BytecodePatch(
listOf( listOf(FloatingButtonParentFingerprint)
FloatingButtonParentFingerprint
)
) { ) {
override fun execute(context: BytecodeContext): PatchResult { 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.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.music.misc.resourceid.patch.SharedResourceIdPatch import app.revanced.patches.music.misc.resourceid.patch.SharedResourceIdPatch.Companion.isTabletId
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction import app.revanced.util.bytecode.isWideLiteralExists
import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
@ -16,11 +16,6 @@ object TabletIdentifierFingerprint : MethodFingerprint(
Opcode.INVOKE_VIRTUAL, Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT Opcode.MOVE_RESULT
), ),
customFingerprint = { methodDef -> customFingerprint = { it.isWideLiteralExists(isTabletId) }
methodDef.implementation?.instructions?.any {
it.opcode.ordinal == Opcode.CONST.ordinal &&
(it as? WideLiteralInstruction)?.wideLiteral == SharedResourceIdPatch.isTabletLabelId
} == true
}
) )

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -19,9 +19,7 @@ import app.revanced.patches.shared.annotation.YouTubeMusicCompatibility
@YouTubeMusicCompatibility @YouTubeMusicCompatibility
@Version("0.0.1") @Version("0.0.1")
class MinimizedPlaybackPatch : BytecodePatch( class MinimizedPlaybackPatch : BytecodePatch(
listOf( listOf(MinimizedPlaybackManagerFingerprint)
MinimizedPlaybackManagerFingerprint
)
) { ) {
override fun execute(context: BytecodeContext): PatchResult { 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 package app.revanced.patches.music.misc.premium.patch
import app.revanced.extensions.findMutableMethodOf
import app.revanced.extensions.toErrorResult import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name 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.BytecodeContext
import app.revanced.patcher.data.toMethodWalker import app.revanced.patcher.data.toMethodWalker
import app.revanced.patcher.extensions.addInstruction import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.extensions.instruction
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod 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.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.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.Opcode
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
import org.jf.dexlib2.iface.instruction.ReferenceInstruction import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction
import org.jf.dexlib2.iface.instruction.formats.Instruction31i import org.jf.dexlib2.iface.reference.Reference
import org.jf.dexlib2.iface.reference.FieldReference
@Patch @Patch
@Name("hide-get-premium") @Name("hide-get-premium")
@Description("Removes all \"Get Premium\" evidences from the avatar menu.") @Description("Removes all \"Get Premium\" evidences from the avatar menu.")
@DependsOn([ResourceMappingPatch::class]) @DependsOn([SharedResourceIdPatch::class])
@YouTubeMusicCompatibility @YouTubeMusicCompatibility
@Version("0.0.1") @Version("0.0.1")
class HideGetPremiumPatch : BytecodePatch( class HideGetPremiumPatch : BytecodePatch(
listOf( listOf(
AccountMenuFooterFingerprint,
HideGetPremiumFingerprint 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 { override fun execute(context: BytecodeContext): PatchResult {
HideGetPremiumFingerprint.result?.let { HideGetPremiumFingerprint.result?.let {
with (it.mutableMethod) { it.mutableMethod.apply {
val insertIndex = it.scanResult.patternScanResult!!.startIndex val insertIndex = it.scanResult.patternScanResult!!.startIndex
val register = (implementation!!.instructions[insertIndex] as TwoRegisterInstruction).registerA val register = instruction<TwoRegisterInstruction>(insertIndex).registerA
addInstruction( addInstruction(
insertIndex + 1, insertIndex + 1,
@ -58,54 +52,40 @@ class HideGetPremiumPatch : BytecodePatch(
} }
} ?: return HideGetPremiumFingerprint.toErrorResult() } ?: 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 if (instruction<ReferenceInstruction>(index).reference == targetReference) {
.toMethodWalker(mutableMethod) val targetRegister = instruction<OneRegisterInstruction>(index + 2).registerA
.nextMethod(viewIndex - 1, true)
.getMethod() as MutableMethod
) {
val viewInstructions = implementation!!.instructions
for ((targetIndex, targetInstruction) in viewInstructions.withIndex()) { addInstruction(
if (targetInstruction.opcode != Opcode.IGET_OBJECT) continue index,
"const/16 v$targetRegister, 0x8"
)
val indexReference = (targetInstruction as ReferenceInstruction).reference as FieldReference break
if (indexReference == viewReference) {
val targetRegister = (viewInstructions.elementAt(targetIndex + 2) as OneRegisterInstruction).registerA
addInstruction(
targetIndex,
"const/16 v$targetRegister, 0x8"
)
break
}
}
}
}
}
} }
else -> return@forEachIndexed
} }
} }
} }
} }
} } ?: return AccountMenuFooterFingerprint.toErrorResult()
return PatchResultSuccess() return PatchResultSuccess()
} }
private companion object{
lateinit var targetReference: Reference
}
} }

View File

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

View File

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

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.builder.instruction.BuilderInstruction21c
import org.jf.dexlib2.iface.instruction.ReferenceInstruction import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.reference.FieldReference import org.jf.dexlib2.iface.reference.FieldReference
import org.jf.dexlib2.iface.reference.Reference
@Patch @Patch
@Name("remember-video-quality") @Name("remember-video-quality")
@ -48,46 +49,48 @@ class VideoQualityPatch : BytecodePatch(
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
MusicVideoQualitySetterParentFingerprint.result?.let { parentResult -> MusicVideoQualitySetterParentFingerprint.result?.let { parentResult ->
MusicVideoQualitySetterFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.let { result -> MusicVideoQualitySetterFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.let {
val endIndex = result.scanResult.patternScanResult!!.endIndex it.mutableMethod.apply {
val instructions = result.method.implementation!!.instructions val endIndex = it.scanResult.patternScanResult!!.endIndex
qualityFieldReference = qualityReference = instruction<ReferenceInstruction>(endIndex).reference
(instructions.elementAt(endIndex) as ReferenceInstruction).reference as FieldReference qualityFieldReference = qualityReference as FieldReference
qIndexMethodName = qIndexMethodName = context
context.classes.single { it.type == qualityFieldReference.type }.methods.single { it.parameterTypes.first() == "I" }.name .classes.single { classDef -> classDef.type == qualityFieldReference.type }
.methods.single { method -> method.parameterTypes.first() == "I" }.name
}
} ?: return MusicVideoQualitySetterFingerprint.toErrorResult() } ?: return MusicVideoQualitySetterFingerprint.toErrorResult()
} ?: return MusicVideoQualitySetterParentFingerprint.toErrorResult() } ?: return MusicVideoQualitySetterParentFingerprint.toErrorResult()
MusicVideoQualitySettingsParentFingerprint.result?.let { parentResult -> MusicVideoQualitySettingsParentFingerprint.result?.let { parentResult ->
MusicVideoQualitySettingsFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.let { MusicVideoQualitySettingsFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.mutableMethod?.addInstructions(
it.mutableMethod.addInstructions( 0, """
0, """ const-string v0, "$qIndexMethodName"
const-string v0, "$qIndexMethodName" sput-object v0, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->qIndexMethod:Ljava/lang/String;
sput-object v0, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->qIndexMethod:Ljava/lang/String; iget-object v0, p0, $qualityReference
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
invoke-static {p1, p2, v0}, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->setVideoQuality([Ljava/lang/Object;ILjava/lang/Object;)I move-result p2
move-result p2 """
""" ) ?: return MusicVideoQualitySettingsFingerprint.toErrorResult()
)
} ?: return MusicVideoQualitySettingsFingerprint.toErrorResult()
} ?: return MusicVideoQualitySettingsParentFingerprint.toErrorResult() } ?: return MusicVideoQualitySettingsParentFingerprint.toErrorResult()
UserQualityChangeFingerprint.result?.let { UserQualityChangeFingerprint.result?.let {
val endIndex = it.scanResult.patternScanResult!!.endIndex it.mutableMethod.apply {
val qualityChangedClass = val endIndex = it.scanResult.patternScanResult!!.endIndex
context.findClass((it.mutableMethod.instruction(endIndex) as BuilderInstruction21c) val qualityChangedClass =
.reference.toString())!! context.findClass((instruction<BuilderInstruction21c>(endIndex))
.mutableClass .reference.toString())!!
.mutableClass
for (method in qualityChangedClass.methods) { for (method in qualityChangedClass.methods) {
with (qualityChangedClass.findMutableMethodOf(method)) { with (qualityChangedClass.findMutableMethodOf(method)) {
if (this.name == "onItemClick") { if (this.name == "onItemClick") {
addInstruction( addInstruction(
0, 0,
"invoke-static {p3}, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->userChangedQuality(I)V" "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 qIndexMethodName: String
private lateinit var qualityFieldReference: FieldReference 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") @Version("0.0.1")
class SharedResourceIdPatch : ResourcePatch { class SharedResourceIdPatch : ResourcePatch {
internal companion object { internal companion object {
var colorGreyLabelId: Long = -1 var chipCloudId: Long = -1
var dialogSolidLabelId: Long = -1 var colorGreyId: Long = -1
var disabledIconLabelId: Long = -1 var dialogSolidId: Long = -1
var isTabletLabelId: Long = -1 var disabledIconId: Long = -1
var notifierShelfLabelId: Long = -1 var isTabletId: Long = -1
var qualityAutoLabelId: Long = -1 var notifierShelfId: Long = -1
var qualityTitleLabelId: Long = -1 var privacyTosFooterId: Long = -1
var qualityAutoId: Long = -1
var qualityTitleId: Long = -1
} }
override fun execute(context: ResourceContext): PatchResult { override fun execute(context: ResourceContext): PatchResult {
@ -33,13 +35,15 @@ class SharedResourceIdPatch : ResourcePatch {
.resourceMappings .resourceMappings
.single { it.type == type.value && it.name == name }.id .single { it.type == type.value && it.name == name }.id
colorGreyLabelId = find(COLOR, "ytm_color_grey_12") chipCloudId = find(LAYOUT, "chip_cloud")
dialogSolidLabelId = find(STYLE, "Theme.YouTubeMusic.Dialog.Solid") colorGreyId = find(COLOR, "ytm_color_grey_12")
disabledIconLabelId = find(DIMEN, "disabled_icon_alpha") dialogSolidId = find(STYLE, "Theme.YouTubeMusic.Dialog.Solid")
isTabletLabelId = find(BOOL, "is_tablet") disabledIconId = find(DIMEN, "disabled_icon_alpha")
notifierShelfLabelId = find(LAYOUT, "music_notifier_shelf") isTabletId = find(BOOL, "is_tablet")
qualityAutoLabelId = find(STRING, "quality_auto") notifierShelfId = find(LAYOUT, "music_notifier_shelf")
qualityTitleLabelId = find(STRING, "quality_title") privacyTosFooterId = find(ID, "privacy_tos_footer")
qualityAutoId = find(STRING, "quality_auto")
qualityTitleId = find(STRING, "quality_title")
return PatchResultSuccess() return PatchResultSuccess()
} }

View File

@ -30,9 +30,10 @@ class MusicSettingsBytecodePatch : BytecodePatch(
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
SettingsHeadersFragmentFingerprint.result?.let { SettingsHeadersFragmentFingerprint.result?.let {
with(it.mutableMethod) { it.mutableMethod.apply {
val targetIndex = it.scanResult.patternScanResult!!.endIndex val targetIndex = it.scanResult.patternScanResult!!.endIndex
val targetRegister = (instruction(targetIndex) as OneRegisterInstruction).registerA val targetRegister = instruction<OneRegisterInstruction>(targetIndex).registerA
addInstruction( addInstruction(
targetIndex + 1, targetIndex + 1,
"invoke-static {v$targetRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->setActivity(Ljava/lang/Object;)V" "invoke-static {v$targetRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->setActivity(Ljava/lang/Object;)V"
@ -41,10 +42,11 @@ class MusicSettingsBytecodePatch : BytecodePatch(
} ?: return SettingsHeadersFragmentFingerprint.toErrorResult() } ?: return SettingsHeadersFragmentFingerprint.toErrorResult()
PreferenceFingerprint.result?.let { PreferenceFingerprint.result?.let {
with(it.mutableMethod) { it.mutableMethod.apply {
val targetIndex = it.scanResult.patternScanResult!!.endIndex val targetIndex = it.scanResult.patternScanResult!!.endIndex
val keyRegister = (instruction(targetIndex) as FiveRegisterInstruction).registerD val keyRegister = instruction<FiveRegisterInstruction>(targetIndex).registerD
val valueRegister = (instruction(targetIndex) as FiveRegisterInstruction).registerE val valueRegister = instruction<FiveRegisterInstruction>(targetIndex).registerE
addInstruction( addInstruction(
targetIndex, targetIndex,
"invoke-static {v$keyRegister, v$valueRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->onPreferenceChanged(Ljava/lang/String;Z)V" "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 * Copy colors
*/ */
context.xmlEditor["res/values/colors.xml"].use { editor -> context.xmlEditor["res/values/colors.xml"].use { editor ->
val resourcesNode = editor.file.getElementsByTagName("resources").item(0) as Element 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 { override fun execute(context: BytecodeContext): PatchResult {
SharePanelFingerprint.result?.let { SharePanelFingerprint.result?.let {
with (it.mutableMethod) { it.mutableMethod.apply {
val targetIndex = it.scanResult.patternScanResult!!.startIndex val targetIndex = it.scanResult.patternScanResult!!.startIndex
addInstructions( 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.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.music.misc.resourceid.patch.SharedResourceIdPatch import app.revanced.patches.music.misc.resourceid.patch.SharedResourceIdPatch.Companion.disabledIconId
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction import app.revanced.util.bytecode.isWideLiteralExists
import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
@ -18,12 +18,6 @@ object ShuffleClassFingerprint : MethodFingerprint(
Opcode.INVOKE_VIRTUAL, Opcode.INVOKE_VIRTUAL,
Opcode.RETURN_VOID Opcode.RETURN_VOID
), ),
customFingerprint = { methodDef -> customFingerprint = { it.name == "<init>" && it.isWideLiteralExists(disabledIconId) }
methodDef.name == "<init>" &&
methodDef.implementation?.instructions?.any {
it.opcode.ordinal == Opcode.CONST.ordinal &&
(it as? WideLiteralInstruction)?.wideLiteral == SharedResourceIdPatch.disabledIconLabelId
} == true
}
) )

View File

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

View File

@ -6,13 +6,14 @@ import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.instruction
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.Patch import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.music.misc.tastebuilder.fingerprints.TasteBuilderConstructorFingerprint import app.revanced.patches.music.misc.tastebuilder.fingerprints.TasteBuilderConstructorFingerprint
import app.revanced.patches.shared.annotation.YouTubeMusicCompatibility import app.revanced.patches.shared.annotation.YouTubeMusicCompatibility
import org.jf.dexlib2.iface.instruction.formats.Instruction22c import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction
@Patch @Patch
@Name("hide-taste-builder") @Name("hide-taste-builder")
@ -20,15 +21,13 @@ import org.jf.dexlib2.iface.instruction.formats.Instruction22c
@YouTubeMusicCompatibility @YouTubeMusicCompatibility
@Version("0.0.1") @Version("0.0.1")
class RemoveTasteBuilderPatch : BytecodePatch( class RemoveTasteBuilderPatch : BytecodePatch(
listOf( listOf(TasteBuilderConstructorFingerprint)
TasteBuilderConstructorFingerprint
)
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
TasteBuilderConstructorFingerprint.result?.let { TasteBuilderConstructorFingerprint.result?.let {
with (it.mutableMethod) { it.mutableMethod.apply {
val insertIndex = it.scanResult.patternScanResult!!.endIndex - 8 val insertIndex = it.scanResult.patternScanResult!!.endIndex - 8
val register = (implementation!!.instructions[insertIndex] as Instruction22c).registerA val register = instruction<TwoRegisterInstruction>(insertIndex).registerA
addInstructions( addInstructions(
insertIndex, """ 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.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.music.misc.resourceid.patch.SharedResourceIdPatch import app.revanced.patches.music.misc.resourceid.patch.SharedResourceIdPatch.Companion.notifierShelfId
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction import app.revanced.util.bytecode.isWideLiteralExists
import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
@ -16,11 +16,6 @@ object NotifierShelfFingerprint : MethodFingerprint(
Opcode.INVOKE_STATIC, Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT Opcode.MOVE_RESULT_OBJECT
), ),
customFingerprint = { methodDef -> customFingerprint = { it.isWideLiteralExists(notifierShelfId)}
methodDef.implementation?.instructions?.any {
it.opcode.ordinal == Opcode.CONST.ordinal &&
(it as? WideLiteralInstruction)?.wideLiteral == SharedResourceIdPatch.notifierShelfLabelId
} == true
}
) )

View File

@ -2,9 +2,9 @@ package app.revanced.patches.music.misc.upgradebutton.fingerprints
import app.revanced.patcher.extensions.or import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.util.bytecode.isNarrowLiteralExists
import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.instruction.NarrowLiteralInstruction
object PivotBarConstructorFingerprint : MethodFingerprint( object PivotBarConstructorFingerprint : MethodFingerprint(
returnType = "V", returnType = "V",
@ -13,10 +13,5 @@ object PivotBarConstructorFingerprint : MethodFingerprint(
Opcode.IPUT_OBJECT, Opcode.IPUT_OBJECT,
Opcode.RETURN_VOID Opcode.RETURN_VOID
), ),
customFingerprint = { methodDef -> customFingerprint = { it.name == "<init>" && it.isNarrowLiteralExists(117501096) }
methodDef.name == "<init>"
&& methodDef.implementation!!.instructions.any {
((it as? NarrowLiteralInstruction)?.narrowLiteral == 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.OneRegisterInstruction
import org.jf.dexlib2.iface.instruction.ReferenceInstruction import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction
import org.jf.dexlib2.iface.reference.FieldReference
@Patch @Patch
@Name("hide-upgrade-button") @Name("hide-upgrade-button")
@ -43,20 +42,12 @@ class RemoveUpgradeButtonPatch : BytecodePatch(
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
PivotBarConstructorFingerprint.result?.let { PivotBarConstructorFingerprint.result?.let {
with (it.mutableMethod) { it.mutableMethod.apply {
val targetIndex = it.scanResult.patternScanResult!!.startIndex 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 replaceReference = instruction<ReferenceInstruction>(targetIndex).reference.toString()
val targetRegisterB = (instruction(targetIndex) as TwoRegisterInstruction).registerB
val replaceReference =
(instruction(targetIndex) as ReferenceInstruction).reference as FieldReference
val replaceReferenceToCall = replaceReference.definingClass +
"->" +
replaceReference.name +
":" +
replaceReference.type
replaceInstruction( replaceInstruction(
targetIndex, targetIndex,
@ -69,16 +60,16 @@ class RemoveUpgradeButtonPatch : BytecodePatch(
if-le v1, v2, :dismiss if-le v1, v2, :dismiss
invoke-interface {v$targetRegisterA, v2}, Ljava/util/List;->remove(I)Ljava/lang/Object; invoke-interface {v$targetRegisterA, v2}, Ljava/util/List;->remove(I)Ljava/lang/Object;
:dismiss :dismiss
iput-object v$targetRegisterA, v$targetRegisterB, $replaceReferenceToCall iput-object v$targetRegisterA, v$targetRegisterB, $replaceReference
""" """
) )
} }
} ?: return PivotBarConstructorFingerprint.toErrorResult() } ?: return PivotBarConstructorFingerprint.toErrorResult()
NotifierShelfFingerprint.result?.let { NotifierShelfFingerprint.result?.let {
with (it.mutableMethod) { it.mutableMethod.apply {
val targetIndex = it.scanResult.patternScanResult!!.endIndex val targetIndex = it.scanResult.patternScanResult!!.endIndex
val targetRegister = (instruction(targetIndex) as OneRegisterInstruction).registerA val targetRegister = instruction<OneRegisterInstruction>(targetIndex).registerA
addInstruction( addInstruction(
targetIndex + 1, targetIndex + 1,
"invoke-static {v$targetRegister}, $INTEGRATIONS_PATH/adremover/AdRemoverAPI;->HideViewWithLayout1dp(Landroid/view/View;)V" "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 @YouTubeMusicCompatibility
@Version("0.0.1") @Version("0.0.1")
class MusicVideoIdPatch : BytecodePatch( class MusicVideoIdPatch : BytecodePatch(
listOf( listOf(MusicVideoIdFingerprint)
MusicVideoIdFingerprint
)
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
MusicVideoIdFingerprint.result?.let { MusicVideoIdFingerprint.result?.let {
insertIndex = it.scanResult.patternScanResult!!.endIndex it.mutableMethod.apply {
insertIndex = it.scanResult.patternScanResult!!.endIndex
with (it.mutableMethod) {
insertMethod = this insertMethod = this
videoIdRegister = (implementation!!.instructions[insertIndex] as OneRegisterInstruction).registerA videoIdRegister = instruction<OneRegisterInstruction>(insertIndex).registerA
} }
offset++ // offset so setVideoId is called before any injected call offset++ // offset so setVideoId is called before any injected call
} ?: return MusicVideoIdFingerprint.toErrorResult() } ?: 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.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
object MiniplayerColorParentFingerprint : MethodFingerprint( object ColorMatchPlayerParentFingerprint : MethodFingerprint(
returnType = "V", returnType = "V",
access = AccessFlags.PRIVATE or AccessFlags.FINAL, access = AccessFlags.PRIVATE or AccessFlags.FINAL,
opcodes = listOf( opcodes = listOf(

View File

@ -4,7 +4,5 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
object LayoutConstructorFingerprint : MethodFingerprint( object LayoutConstructorFingerprint : MethodFingerprint(
strings = listOf("1.0x"), strings = listOf("1.0x"),
customFingerprint = { customFingerprint = { it.definingClass.endsWith("YouTubeControlsOverlay;") }
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.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourceIdPatch import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourceIdPatch.Companion.imageOnlyTabId
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction import app.revanced.util.bytecode.isWideLiteralExists
import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
@ -14,10 +14,5 @@ object PivotBarCreateButtonViewFingerprint : MethodFingerprint(
Opcode.MOVE_OBJECT, Opcode.MOVE_OBJECT,
Opcode.INVOKE_DIRECT_RANGE, // unique instruction anchor Opcode.INVOKE_DIRECT_RANGE, // unique instruction anchor
), ),
customFingerprint = { methodDef -> customFingerprint = { it.isWideLiteralExists(imageOnlyTabId) }
methodDef.implementation?.instructions?.any {
it.opcode.ordinal == Opcode.CONST.ordinal &&
(it as? WideLiteralInstruction)?.wideLiteral == SharedResourceIdPatch.imageOnlyTabId
} == true
}
) )

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
}