mirror of
https://github.com/inotia00/revanced-patches.git
synced 2025-05-01 07:04:30 +02:00
feat(music/remember-shuffle-state): change patch name enable-force-shuffle
→ remember-shuffle-state
This commit is contained in:
parent
ff895f6f66
commit
6601d4539c
@ -7,20 +7,20 @@ import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.removeInstruction
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
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.player.colormatchplayer.fingerprints.ColorMatchPlayerFingerprint
|
||||
import app.revanced.patches.music.utils.annotations.MusicCompatibility
|
||||
import app.revanced.patches.music.utils.fingerprints.ColorMatchPlayerParentFingerprint
|
||||
import app.revanced.patches.music.utils.fingerprints.PlayerColorFingerprint
|
||||
import app.revanced.patches.music.utils.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.util.enum.CategoryType
|
||||
import app.revanced.util.integrations.Constants.MUSIC_PLAYER
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
@Patch
|
||||
@Name("Enable color match player")
|
||||
@ -28,50 +28,44 @@ import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||
@DependsOn([SettingsPatch::class])
|
||||
@MusicCompatibility
|
||||
class ColorMatchPlayerPatch : BytecodePatch(
|
||||
listOf(ColorMatchPlayerParentFingerprint)
|
||||
listOf(PlayerColorFingerprint)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
|
||||
ColorMatchPlayerParentFingerprint.result?.let { parentResult ->
|
||||
ColorMatchPlayerFingerprint.also {
|
||||
it.resolve(
|
||||
context,
|
||||
parentResult.classDef
|
||||
)
|
||||
}.result?.let {
|
||||
PlayerColorFingerprint.result?.let {
|
||||
it.mutableMethod.apply {
|
||||
targetMethod = parentResult.mutableMethod
|
||||
|
||||
val insertIndex = it.scanResult.patternScanResult!!.startIndex + 1
|
||||
relativeIndex = it.scanResult.patternScanResult!!.startIndex
|
||||
val insertIndex = implementation!!.instructions.indexOfFirst { instruction ->
|
||||
instruction.opcode == Opcode.IPUT_OBJECT
|
||||
}
|
||||
val jumpInstruction = getInstruction<Instruction>(insertIndex)
|
||||
|
||||
val type = it.classDef.type
|
||||
val replaceReference =
|
||||
getInstruction<ReferenceInstruction>(insertIndex - 1).reference
|
||||
|
||||
addInstructionsWithLabels(
|
||||
insertIndex, """
|
||||
invoke-static {}, $MUSIC_PLAYER->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)}
|
||||
iget v0, p0, ${descriptor(2)}
|
||||
if-eq v0, v2, :switch
|
||||
iput v2, p0, ${descriptor(2)}
|
||||
iget-object v0, p0, ${descriptor(3)}
|
||||
invoke-virtual {v0, v2, p2, p3}, ${descriptor(4)}
|
||||
:switch
|
||||
iget v0, p0, ${descriptor(7)}
|
||||
if-eq v0, v1, :exit
|
||||
iput v1, p0, ${descriptor(10)}
|
||||
iget-object v0, p0, ${descriptor(11)}
|
||||
invoke-virtual {v0, v1, p2, p3}, ${descriptor(12)}
|
||||
iput v1, p0, ${descriptor(7)}
|
||||
iget-object v0, p0, ${descriptor(8)}
|
||||
invoke-virtual {v0, v1, p2, p3}, ${descriptor(9)}
|
||||
goto :exit
|
||||
:off
|
||||
invoke-direct {p0}, ${type}->${parentResult.mutableMethod.name}()V
|
||||
invoke-direct {p0}, $replaceReference
|
||||
""", ExternalLabel("exit", jumpInstruction)
|
||||
)
|
||||
removeInstruction(insertIndex - 1)
|
||||
}
|
||||
} ?: throw ColorMatchPlayerFingerprint.exception
|
||||
} ?: throw ColorMatchPlayerParentFingerprint.exception
|
||||
} ?: throw PlayerColorFingerprint.exception
|
||||
|
||||
SettingsPatch.addMusicPreference(
|
||||
CategoryType.PLAYER,
|
||||
@ -82,10 +76,10 @@ class ColorMatchPlayerPatch : BytecodePatch(
|
||||
}
|
||||
|
||||
private companion object {
|
||||
private lateinit var targetMethod: MutableMethod
|
||||
var relativeIndex by Delegates.notNull<Int>()
|
||||
|
||||
fun descriptor(index: Int): String {
|
||||
return targetMethod.getInstruction<ReferenceInstruction>(index).reference.toString()
|
||||
fun MutableMethod.descriptor(index: Int): String {
|
||||
return getInstruction<ReferenceInstruction>(relativeIndex + index).reference.toString()
|
||||
}
|
||||
}
|
||||
}
|
@ -13,7 +13,7 @@ import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patches.music.player.oldstyleminiplayer.fingerprints.NextButtonVisibilityFingerprint
|
||||
import app.revanced.patches.music.player.oldstyleminiplayer.fingerprints.SwipeToCloseFingerprint
|
||||
import app.revanced.patches.music.utils.annotations.MusicCompatibility
|
||||
import app.revanced.patches.music.utils.fingerprints.ColorMatchPlayerParentFingerprint
|
||||
import app.revanced.patches.music.utils.fingerprints.PlayerColorFingerprint
|
||||
import app.revanced.patches.music.utils.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.util.enum.CategoryType
|
||||
import app.revanced.util.integrations.Constants.MUSIC_PLAYER
|
||||
@ -26,13 +26,13 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
@MusicCompatibility
|
||||
class OldStyleMiniPlayerPatch : BytecodePatch(
|
||||
listOf(
|
||||
ColorMatchPlayerParentFingerprint,
|
||||
PlayerColorFingerprint,
|
||||
SwipeToCloseFingerprint
|
||||
)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
|
||||
ColorMatchPlayerParentFingerprint.result?.let { parentResult ->
|
||||
PlayerColorFingerprint.result?.let { parentResult ->
|
||||
NextButtonVisibilityFingerprint.also {
|
||||
it.resolve(
|
||||
context,
|
||||
@ -52,7 +52,7 @@ class OldStyleMiniPlayerPatch : BytecodePatch(
|
||||
)
|
||||
}
|
||||
} ?: throw NextButtonVisibilityFingerprint.exception
|
||||
} ?: throw ColorMatchPlayerParentFingerprint.exception
|
||||
} ?: throw PlayerColorFingerprint.exception
|
||||
|
||||
SwipeToCloseFingerprint.result?.let {
|
||||
it.mutableMethod.apply {
|
||||
|
@ -1,27 +0,0 @@
|
||||
package app.revanced.patches.music.player.shuffle.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import app.revanced.patches.music.utils.resourceid.patch.SharedResourceIdPatch.Companion.DisabledIconAlpha
|
||||
import app.revanced.util.bytecode.isWideLiteralExists
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
object ShuffleClassFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
|
||||
opcodes = listOf(
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.IPUT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.RETURN_VOID
|
||||
),
|
||||
customFingerprint = { methodDef, _ ->
|
||||
methodDef.name == "<init>" && methodDef.isWideLiteralExists(
|
||||
DisabledIconAlpha
|
||||
)
|
||||
}
|
||||
)
|
||||
|
@ -1,187 +0,0 @@
|
||||
package app.revanced.patches.music.player.shuffle.patch
|
||||
|
||||
import app.revanced.extensions.exception
|
||||
import app.revanced.extensions.transformFields
|
||||
import app.revanced.extensions.traverseClassHierarchy
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
|
||||
import app.revanced.patcher.util.smali.toInstructions
|
||||
import app.revanced.patches.music.player.shuffle.fingerprints.MusicPlaybackControlsFingerprint
|
||||
import app.revanced.patches.music.player.shuffle.fingerprints.ShuffleClassFingerprint
|
||||
import app.revanced.patches.music.player.shuffle.fingerprints.ShuffleClassReferenceFingerprint
|
||||
import app.revanced.patches.music.utils.annotations.MusicCompatibility
|
||||
import app.revanced.patches.music.utils.resourceid.patch.SharedResourceIdPatch
|
||||
import app.revanced.patches.music.utils.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.util.enum.CategoryType
|
||||
import app.revanced.util.integrations.Constants.MUSIC_MISC_PATH
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||
import com.android.tools.smali.dexlib2.iface.reference.Reference
|
||||
import com.android.tools.smali.dexlib2.immutable.ImmutableField
|
||||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
|
||||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodImplementation
|
||||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
|
||||
|
||||
@Patch
|
||||
@Name("Enable force shuffle")
|
||||
@Description("Enable force shuffle even if another track is played.")
|
||||
@DependsOn(
|
||||
[
|
||||
SettingsPatch::class,
|
||||
SharedResourceIdPatch::class
|
||||
]
|
||||
)
|
||||
@MusicCompatibility
|
||||
class EnforceShufflePatch : BytecodePatch(
|
||||
listOf(
|
||||
MusicPlaybackControlsFingerprint,
|
||||
ShuffleClassFingerprint,
|
||||
ShuffleClassReferenceFingerprint
|
||||
)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
|
||||
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 = getInstruction(startIndex).descriptor
|
||||
shuffleReference2 = getInstruction(startIndex + 1).descriptor
|
||||
shuffleReference3 = getInstruction(endIndex).descriptor
|
||||
shuffleReference4 = getInstruction(imageViewIndex).descriptor
|
||||
}
|
||||
} ?: throw ShuffleClassReferenceFingerprint.exception
|
||||
|
||||
|
||||
ShuffleClassFingerprint.result?.let {
|
||||
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
|
||||
transformFields {
|
||||
ImmutableField(
|
||||
definingClass,
|
||||
name,
|
||||
type,
|
||||
AccessFlags.PUBLIC or AccessFlags.PUBLIC,
|
||||
null,
|
||||
annotations,
|
||||
null
|
||||
).toMutable()
|
||||
}
|
||||
}
|
||||
} ?: throw ShuffleClassFingerprint.exception
|
||||
|
||||
MusicPlaybackControlsFingerprint.result?.let {
|
||||
it.mutableMethod.apply {
|
||||
shuffleReference5 = getInstruction(0).descriptor
|
||||
shuffleReference6 = getInstruction(1).descriptor
|
||||
|
||||
addInstructions(
|
||||
0, """
|
||||
invoke-virtual {v0, v1}, $MUSIC_PLAYBACK_CONTROLS_CLASS_DESCRIPTOR->buttonHook(Z)V
|
||||
return-void
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
it.mutableClass.apply {
|
||||
staticFields.add(
|
||||
ImmutableField(
|
||||
it.mutableMethod.definingClass,
|
||||
"shuffleclass",
|
||||
SHUFFLE_CLASS,
|
||||
AccessFlags.PUBLIC or AccessFlags.STATIC,
|
||||
null,
|
||||
annotations,
|
||||
null
|
||||
).toMutable()
|
||||
)
|
||||
|
||||
val shuffleFieldReference = shuffleReference3 as FieldReference
|
||||
|
||||
methods.add(
|
||||
ImmutableMethod(
|
||||
it.classDef.type,
|
||||
"buttonHook",
|
||||
listOf(ImmutableMethodParameter("Z", annotations, null)),
|
||||
"V",
|
||||
AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
annotations,
|
||||
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, $shuffleReference1
|
||||
invoke-interface {v1}, $shuffleReference2
|
||||
move-result-object v1
|
||||
check-cast v1, ${shuffleFieldReference.definingClass}
|
||||
iget-object v1, v1, $shuffleReference3
|
||||
invoke-virtual {v1}, ${shuffleFieldReference.type}->ordinal()I
|
||||
move-result v1
|
||||
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, $shuffleReference5
|
||||
invoke-virtual {v3}, $shuffleReference6
|
||||
return-void
|
||||
""".toInstructions(), null, null
|
||||
)
|
||||
).toMutable()
|
||||
)
|
||||
}
|
||||
} ?: throw MusicPlaybackControlsFingerprint.exception
|
||||
|
||||
SettingsPatch.addMusicPreference(
|
||||
CategoryType.PLAYER,
|
||||
"revanced_enable_force_shuffle",
|
||||
"true"
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val MUSIC_PLAYBACK_CONTROLS_CLASS_DESCRIPTOR =
|
||||
"Lcom/google/android/apps/youtube/music/watchpage/MusicPlaybackControls;"
|
||||
|
||||
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
|
||||
|
||||
val Instruction.descriptor
|
||||
get() = (this as ReferenceInstruction).reference
|
||||
}
|
||||
}
|
@ -0,0 +1,180 @@
|
||||
package app.revanced.patches.music.player.shuffle.patch
|
||||
|
||||
import app.revanced.extensions.exception
|
||||
import app.revanced.extensions.transformFields
|
||||
import app.revanced.extensions.traverseClassHierarchy
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
|
||||
import app.revanced.patches.music.player.shuffle.fingerprints.MusicPlaybackControlsFingerprint
|
||||
import app.revanced.patches.music.player.shuffle.fingerprints.ShuffleClassReferenceFingerprint
|
||||
import app.revanced.patches.music.utils.annotations.MusicCompatibility
|
||||
import app.revanced.patches.music.utils.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.util.enum.CategoryType
|
||||
import app.revanced.util.integrations.Constants.MUSIC_PLAYER
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||
import com.android.tools.smali.dexlib2.iface.reference.Reference
|
||||
import com.android.tools.smali.dexlib2.immutable.ImmutableField
|
||||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
|
||||
import com.android.tools.smali.dexlib2.util.MethodUtil
|
||||
|
||||
@Patch
|
||||
@Name("Remember shuffle state")
|
||||
@Description("Remembers the state of the shuffle.")
|
||||
@DependsOn([SettingsPatch::class])
|
||||
@MusicCompatibility
|
||||
class RememberShufflePatch : BytecodePatch(
|
||||
listOf(
|
||||
MusicPlaybackControlsFingerprint,
|
||||
ShuffleClassReferenceFingerprint
|
||||
)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
|
||||
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
|
||||
|
||||
val shuffleReference1 = descriptor(startIndex)
|
||||
val shuffleReference2 = descriptor(startIndex + 1)
|
||||
val shuffleReference3 = descriptor(endIndex)
|
||||
val shuffleFieldReference = shuffleReference3 as FieldReference
|
||||
imageViewReference = descriptor(imageViewIndex)
|
||||
|
||||
shuffleStateLabel = """
|
||||
iget-object v1, v0, $shuffleReference1
|
||||
invoke-interface {v1}, $shuffleReference2
|
||||
move-result-object v1
|
||||
check-cast v1, ${shuffleFieldReference.definingClass}
|
||||
iget-object v1, v1, $shuffleReference3
|
||||
invoke-virtual {v1}, ${shuffleFieldReference.type}->ordinal()I
|
||||
move-result v1
|
||||
"""
|
||||
}
|
||||
|
||||
val constructorMethod =
|
||||
it.mutableClass.methods.first { method -> MethodUtil.isConstructor(method) }
|
||||
val onClickMethod = it.mutableClass.methods.first { method -> method.name == "onClick" }
|
||||
|
||||
constructorMethod.apply {
|
||||
addInstruction(
|
||||
implementation!!.instructions.size - 1,
|
||||
"sput-object p0, $MUSIC_PLAYBACK_CONTROLS_CLASS_DESCRIPTOR->shuffleClass:$SHUFFLE_CLASS"
|
||||
)
|
||||
}
|
||||
|
||||
onClickMethod.apply {
|
||||
addInstructions(
|
||||
0, """
|
||||
move-object v0, p0
|
||||
""" + shuffleStateLabel + """
|
||||
invoke-static {v1}, $MUSIC_PLAYER->setShuffleState(I)V
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
context.traverseClassHierarchy(it.mutableClass) {
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL
|
||||
transformFields {
|
||||
ImmutableField(
|
||||
definingClass,
|
||||
name,
|
||||
type,
|
||||
AccessFlags.PUBLIC or AccessFlags.PUBLIC,
|
||||
null,
|
||||
annotations,
|
||||
null
|
||||
).toMutable()
|
||||
}
|
||||
}
|
||||
} ?: throw ShuffleClassReferenceFingerprint.exception
|
||||
|
||||
MusicPlaybackControlsFingerprint.result?.let {
|
||||
it.mutableMethod.apply {
|
||||
addInstruction(
|
||||
0,
|
||||
"invoke-virtual {v0}, $MUSIC_PLAYBACK_CONTROLS_CLASS_DESCRIPTOR->rememberShuffleState()V"
|
||||
)
|
||||
|
||||
val shuffleField = ImmutableField(
|
||||
definingClass,
|
||||
"shuffleClass",
|
||||
SHUFFLE_CLASS,
|
||||
AccessFlags.PUBLIC or AccessFlags.STATIC,
|
||||
null,
|
||||
annotations,
|
||||
null
|
||||
).toMutable()
|
||||
|
||||
val shuffleMethod = ImmutableMethod(
|
||||
definingClass,
|
||||
"rememberShuffleState",
|
||||
emptyList(),
|
||||
"V",
|
||||
AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
annotations, null,
|
||||
MutableMethodImplementation(5)
|
||||
).toMutable()
|
||||
|
||||
shuffleMethod.addInstructionsWithLabels(
|
||||
0, """
|
||||
invoke-static {}, $MUSIC_PLAYER->getShuffleState()I
|
||||
move-result v2
|
||||
if-nez v2, :dont_shuffle
|
||||
sget-object v0, $MUSIC_PLAYBACK_CONTROLS_CLASS_DESCRIPTOR->shuffleClass:$SHUFFLE_CLASS
|
||||
""" + shuffleStateLabel + """
|
||||
iget-object v3, v0, $imageViewReference
|
||||
invoke-virtual {v3}, Landroid/widget/ImageView;->performClick()Z
|
||||
if-eqz v1, :dont_shuffle
|
||||
invoke-virtual {v3}, Landroid/widget/ImageView;->performClick()Z
|
||||
:dont_shuffle
|
||||
return-void
|
||||
"""
|
||||
)
|
||||
|
||||
it.mutableClass.methods.add(shuffleMethod)
|
||||
it.mutableClass.staticFields.add(shuffleField)
|
||||
}
|
||||
} ?: throw MusicPlaybackControlsFingerprint.exception
|
||||
|
||||
SettingsPatch.addMusicPreference(
|
||||
CategoryType.PLAYER,
|
||||
"revanced_remember_shuffle_state",
|
||||
"true"
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val MUSIC_PLAYBACK_CONTROLS_CLASS_DESCRIPTOR =
|
||||
"Lcom/google/android/apps/youtube/music/watchpage/MusicPlaybackControls;"
|
||||
|
||||
lateinit var SHUFFLE_CLASS: String
|
||||
lateinit var imageViewReference: Reference
|
||||
lateinit var shuffleStateLabel: String
|
||||
|
||||
fun MutableMethod.descriptor(index: Int): Reference {
|
||||
return getInstruction<ReferenceInstruction>(index).reference
|
||||
}
|
||||
}
|
||||
}
|
@ -13,7 +13,7 @@ import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patches.music.player.zenmode.fingerprints.ZenModeFingerprint
|
||||
import app.revanced.patches.music.utils.annotations.MusicCompatibility
|
||||
import app.revanced.patches.music.utils.fingerprints.ColorMatchPlayerParentFingerprint
|
||||
import app.revanced.patches.music.utils.fingerprints.PlayerColorFingerprint
|
||||
import app.revanced.patches.music.utils.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.util.enum.CategoryType
|
||||
import app.revanced.util.integrations.Constants.MUSIC_PLAYER
|
||||
@ -26,11 +26,11 @@ import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||
@DependsOn([SettingsPatch::class])
|
||||
@MusicCompatibility
|
||||
class ZenModePatch : BytecodePatch(
|
||||
listOf(ColorMatchPlayerParentFingerprint)
|
||||
listOf(PlayerColorFingerprint)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
|
||||
ColorMatchPlayerParentFingerprint.result?.let { parentResult ->
|
||||
PlayerColorFingerprint.result?.let { parentResult ->
|
||||
ZenModeFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.let {
|
||||
it.mutableMethod.apply {
|
||||
val startIndex = it.scanResult.patternScanResult!!.startIndex
|
||||
@ -40,11 +40,11 @@ class ZenModePatch : BytecodePatch(
|
||||
getInstruction<OneRegisterInstruction>(startIndex + 2).registerA
|
||||
val dummyRegister = secondRegister + 1
|
||||
|
||||
val referenceIndex = it.scanResult.patternScanResult!!.endIndex + 1
|
||||
val targetReference =
|
||||
getInstruction<ReferenceInstruction>(referenceIndex).reference.toString()
|
||||
val replaceReferenceIndex = it.scanResult.patternScanResult!!.endIndex + 1
|
||||
val replaceReference =
|
||||
getInstruction<ReferenceInstruction>(replaceReferenceIndex).reference
|
||||
|
||||
val insertIndex = referenceIndex + 1
|
||||
val insertIndex = replaceReferenceIndex + 1
|
||||
|
||||
addInstructionsWithLabels(
|
||||
insertIndex, """
|
||||
@ -56,13 +56,13 @@ class ZenModePatch : BytecodePatch(
|
||||
const v$firstRegister, -0xbfbfc0
|
||||
const v$secondRegister, -0xbfbfc0
|
||||
:off
|
||||
sget-object v0, $targetReference
|
||||
sget-object v0, $replaceReference
|
||||
"""
|
||||
)
|
||||
removeInstruction(referenceIndex)
|
||||
removeInstruction(replaceReferenceIndex)
|
||||
}
|
||||
} ?: throw ZenModeFingerprint.exception
|
||||
} ?: throw ColorMatchPlayerParentFingerprint.exception
|
||||
} ?: throw PlayerColorFingerprint.exception
|
||||
|
||||
SettingsPatch.addMusicPreference(
|
||||
CategoryType.PLAYER,
|
||||
|
@ -5,22 +5,23 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
object ColorMatchPlayerParentFingerprint : MethodFingerprint(
|
||||
object PlayerColorFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL,
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = listOf("L", "J"),
|
||||
opcodes = listOf(
|
||||
Opcode.IGET,
|
||||
Opcode.IGET,
|
||||
Opcode.CONST_WIDE_16,
|
||||
Opcode.IF_EQ,
|
||||
Opcode.IPUT,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.IGET,
|
||||
Opcode.IGET,
|
||||
Opcode.IF_EQ,
|
||||
Opcode.IPUT,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.IF_EQZ
|
||||
)
|
||||
)
|
@ -22,7 +22,6 @@ class SharedResourceIdPatch : ResourcePatch {
|
||||
var ChipCloud: Long = -1
|
||||
var ColorGrey: Long = -1
|
||||
var DialogSolid: Long = -1
|
||||
var DisabledIconAlpha: Long = -1
|
||||
var InlineTimeBarAdBreakMarkerColor: Long = -1
|
||||
var IsTablet: Long = -1
|
||||
var MenuEntry: Long = -1
|
||||
@ -49,7 +48,6 @@ class SharedResourceIdPatch : ResourcePatch {
|
||||
ChipCloud = find(LAYOUT, "chip_cloud")
|
||||
ColorGrey = find(COLOR, "ytm_color_grey_12")
|
||||
DialogSolid = find(STYLE, "Theme.YouTubeMusic.Dialog.Solid")
|
||||
DisabledIconAlpha = find(DIMEN, "disabled_icon_alpha")
|
||||
InlineTimeBarAdBreakMarkerColor = find(COLOR, "inline_time_bar_ad_break_marker_color")
|
||||
IsTablet = find(BOOL, "is_tablet")
|
||||
MenuEntry = find(LAYOUT, "menu_entry")
|
||||
|
@ -32,8 +32,6 @@
|
||||
<string name="revanced_enable_flyout_panel_playback_speed_title">Enable playback speed</string>
|
||||
<string name="revanced_enable_force_minimized_player_summary">Keep player permanently minimized even if another track is played.</string>
|
||||
<string name="revanced_enable_force_minimized_player_title">Enable force minimized player</string>
|
||||
<string name="revanced_enable_force_shuffle_summary">Enable force shuffle even if another track is played.</string>
|
||||
<string name="revanced_enable_force_shuffle_title">Enable force shuffle</string>
|
||||
<string name="revanced_enable_landscape_mode_summary">Enables entry into landscape mode by screen rotation on the phone.</string>
|
||||
<string name="revanced_enable_landscape_mode_title">Enable landscape mode</string>
|
||||
<string name="revanced_enable_new_layout_summary">Enable new player layouts.</string>
|
||||
@ -129,6 +127,8 @@
|
||||
<string name="revanced_replace_flyout_panel_dismiss_queue_continue_watch_title">Continue watching</string>
|
||||
<string name="revanced_replace_flyout_panel_dismiss_queue_summary">Replaces dismiss queue menu to watch on YouTube.</string>
|
||||
<string name="revanced_replace_flyout_panel_dismiss_queue_title">Replace dismiss queue</string>
|
||||
<string name="revanced_remember_shuffle_state_summary">Remembers the state of the shuffle.</string>
|
||||
<string name="revanced_remember_shuffle_state_title">Remember shuffle state</string>
|
||||
<string name="revanced_reset">Reset</string>
|
||||
<string name="revanced_ryd_about">About</string>
|
||||
<string name="revanced_ryd_attribution_summary">Data is provided by the Return YouTube Dislike API. Tap here to learn more.</string>
|
||||
|
Loading…
x
Reference in New Issue
Block a user