feat(YouTube Music): Add support version 8.02.53

This commit is contained in:
inotia00 2025-01-17 14:58:44 +09:00
parent c8cc8c4bda
commit 4307b8e439
13 changed files with 110 additions and 73 deletions

View File

@ -49,9 +49,14 @@ val dislikeRedirectionPatch = bytecodePatch(
val onClickMethod = getWalkerMethod(onClickMethodIndex)
onClickMethod.apply {
val onClickIndex = indexOfFirstInstructionOrThrow {
val reference =
((this as? ReferenceInstruction)?.reference as? MethodReference)
val relativeIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.INVOKE_VIRTUAL &&
getReference<MethodReference>()
?.parameterTypes
?.contains("Ljava/util/Map;") == true
}
val onClickIndex = indexOfFirstInstructionOrThrow(relativeIndex) {
val reference = getReference<MethodReference>()
opcode == Opcode.INVOKE_INTERFACE &&
reference?.returnType == "V" &&

View File

@ -12,6 +12,8 @@ import app.revanced.patches.music.utils.settings.ResourceUtils.updatePatchStatus
import app.revanced.patches.music.utils.settings.addPreferenceWithIntent
import app.revanced.patches.music.utils.settings.settingsPatch
import app.revanced.util.fingerprint.matchOrThrow
import app.revanced.util.fingerprint.methodOrThrow
import app.revanced.util.indexOfFirstStringInstructionOrThrow
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
@Suppress("unused")
@ -25,20 +27,18 @@ val changeStartPagePatch = bytecodePatch(
execute {
coldStartUpFingerprint.matchOrThrow().let {
it.method.apply {
val targetIndex = it.patternMatch!!.endIndex
val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
coldStartUpFingerprint.methodOrThrow().apply {
val targetIndex = indexOfFirstStringInstructionOrThrow(DEFAULT_BROWSE_ID) + 1
val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
addInstructions(
targetIndex + 1, """
invoke-static {v$targetRegister}, $GENERAL_CLASS_DESCRIPTOR->changeStartPage(Ljava/lang/String;)Ljava/lang/String;
move-result-object v$targetRegister
return-object v$targetRegister
"""
)
removeInstruction(targetIndex)
}
addInstructions(
targetIndex + 1, """
invoke-static {v$targetRegister}, $GENERAL_CLASS_DESCRIPTOR->changeStartPage(Ljava/lang/String;)Ljava/lang/String;
move-result-object v$targetRegister
return-object v$targetRegister
"""
)
removeInstruction(targetIndex)
}
addPreferenceWithIntent(

View File

@ -5,16 +5,17 @@ import app.revanced.util.or
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
const val DEFAULT_BROWSE_ID = "FEmusic_home"
internal val coldStartUpFingerprint = legacyFingerprint(
name = "coldStartUpFingerprint",
returnType = "Ljava/lang/String;",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = emptyList(),
opcodes = listOf(
Opcode.GOTO,
Opcode.CONST_STRING,
Opcode.RETURN_OBJECT
),
strings = listOf("FEmusic_library_sideloaded_tracks", "FEmusic_home")
strings = listOf("FEmusic_library_sideloaded_tracks", DEFAULT_BROWSE_ID)
)

View File

@ -22,7 +22,9 @@ internal val audioVideoSwitchToggleConstructorFingerprint = legacyFingerprint(
internal fun indexOfAudioVideoSwitchSetOnClickListenerInstruction(method: Method) =
method.indexOfFirstInstruction {
opcode == Opcode.INVOKE_VIRTUAL &&
getReference<MethodReference>()?.toString() == "Lcom/google/android/apps/youtube/music/player/AudioVideoSwitcherToggleView;->setOnClickListener(Landroid/view/View${'$'}OnClickListener;)V"
getReference<MethodReference>()
?.toString()
?.endsWith("/AudioVideoSwitcherToggleView;->setOnClickListener(Landroid/view/View${'$'}OnClickListener;)V") == true
}
internal val snackBarParentFingerprint = legacyFingerprint(

View File

@ -40,6 +40,7 @@ val cairoSplashAnimationPatch = bytecodePatch(
"7.06.54",
"7.16.53",
"7.25.53",
"8.02.53",
),
)

View File

@ -23,7 +23,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
const val AUDIO_VIDEO_SWITCH_TOGGLE_VISIBILITY =
"Lcom/google/android/apps/youtube/music/player/AudioVideoSwitcherToggleView;->setVisibility(I)V"
"/AudioVideoSwitcherToggleView;->setVisibility(I)V"
internal val audioVideoSwitchToggleFingerprint = legacyFingerprint(
name = "audioVideoSwitchToggleFingerprint",
@ -33,7 +33,9 @@ internal val audioVideoSwitchToggleFingerprint = legacyFingerprint(
customFingerprint = { method, _ ->
method.indexOfFirstInstruction {
opcode == Opcode.INVOKE_VIRTUAL &&
getReference<MethodReference>()?.toString() == AUDIO_VIDEO_SWITCH_TOGGLE_VISIBILITY
getReference<MethodReference>()
?.toString()
?.endsWith(AUDIO_VIDEO_SWITCH_TOGGLE_VISIBILITY) == true
} >= 0
}
)

View File

@ -799,7 +799,7 @@ val playerComponentsPatch = bytecodePatch(
val reference = (instruction as? ReferenceInstruction)?.reference
instruction.opcode == Opcode.INVOKE_VIRTUAL &&
reference is MethodReference &&
reference.toString() == AUDIO_VIDEO_SWITCH_TOGGLE_VISIBILITY
reference.toString().endsWith(AUDIO_VIDEO_SWITCH_TOGGLE_VISIBILITY)
}
.map { (index, _) -> index }
.reversed()
@ -995,7 +995,7 @@ val playerComponentsPatch = bytecodePatch(
val reference = getReference<MethodReference>()
opcode == Opcode.INVOKE_INTERFACE &&
reference?.returnType == "Z" &&
reference.parameterTypes.size == 0
reference.parameterTypes.isEmpty()
} + 1
val targetRegister =
getInstruction<OneRegisterInstruction>(targetIndex).registerA

View File

@ -14,7 +14,8 @@ internal object Constants {
"6.42.55", // This is the latest version that supports Android 7.0
"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 latest version supported by the RVX 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.
)
)
}

View File

@ -1,26 +1,33 @@
package app.revanced.patches.music.utils.videotype
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.Method
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
internal val videoTypeFingerprint = legacyFingerprint(
name = "videoTypeFingerprint",
returnType = "L",
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
parameters = listOf("L"),
opcodes = listOf(
Opcode.IGET,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.IF_NEZ,
Opcode.SGET_OBJECT,
Opcode.GOTO,
Opcode.SGET_OBJECT
)
customFingerprint = { method, _ ->
indexOfGetEnumInstruction(method) >= 0
}
)
internal fun indexOfGetEnumInstruction(method: Method) =
method.indexOfFirstInstruction {
val reference = getReference<MethodReference>()
opcode == Opcode.INVOKE_STATIC &&
reference?.name == "a" &&
reference.parameterTypes.firstOrNull() == "I" &&
reference.definingClass == reference.returnType
}
internal val videoTypeParentFingerprint = legacyFingerprint(
name = "videoTypeParentFingerprint",
returnType = "Z",

View File

@ -4,8 +4,14 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWith
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.music.utils.extension.Constants.UTILS_PATH
import app.revanced.util.fingerprint.matchOrThrow
import app.revanced.util.fingerprint.methodOrThrow
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import com.android.tools.smali.dexlib2.Opcode
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.reference.FieldReference
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
private const val EXTENSION_CLASS_DESCRIPTOR =
"$UTILS_PATH/VideoTypeHookPatch;"
@ -17,22 +23,27 @@ val videoTypeHookPatch = bytecodePatch(
execute {
videoTypeFingerprint.matchOrThrow(videoTypeParentFingerprint).let {
it.method.apply {
val insertIndex = it.patternMatch!!.startIndex + 3
val referenceIndex = insertIndex + 1
val referenceInstruction =
getInstruction<ReferenceInstruction>(referenceIndex).reference
addInstructionsWithLabels(
insertIndex, """
if-nez p0, :dismiss
sget-object p0, $referenceInstruction
:dismiss
invoke-static {p0}, $EXTENSION_CLASS_DESCRIPTOR->setVideoType(Ljava/lang/Enum;)V
"""
)
videoTypeFingerprint.methodOrThrow(videoTypeParentFingerprint).apply {
val getEnumIndex = indexOfGetEnumInstruction(this)
val enumClass = (getInstruction<ReferenceInstruction>(getEnumIndex).reference as MethodReference).definingClass
val referenceIndex = indexOfFirstInstructionOrThrow(getEnumIndex) {
opcode == Opcode.SGET_OBJECT &&
getReference<FieldReference>()?.type == enumClass
}
val referenceInstruction =
getInstruction<ReferenceInstruction>(referenceIndex).reference
val insertIndex = indexOfFirstInstructionOrThrow(getEnumIndex, Opcode.IF_NEZ)
val insertRegister = getInstruction<OneRegisterInstruction>(insertIndex).registerA
addInstructionsWithLabels(
insertIndex, """
if-nez v$insertRegister, :dismiss
sget-object v$insertRegister, $referenceInstruction
:dismiss
invoke-static {v$insertRegister}, $EXTENSION_CLASS_DESCRIPTOR->setVideoType(Ljava/lang/Enum;)V
"""
)
}
}
}

View File

@ -26,12 +26,6 @@ internal val videoIdFingerprint = legacyFingerprint(
returnType = "V",
parameters = listOf("L", "Ljava/lang/String;"),
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
opcodes = listOf(
Opcode.INVOKE_INTERFACE_RANGE,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_INTERFACE_RANGE,
Opcode.MOVE_RESULT_OBJECT,
),
strings = listOf("Null initialPlayabilityStatus")
)

View File

@ -191,7 +191,12 @@ val videoInformationPatch = bytecodePatch(
*/
videoIdFingerprint.matchOrThrow().let {
it.method.apply {
val playerResponseModelIndex = it.patternMatch!!.startIndex
val playerResponseModelIndex = indexOfFirstInstructionOrThrow {
val reference = getReference<MethodReference>()
(opcode == Opcode.INVOKE_INTERFACE_RANGE || opcode == Opcode.INVOKE_INTERFACE) &&
reference?.returnType == "Ljava/lang/String;" &&
reference.parameterTypes.isEmpty()
}
PLAYER_RESPONSE_MODEL_CLASS_DESCRIPTOR =
getInstruction(playerResponseModelIndex)

View File

@ -2,9 +2,19 @@ package app.revanced.patches.music.video.playerresponse
import app.revanced.util.fingerprint.legacyFingerprint
import app.revanced.util.or
import app.revanced.util.parametersEqual
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
private val PLAYER_PARAMETER_STARTS_WITH_PARAMETER_LIST = listOf(
"Ljava/lang/String;", // VideoId.
"[B",
"Ljava/lang/String;", // Player parameters proto buffer.
"Ljava/lang/String;", // PlaylistId.
"I", // PlaylistIndex.
"I"
)
/**
* For targets 7.03 and later.
*/
@ -12,23 +22,21 @@ internal val playerParameterBuilderFingerprint = legacyFingerprint(
name = "playerParameterBuilderFingerprint",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
returnType = "L",
parameters = listOf(
"Ljava/lang/String;", // VideoId.
"[B",
"Ljava/lang/String;", // Player parameters proto buffer.
"Ljava/lang/String;", // PlaylistId.
"I", // PlaylistIndex.
"I",
"L",
"Ljava/util/Set;",
"Ljava/lang/String;",
"Ljava/lang/String;",
"L",
"Z",
"Z",
"Z", // Appears to indicate if the video id is being opened or is currently playing.
),
strings = listOf("psps")
strings = listOf("psps"),
customFingerprint = custom@{ method, _ ->
val parameterTypes = method.parameterTypes
val parameterSize = parameterTypes.size
if (parameterSize < 13) {
return@custom false
}
val startsWithMethodParameterList = parameterTypes.slice(0..5)
parametersEqual(
PLAYER_PARAMETER_STARTS_WITH_PARAMETER_LIST,
startsWithMethodParameterList
)
}
)
/**