Skip to content

Commit

Permalink
feat(YouTube Music): Add support version 8.05.50, Remove support ve…
Browse files Browse the repository at this point in the history
  • Loading branch information
inotia00 committed Feb 7, 2025
1 parent 38949e1 commit c575ffc
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -306,23 +306,32 @@ internal val repeatTrackFingerprint = legacyFingerprint(
strings = listOf("w_st")
)

internal const val SHUFFLE_BUTTON_ID = 45468L

internal val shuffleOnClickFingerprint = legacyFingerprint(
name = "shuffleOnClickFingerprint",
returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("Landroid/view/View;"),
literals = listOf(45468L),
literals = listOf(SHUFFLE_BUTTON_ID),
customFingerprint = { method, _ ->
method.name == "onClick" &&
indexOfAccessibilityInstruction(method) >= 0
method.name == "onClick"
}
)

internal fun indexOfAccessibilityInstruction(method: Method) =
method.indexOfFirstInstruction {
opcode == Opcode.INVOKE_VIRTUAL &&
getReference<MethodReference>()?.name == "announceForAccessibility"
internal val shuffleEnumFingerprint = legacyFingerprint(
name = "shuffleEnumFingerprint",
returnType = "V",
parameters = emptyList(),
strings = listOf(
"SHUFFLE_OFF",
"SHUFFLE_ALL",
"SHUFFLE_DISABLED",
),
customFingerprint = { method, _ ->
method.name == "<clinit>"
}
)

internal val swipeToCloseFingerprint = legacyFingerprint(
name = "swipeToCloseFingerprint",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import app.revanced.patches.music.utils.playservice.is_6_27_or_greater
import app.revanced.patches.music.utils.playservice.is_6_42_or_greater
import app.revanced.patches.music.utils.playservice.is_7_18_or_greater
import app.revanced.patches.music.utils.playservice.is_7_25_or_greater
import app.revanced.patches.music.utils.playservice.is_8_03_or_greater
import app.revanced.patches.music.utils.playservice.versionCheckPatch
import app.revanced.patches.music.utils.resourceid.colorGrey
import app.revanced.patches.music.utils.resourceid.darkBackground
Expand Down Expand Up @@ -57,6 +58,7 @@ import app.revanced.util.fingerprint.mutableClassOrThrow
import app.revanced.util.fingerprint.resolvable
import app.revanced.util.getReference
import app.revanced.util.getWalkerMethod
import app.revanced.util.indexOfFirstInstruction
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
import app.revanced.util.indexOfFirstLiteralInstructionOrThrow
Expand All @@ -65,13 +67,15 @@ import app.revanced.util.insertNode
import app.revanced.util.or
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
import com.android.tools.smali.dexlib2.immutable.ImmutableField
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
import org.w3c.dom.Element

private const val IMAGE_VIEW_TAG_NAME =
Expand Down Expand Up @@ -850,17 +854,28 @@ val playerComponentsPatch = bytecodePatch(
// region patch for remember shuffle state

shuffleOnClickFingerprint.methodOrThrow().apply {
val accessibilityIndex = indexOfAccessibilityInstruction(this)

// region set shuffle enum
val enumClass = shuffleEnumFingerprint.methodOrThrow().definingClass

val startIndex = indexOfFirstLiteralInstructionOrThrow(SHUFFLE_BUTTON_ID)

val (enumIndex, enumRegister) = if (is_8_03_or_greater) {
val index = indexOfFirstInstructionReversedOrThrow(startIndex) {
opcode == Opcode.INVOKE_VIRTUAL &&
getReference<MethodReference>()?.returnType == enumClass
}
val register = getInstruction<OneRegisterInstruction>(index + 1).registerA

val enumIndex = indexOfFirstInstructionReversedOrThrow(accessibilityIndex) {
opcode == Opcode.INVOKE_DIRECT &&
getReference<MethodReference>()?.returnType == "Ljava/lang/String;"
Pair(index + 2, register)
} else {
val index = indexOfFirstInstructionReversedOrThrow(startIndex) {
opcode == Opcode.INVOKE_DIRECT &&
getReference<MethodReference>()?.returnType == "Ljava/lang/String;"
}
val register = getInstruction<FiveRegisterInstruction>(index).registerD

Pair(index, register)
}
val enumRegister = getInstruction<FiveRegisterInstruction>(enumIndex).registerD
val enumClass =
(getInstruction<ReferenceInstruction>(enumIndex).reference as MethodReference).parameterTypes.first()

addInstruction(
enumIndex,
Expand All @@ -872,7 +887,7 @@ val playerComponentsPatch = bytecodePatch(
// region set static field

val shuffleClassIndex =
indexOfFirstInstructionReversedOrThrow(accessibilityIndex, Opcode.CHECK_CAST)
indexOfFirstInstructionReversedOrThrow(enumIndex, Opcode.CHECK_CAST)
val shuffleClass =
getInstruction<ReferenceInstruction>(shuffleClassIndex).reference.toString()
val shuffleMutableClass = classBy { classDef ->
Expand Down Expand Up @@ -901,17 +916,55 @@ val playerComponentsPatch = bytecodePatch(

// region make all methods accessible

fun Method.indexOfEnumOrdinalInstruction() =
indexOfFirstInstruction {
val reference = getReference<MethodReference>()
opcode == Opcode.INVOKE_VIRTUAL &&
reference?.name == "ordinal" &&
reference.definingClass == enumClass
}

val isShuffleMethod: Method.() -> Boolean = {
returnType == "V" &&
indexOfEnumOrdinalInstruction() >= 0 &&
indexOfFirstInstruction {
opcode == Opcode.INVOKE_VIRTUAL &&
getReference<MethodReference>()?.name == "post"
} >= 0
}

val shuffleMethod = shuffleMutableClass.methods.find { method ->
method.parameterTypes.firstOrNull() == enumClass &&
method.parameterTypes.size == 1 &&
method.returnType == "V"
method.isShuffleMethod()
} ?: throw PatchException("shuffle method not found")
val shuffleMethodRegisterCount = shuffleMethod.implementation!!.registerCount

shuffleMutableClass.methods.add(
shuffleMethod.cloneMutable(
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
name = "shuffleTracks"
)
name = "shuffleTracks",
registerCount = if (is_8_03_or_greater) {
shuffleMethodRegisterCount + 1
} else {
shuffleMethodRegisterCount
},
parameters = listOf(
ImmutableMethodParameter(
enumClass,
annotations,
"enumClass"
)
)
).apply {
if (is_8_03_or_greater) {
val index = indexOfEnumOrdinalInstruction()
val register = getInstruction<FiveRegisterInstruction>(index).registerC

addInstruction(
index,
"move-object/from16 v$register, p1"
)
}
}
)

// endregion
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ internal object Constants {
"6.51.53", // This is the latest version of YouTube Music 6.xx.xx
"7.16.53", // This is the latest version that supports the 'Spoof app version' patch.
"7.25.53", // This is the last supported version for 2024.
"8.02.53", // This is the latest version supported by the RVX patch.
"8.05.50", // This is the latest version supported by the RVX patch.
)
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ var is_7_27_or_greater = false
private set
var is_7_29_or_greater = false
private set
var is_8_03_or_greater = false
private set

val versionCheckPatch = resourcePatch(
description = "versionCheckPatch",
Expand Down Expand Up @@ -62,5 +64,6 @@ val versionCheckPatch = resourcePatch(
is_7_25_or_greater = 244399000 <= playStoreServicesVersion
is_7_27_or_greater = 244515000 <= playStoreServicesVersion
is_7_29_or_greater = 244799000 <= playStoreServicesVersion
is_8_03_or_greater = 250399000 <= playStoreServicesVersion
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
import com.android.tools.smali.dexlib2.iface.reference.StringReference

internal val createPlayerRequestBodyWithModelFingerprint = legacyFingerprint(
name = "createPlayerRequestBodyWithModelFingerprint",
Expand Down Expand Up @@ -75,9 +76,14 @@ internal val sharedSettingFingerprint = legacyFingerprint(
internal val spannableStringBuilderFingerprint = legacyFingerprint(
name = "spannableStringBuilderFingerprint",
returnType = "Ljava/lang/CharSequence;",
strings = listOf("Failed to set PB Style Run Extension in TextComponentSpec. Extension id: %s"),
customFingerprint = { method, _ ->
indexOfSpannableStringInstruction(method) >= 0
method.indexOfFirstInstruction {
opcode == Opcode.CONST_STRING &&
getReference<StringReference>()
?.string.toString()
.startsWith("Failed to set PB Style Run Extension in TextComponentSpec.")
} >= 0 &&
indexOfSpannableStringInstruction(method) >= 0
}
)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
package app.revanced.patches.shared.litho

import app.revanced.util.fingerprint.legacyFingerprint
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
import app.revanced.util.or
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.reference.StringReference

internal const val BUFFER_UPD_FEATURE_FLAG = 45419603L

internal val bufferUpbFeatureFlagFingerprint = legacyFingerprint(
name = "bufferUpbFeatureFlagFingerprint",
returnType = "L",
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
parameters = listOf("L"),
literals = listOf(45419603L),
literals = listOf(BUFFER_UPD_FEATURE_FLAG),
)

internal val byteBufferFingerprint = legacyFingerprint(
Expand Down Expand Up @@ -51,9 +56,16 @@ internal val emptyComponentsFingerprint = legacyFingerprint(
Opcode.INVOKE_INTERFACE,
Opcode.INVOKE_STATIC_RANGE,
Opcode.MOVE_RESULT_OBJECT,
Opcode.IGET_OBJECT
Opcode.IGET_OBJECT,
),
strings = listOf("Error while converting %s"),
customFingerprint = { method, _ ->
method.indexOfFirstInstruction {
opcode == Opcode.CONST_STRING &&
getReference<StringReference>()
?.string.toString()
.startsWith("Error while converting")
} >= 0
}
)

/**
Expand All @@ -65,10 +77,12 @@ internal val pathBuilderFingerprint = legacyFingerprint(
strings = listOf("Number of bits must be positive"),
)

internal const val PATH_UPD_FEATURE_FLAG = 45631264L

internal val pathUpbFeatureFlagFingerprint = legacyFingerprint(
name = "pathUpbFeatureFlagFingerprint",
returnType = "Z",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = emptyList(),
literals = listOf(45631264L),
literals = listOf(PATH_UPD_FEATURE_FLAG),
)
Original file line number Diff line number Diff line change
Expand Up @@ -165,13 +165,11 @@ val lithoFilterPatch = bytecodePatch(
// Turn off native code that handles litho component names. If this feature is on then nearly
// all litho components have a null name and identifier/path filtering is completely broken.

if (bufferUpbFeatureFlagFingerprint.second.methodOrNull != null &&
pathUpbFeatureFlagFingerprint.second.methodOrNull != null
) {
mapOf(
bufferUpbFeatureFlagFingerprint to 45419603L,
pathUpbFeatureFlagFingerprint to 45631264L,
).forEach { (fingerprint, literalValue) ->
mapOf(
bufferUpbFeatureFlagFingerprint to BUFFER_UPD_FEATURE_FLAG,
pathUpbFeatureFlagFingerprint to PATH_UPD_FEATURE_FLAG,
).forEach { (fingerprint, literalValue) ->
if (fingerprint.second.methodOrNull != null) {
fingerprint.injectLiteralInstructionBooleanCall(
literalValue,
"0x0"
Expand Down

0 comments on commit c575ffc

Please sign in to comment.