feat(YouTube): add support version 19.23.40, drop support version 19.20.35, 19.21.40

This commit is contained in:
inotia00 2024-06-23 13:46:27 +09:00
parent 7a0b3033bb
commit b99c6218f7
10 changed files with 178 additions and 92 deletions

View File

@ -7,6 +7,7 @@ import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patches.youtube.misc.backgroundplayback.fingerprints.BackgroundPlaybackManagerFingerprint import app.revanced.patches.youtube.misc.backgroundplayback.fingerprints.BackgroundPlaybackManagerFingerprint
import app.revanced.patches.youtube.misc.backgroundplayback.fingerprints.BackgroundPlaybackSettingsFingerprint import app.revanced.patches.youtube.misc.backgroundplayback.fingerprints.BackgroundPlaybackSettingsFingerprint
import app.revanced.patches.youtube.misc.backgroundplayback.fingerprints.KidsBackgroundPlaybackPolicyControllerFingerprint import app.revanced.patches.youtube.misc.backgroundplayback.fingerprints.KidsBackgroundPlaybackPolicyControllerFingerprint
import app.revanced.patches.youtube.misc.backgroundplayback.fingerprints.KidsBackgroundPlaybackPolicyControllerParentFingerprint
import app.revanced.patches.youtube.misc.backgroundplayback.fingerprints.PiPControllerFingerprint import app.revanced.patches.youtube.misc.backgroundplayback.fingerprints.PiPControllerFingerprint
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
import app.revanced.patches.youtube.utils.integrations.Constants.MISC_PATH import app.revanced.patches.youtube.utils.integrations.Constants.MISC_PATH
@ -31,7 +32,7 @@ object BackgroundPlaybackPatch : BaseBytecodePatch(
fingerprints = setOf( fingerprints = setOf(
BackgroundPlaybackManagerFingerprint, BackgroundPlaybackManagerFingerprint,
BackgroundPlaybackSettingsFingerprint, BackgroundPlaybackSettingsFingerprint,
KidsBackgroundPlaybackPolicyControllerFingerprint, KidsBackgroundPlaybackPolicyControllerParentFingerprint,
PiPControllerFingerprint PiPControllerFingerprint
) )
) { ) {
@ -66,6 +67,10 @@ object BackgroundPlaybackPatch : BaseBytecodePatch(
} }
// Force allowing background play for videos labeled for kids. // Force allowing background play for videos labeled for kids.
KidsBackgroundPlaybackPolicyControllerFingerprint.resolve(
context,
KidsBackgroundPlaybackPolicyControllerParentFingerprint.resultOrThrow().classDef
)
KidsBackgroundPlaybackPolicyControllerFingerprint.resultOrThrow().mutableMethod.addInstruction( KidsBackgroundPlaybackPolicyControllerFingerprint.resultOrThrow().mutableMethod.addInstruction(
0, 0,
"return-void" "return-void"

View File

@ -3,40 +3,10 @@ package app.revanced.patches.youtube.misc.backgroundplayback.fingerprints
import app.revanced.patcher.extensions.or import app.revanced.patcher.extensions.or
import app.revanced.util.fingerprint.LiteralValueFingerprint import app.revanced.util.fingerprint.LiteralValueFingerprint
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
internal object KidsBackgroundPlaybackPolicyControllerFingerprint : LiteralValueFingerprint( internal object KidsBackgroundPlaybackPolicyControllerFingerprint : LiteralValueFingerprint(
returnType = "V", returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("I", "L", "L"), parameters = listOf("I", "L", "L"),
opcodes = listOf(
Opcode.IF_EQZ,
Opcode.SGET_OBJECT,
Opcode.IF_NE,
Opcode.CONST_4,
Opcode.IPUT_BOOLEAN,
Opcode.IF_EQZ,
Opcode.IGET,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT,
Opcode.IF_NEZ,
Opcode.GOTO,
Opcode.CONST_4,
Opcode.IF_NE,
Opcode.CONST_4,
Opcode.IF_NE,
Opcode.SGET_OBJECT,
Opcode.IF_NE,
Opcode.IGET,
Opcode.CONST_4,
Opcode.IF_NE,
Opcode.IGET_OBJECT,
Opcode.SGET_OBJECT,
Opcode.IF_EQ,
Opcode.GOTO,
Opcode.IGET_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.RETURN_VOID
),
literalSupplier = { 5 } literalSupplier = { 5 }
) )

View File

@ -0,0 +1,21 @@
package app.revanced.patches.youtube.misc.backgroundplayback.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
internal object KidsBackgroundPlaybackPolicyControllerParentFingerprint : MethodFingerprint(
returnType = "L",
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
parameters = listOf("Lcom/google/android/libraries/youtube/innertube/model/player/PlayerResponseModel;"),
customFingerprint = { methodDef, _ ->
methodDef.indexOfFirstInstruction {
opcode == Opcode.SGET_OBJECT
&& getReference<FieldReference>()?.name == "miniplayerRenderer"
} >= 0
}
)

View File

@ -13,8 +13,7 @@ object Constants {
"18.48.39", // This is the last version that do not use Rolling Number. "18.48.39", // This is the last version that do not use Rolling Number.
"19.05.36", // This is the last version with the least YouTube experimental flag. "19.05.36", // This is the last version with the least YouTube experimental flag.
"19.16.39", // This is the last version that supports the 'Restore old seekbar thumbnails' setting. "19.16.39", // This is the last version that supports the 'Restore old seekbar thumbnails' setting.
"19.20.35", // This is the last version that play icon in the Miniplayer is not giant. "19.23.40", // This is the latest version supported by the RVX patch.
"19.21.40", // This is the latest version supported by the RVX patch.
) )
) )
) )

View File

@ -8,6 +8,5 @@ import com.android.tools.smali.dexlib2.AccessFlags
internal object InitializeButtonsFingerprint : LiteralValueFingerprint( internal object InitializeButtonsFingerprint : LiteralValueFingerprint(
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
returnType = "V", returnType = "V",
parameters = emptyList(),
literalSupplier = { ImageOnlyTab } literalSupplier = { ImageOnlyTab }
) )

View File

@ -97,6 +97,8 @@ object SettingsPatch : BaseResourcePatch(
internal var upward1849 = false internal var upward1849 = false
internal var upward1902 = false internal var upward1902 = false
internal var upward1912 = false internal var upward1912 = false
internal var upward1920 = false
internal var upward1923 = false
override fun execute(context: ResourceContext) { override fun execute(context: ResourceContext) {
@ -285,6 +287,8 @@ object SettingsPatch : BaseResourcePatch(
upward1849 = 235000000 <= playServicesVersion upward1849 = 235000000 <= playServicesVersion
upward1902 = 240204000 < playServicesVersion upward1902 = 240204000 < playServicesVersion
upward1912 = 241302000 <= playServicesVersion upward1912 = 241302000 <= playServicesVersion
upward1920 = 242099000 <= playServicesVersion
upward1923 = 242402000 <= playServicesVersion
break break
} }

View File

@ -33,9 +33,8 @@ import app.revanced.patches.youtube.video.playback.fingerprints.QualitySetterFin
import app.revanced.patches.youtube.video.videoid.VideoIdPatch import app.revanced.patches.youtube.video.videoid.VideoIdPatch
import app.revanced.util.getReference import app.revanced.util.getReference
import app.revanced.util.getStringInstructionIndex import app.revanced.util.getStringInstructionIndex
import app.revanced.util.getTargetIndex
import app.revanced.util.getTargetIndexOrThrow import app.revanced.util.getTargetIndexOrThrow
import app.revanced.util.indexOfFirstInstruction import app.revanced.util.getWalkerMethod
import app.revanced.util.indexOfFirstInstructionOrThrow import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.patch.BaseBytecodePatch import app.revanced.util.patch.BaseBytecodePatch
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
@ -44,6 +43,7 @@ import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction 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.FieldReference
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
import com.android.tools.smali.dexlib2.util.MethodUtil import com.android.tools.smali.dexlib2.util.MethodUtil
@Suppress("unused") @Suppress("unused")
@ -108,6 +108,15 @@ object VideoPlaybackPatch : BaseBytecodePatch(
// region patch for disable HDR video // region patch for disable HDR video
HDRCapabilityFingerprint.resultOrThrow().mutableMethod.apply { HDRCapabilityFingerprint.resultOrThrow().mutableMethod.apply {
val stringIndex = getStringInstructionIndex("av1_profile_main_10_hdr_10_plus_supported")
val walkerIndex = indexOfFirstInstructionOrThrow(stringIndex) {
val reference = getReference<MethodReference>()
reference?.parameterTypes == listOf("I", "Landroid/view/Display;")
&& reference.returnType == "Z"
}
val walkerMethod = getWalkerMethod(context, walkerIndex)
walkerMethod.apply {
addInstructionsWithLabels( addInstructionsWithLabels(
0, """ 0, """
invoke-static {}, $INTEGRATIONS_HDR_VIDEO_CLASS_DESCRIPTOR->disableHDRVideo()Z invoke-static {}, $INTEGRATIONS_HDR_VIDEO_CLASS_DESCRIPTOR->disableHDRVideo()Z
@ -117,6 +126,7 @@ object VideoPlaybackPatch : BaseBytecodePatch(
""", ExternalLabel("default", getInstruction(0)) """, ExternalLabel("default", getInstruction(0))
) )
} }
}
// endregion // endregion

View File

@ -1,9 +1,13 @@
package app.revanced.patches.youtube.video.playback.fingerprints package app.revanced.patches.youtube.video.playback.fingerprints
import app.revanced.util.fingerprint.MethodReferenceNameFingerprint import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
internal object HDRCapabilityFingerprint : MethodReferenceNameFingerprint( internal object HDRCapabilityFingerprint : MethodFingerprint(
returnType = "Z", accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("I", "Landroid/view/Display;"), strings = listOf(
reference = { "getSupportedHdrTypes" } "av1_profile_main_10_hdr_10_plus_supported",
"video/av01"
)
) )

View File

@ -8,6 +8,7 @@ import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patches.youtube.video.playerresponse.fingerprint.PlayerParameterBuilderFingerprint import app.revanced.patches.youtube.video.playerresponse.fingerprint.PlayerParameterBuilderFingerprint
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
import java.io.Closeable import java.io.Closeable
import kotlin.properties.Delegates
object PlayerResponseMethodHookPatch : object PlayerResponseMethodHookPatch :
BytecodePatch(setOf(PlayerParameterBuilderFingerprint)), BytecodePatch(setOf(PlayerParameterBuilderFingerprint)),
@ -17,57 +18,59 @@ object PlayerResponseMethodHookPatch :
// Parameter numbers of the patched method. // Parameter numbers of the patched method.
private var PARAMETER_VIDEO_ID = 1 private var PARAMETER_VIDEO_ID = 1
private var PARAMETER_PLAYER_PARAMETER = 3 private var PARAMETER_PLAYER_PARAMETER = 3
private var PARAMETER_IS_SHORT_AND_OPENING_OR_PLAYING = 11 private var PARAMETER_IS_SHORT_AND_OPENING_OR_PLAYING by Delegates.notNull<Int>()
private var freeRegister = 0 // Registers used to pass the parameters to integrations.
private var shouldApplyNewMethod = false private var playerResponseMethodCopyRegisters = false
private lateinit var REGISTER_VIDEO_ID : String
private lateinit var REGISTER_PLAYER_PARAMETER : String
private lateinit var REGISTER_IS_SHORT_AND_OPENING_OR_PLAYING : String
private lateinit var playerResponseMethod: MutableMethod private lateinit var playerResponseMethod: MutableMethod
private var numberOfInstructionsAdded = 0
override fun execute(context: BytecodeContext) { override fun execute(context: BytecodeContext) {
playerResponseMethod = PlayerParameterBuilderFingerprint.resultOrThrow().mutableMethod playerResponseMethod = PlayerParameterBuilderFingerprint
.resultOrThrow()
.mutableMethod
playerResponseMethod.apply { playerResponseMethod.apply {
freeRegister = implementation!!.registerCount - parameters.size - 2 PARAMETER_IS_SHORT_AND_OPENING_OR_PLAYING = parameters.size - 2
shouldApplyNewMethod = freeRegister > 2
if (shouldApplyNewMethod) { // On some app targets the method has too many registers pushing the parameters past v15.
PARAMETER_IS_SHORT_AND_OPENING_OR_PLAYING = freeRegister // If needed, move the parameters to 4-bit registers so they can be passed to integrations.
PARAMETER_PLAYER_PARAMETER = freeRegister - 2 playerResponseMethodCopyRegisters = implementation!!.registerCount -
PARAMETER_VIDEO_ID = freeRegister - 3 parameterTypes.size + PARAMETER_IS_SHORT_AND_OPENING_OR_PLAYING > 15
} }
if (playerResponseMethodCopyRegisters) {
REGISTER_VIDEO_ID = "v0"
REGISTER_PLAYER_PARAMETER = "v1"
REGISTER_IS_SHORT_AND_OPENING_OR_PLAYING = "v2"
} else {
REGISTER_VIDEO_ID = "p$PARAMETER_VIDEO_ID"
REGISTER_PLAYER_PARAMETER = "p$PARAMETER_PLAYER_PARAMETER"
REGISTER_IS_SHORT_AND_OPENING_OR_PLAYING = "p$PARAMETER_IS_SHORT_AND_OPENING_OR_PLAYING"
} }
} }
override fun close() { override fun close() {
fun hookVideoId(hook: Hook) { fun hookVideoId(hook: Hook) {
val instruction =
if (shouldApplyNewMethod)
"invoke-static {v$PARAMETER_VIDEO_ID, v$PARAMETER_IS_SHORT_AND_OPENING_OR_PLAYING}, $hook"
else
"invoke-static {p$PARAMETER_VIDEO_ID, p$PARAMETER_IS_SHORT_AND_OPENING_OR_PLAYING}, $hook"
playerResponseMethod.addInstruction( playerResponseMethod.addInstruction(
0, instruction 0,
"invoke-static {$REGISTER_VIDEO_ID, $REGISTER_IS_SHORT_AND_OPENING_OR_PLAYING}, $hook"
) )
numberOfInstructionsAdded++
} }
fun hookPlayerParameter(hook: Hook) { fun hookPlayerParameter(hook: Hook) {
val instruction =
if (shouldApplyNewMethod)
"""
invoke-static {v$PARAMETER_VIDEO_ID, v$PARAMETER_PLAYER_PARAMETER, v$PARAMETER_IS_SHORT_AND_OPENING_OR_PLAYING}, $hook
move-result-object p3
"""
else
"""
invoke-static {p$PARAMETER_VIDEO_ID, p$PARAMETER_PLAYER_PARAMETER, p$PARAMETER_IS_SHORT_AND_OPENING_OR_PLAYING}, $hook
move-result-object p$PARAMETER_PLAYER_PARAMETER
"""
playerResponseMethod.addInstructions( playerResponseMethod.addInstructions(
0, 0, """
instruction invoke-static {$REGISTER_VIDEO_ID, $REGISTER_PLAYER_PARAMETER, $REGISTER_IS_SHORT_AND_OPENING_OR_PLAYING}, $hook
move-result-object $REGISTER_PLAYER_PARAMETER
"""
) )
numberOfInstructionsAdded += 2
} }
// Reverse the order in order to preserve insertion order of the hooks. // Reverse the order in order to preserve insertion order of the hooks.
@ -80,14 +83,24 @@ object PlayerResponseMethodHookPatch :
videoIdHooks.forEach(::hookVideoId) videoIdHooks.forEach(::hookVideoId)
beforeVideoIdHooks.forEach(::hookPlayerParameter) beforeVideoIdHooks.forEach(::hookPlayerParameter)
if (shouldApplyNewMethod) { if (playerResponseMethodCopyRegisters) {
playerResponseMethod.addInstructions( playerResponseMethod.apply {
addInstructions(
0, """ 0, """
move-object v$PARAMETER_VIDEO_ID, p1 move-object/from16 $REGISTER_VIDEO_ID, p$PARAMETER_VIDEO_ID
move-object v$PARAMETER_PLAYER_PARAMETER, p3 move-object/from16 $REGISTER_PLAYER_PARAMETER, p$PARAMETER_PLAYER_PARAMETER
move/from16 v$PARAMETER_IS_SHORT_AND_OPENING_OR_PLAYING, p11 move/from16 $REGISTER_IS_SHORT_AND_OPENING_OR_PLAYING, p$PARAMETER_IS_SHORT_AND_OPENING_OR_PLAYING
""" """,
) )
numberOfInstructionsAdded += 3
// Move the modified register back.
addInstruction(
numberOfInstructionsAdded,
"move-object/from16 p$PARAMETER_PLAYER_PARAMETER, $REGISTER_PLAYER_PARAMETER"
)
}
} }
} }

View File

@ -2,18 +2,67 @@ package app.revanced.patches.youtube.video.playerresponse.fingerprint
import app.revanced.patcher.extensions.or import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patches.youtube.video.playerresponse.fingerprint.PlayerParameterBuilderFingerprint.ENDS_WITH_PARAMETER_LIST
import app.revanced.patches.youtube.video.playerresponse.fingerprint.PlayerParameterBuilderFingerprint.STARTS_WITH_PARAMETER_LIST
import app.revanced.patches.youtube.video.playerresponse.fingerprint.PlayerParameterBuilderFingerprint.parametersEqual
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
internal object PlayerParameterBuilderFingerprint : MethodFingerprint( internal object PlayerParameterBuilderFingerprint : MethodFingerprint(
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
returnType = "L", returnType = "L",
parameters = listOf( // 19.22 and earlier parameters are:
// "Ljava/lang/String;", // VideoId.
// "[B",
// "Ljava/lang/String;", // Player parameters proto buffer.
// "Ljava/lang/String;", // PlaylistId.
// "I",
// "I",
// "Ljava/util/Set;",
// "Ljava/lang/String;",
// "Ljava/lang/String;",
// "L",
// "Z", // Appears to indicate if the video id is being opened or is currently playing.
// "Z",
// "Z"
// 19.23+ parameters are:
// "Ljava/lang/String;", // VideoId.
// "[B",
// "Ljava/lang/String;", // Player parameters proto buffer.
// "Ljava/lang/String;", // PlaylistId.
// "I",
// "I",
// "L",
// "Ljava/util/Set;",
// "Ljava/lang/String;",
// "Ljava/lang/String;",
// "L",
// "Z", // Appears to indicate if the video id is being opened or is currently playing.
// "Z",
// "Z"
customFingerprint = custom@{ methodDef, _ ->
val parameterTypes = methodDef.parameterTypes
val parameterSize = parameterTypes.size
if (parameterSize != 13 && parameterSize != 14) {
return@custom false
}
val startsWithMethodParameterList = parameterTypes.slice(0..5)
val endsWithMethodParameterList = parameterTypes.slice(parameterSize - 7..<parameterSize)
parametersEqual(STARTS_WITH_PARAMETER_LIST, startsWithMethodParameterList)
&& parametersEqual(ENDS_WITH_PARAMETER_LIST, endsWithMethodParameterList)
}
) {
val STARTS_WITH_PARAMETER_LIST = listOf(
"Ljava/lang/String;", // VideoId. "Ljava/lang/String;", // VideoId.
"[B", "[B",
"Ljava/lang/String;", // Player parameters proto buffer. "Ljava/lang/String;", // Player parameters proto buffer.
"Ljava/lang/String;", // PlaylistId. "Ljava/lang/String;", // PlaylistId.
"I", "I",
"I", "I"
)
val ENDS_WITH_PARAMETER_LIST = listOf(
"Ljava/util/Set;", "Ljava/util/Set;",
"Ljava/lang/String;", "Ljava/lang/String;",
"Ljava/lang/String;", "Ljava/lang/String;",
@ -22,4 +71,16 @@ internal object PlayerParameterBuilderFingerprint : MethodFingerprint(
"Z", "Z",
"Z" "Z"
) )
)
fun parametersEqual(
parameters1: Iterable<CharSequence>,
parameters2: Iterable<CharSequence>
): Boolean {
if (parameters1.count() != parameters2.count()) return false
val iterator1 = parameters1.iterator()
parameters2.forEach {
if (!it.startsWith(iterator1.next())) return false
}
return true
}
}