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.BackgroundPlaybackSettingsFingerprint
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.utils.compatibility.Constants.COMPATIBLE_PACKAGE
import app.revanced.patches.youtube.utils.integrations.Constants.MISC_PATH
@ -31,7 +32,7 @@ object BackgroundPlaybackPatch : BaseBytecodePatch(
fingerprints = setOf(
BackgroundPlaybackManagerFingerprint,
BackgroundPlaybackSettingsFingerprint,
KidsBackgroundPlaybackPolicyControllerFingerprint,
KidsBackgroundPlaybackPolicyControllerParentFingerprint,
PiPControllerFingerprint
)
) {
@ -66,6 +67,10 @@ object BackgroundPlaybackPatch : BaseBytecodePatch(
}
// Force allowing background play for videos labeled for kids.
KidsBackgroundPlaybackPolicyControllerFingerprint.resolve(
context,
KidsBackgroundPlaybackPolicyControllerParentFingerprint.resultOrThrow().classDef
)
KidsBackgroundPlaybackPolicyControllerFingerprint.resultOrThrow().mutableMethod.addInstruction(
0,
"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.util.fingerprint.LiteralValueFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
internal object KidsBackgroundPlaybackPolicyControllerFingerprint : LiteralValueFingerprint(
returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
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 }
)

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.
"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.20.35", // This is the last version that play icon in the Miniplayer is not giant.
"19.21.40", // This is the latest version supported by the RVX patch.
"19.23.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(
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
returnType = "V",
parameters = emptyList(),
literalSupplier = { ImageOnlyTab }
)

View File

@ -97,6 +97,8 @@ object SettingsPatch : BaseResourcePatch(
internal var upward1849 = false
internal var upward1902 = false
internal var upward1912 = false
internal var upward1920 = false
internal var upward1923 = false
override fun execute(context: ResourceContext) {
@ -285,6 +287,8 @@ object SettingsPatch : BaseResourcePatch(
upward1849 = 235000000 <= playServicesVersion
upward1902 = 240204000 < playServicesVersion
upward1912 = 241302000 <= playServicesVersion
upward1920 = 242099000 <= playServicesVersion
upward1923 = 242402000 <= playServicesVersion
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.util.getReference
import app.revanced.util.getStringInstructionIndex
import app.revanced.util.getTargetIndex
import app.revanced.util.getTargetIndexOrThrow
import app.revanced.util.indexOfFirstInstruction
import app.revanced.util.getWalkerMethod
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.patch.BaseBytecodePatch
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.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.util.MethodUtil
@Suppress("unused")
@ -108,14 +108,24 @@ object VideoPlaybackPatch : BaseBytecodePatch(
// region patch for disable HDR video
HDRCapabilityFingerprint.resultOrThrow().mutableMethod.apply {
addInstructionsWithLabels(
0, """
invoke-static {}, $INTEGRATIONS_HDR_VIDEO_CLASS_DESCRIPTOR->disableHDRVideo()Z
move-result v0
if-nez v0, :default
return v0
""", ExternalLabel("default", getInstruction(0))
)
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(
0, """
invoke-static {}, $INTEGRATIONS_HDR_VIDEO_CLASS_DESCRIPTOR->disableHDRVideo()Z
move-result v0
if-nez v0, :default
return v0
""", ExternalLabel("default", getInstruction(0))
)
}
}
// endregion

View File

@ -1,9 +1,13 @@
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(
returnType = "Z",
parameters = listOf("I", "Landroid/view/Display;"),
reference = { "getSupportedHdrTypes" }
internal object HDRCapabilityFingerprint : MethodFingerprint(
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
strings = listOf(
"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.util.resultOrThrow
import java.io.Closeable
import kotlin.properties.Delegates
object PlayerResponseMethodHookPatch :
BytecodePatch(setOf(PlayerParameterBuilderFingerprint)),
@ -17,57 +18,59 @@ object PlayerResponseMethodHookPatch :
// Parameter numbers of the patched method.
private var PARAMETER_VIDEO_ID = 1
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
private var shouldApplyNewMethod = false
// Registers used to pass the parameters to integrations.
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 var numberOfInstructionsAdded = 0
override fun execute(context: BytecodeContext) {
playerResponseMethod = PlayerParameterBuilderFingerprint.resultOrThrow().mutableMethod
playerResponseMethod = PlayerParameterBuilderFingerprint
.resultOrThrow()
.mutableMethod
playerResponseMethod.apply {
freeRegister = implementation!!.registerCount - parameters.size - 2
shouldApplyNewMethod = freeRegister > 2
if (shouldApplyNewMethod) {
PARAMETER_IS_SHORT_AND_OPENING_OR_PLAYING = freeRegister
PARAMETER_PLAYER_PARAMETER = freeRegister - 2
PARAMETER_VIDEO_ID = freeRegister - 3
}
PARAMETER_IS_SHORT_AND_OPENING_OR_PLAYING = parameters.size - 2
// On some app targets the method has too many registers pushing the parameters past v15.
// If needed, move the parameters to 4-bit registers so they can be passed to integrations.
playerResponseMethodCopyRegisters = implementation!!.registerCount -
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() {
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(
0, instruction
0,
"invoke-static {$REGISTER_VIDEO_ID, $REGISTER_IS_SHORT_AND_OPENING_OR_PLAYING}, $hook"
)
numberOfInstructionsAdded++
}
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(
0,
instruction
0, """
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.
@ -80,14 +83,24 @@ object PlayerResponseMethodHookPatch :
videoIdHooks.forEach(::hookVideoId)
beforeVideoIdHooks.forEach(::hookPlayerParameter)
if (shouldApplyNewMethod) {
playerResponseMethod.addInstructions(
0, """
move-object v$PARAMETER_VIDEO_ID, p1
move-object v$PARAMETER_PLAYER_PARAMETER, p3
move/from16 v$PARAMETER_IS_SHORT_AND_OPENING_OR_PLAYING, p11
"""
)
if (playerResponseMethodCopyRegisters) {
playerResponseMethod.apply {
addInstructions(
0, """
move-object/from16 $REGISTER_VIDEO_ID, p$PARAMETER_VIDEO_ID
move-object/from16 $REGISTER_PLAYER_PARAMETER, p$PARAMETER_PLAYER_PARAMETER
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.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
internal object PlayerParameterBuilderFingerprint : MethodFingerprint(
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
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.
"[B",
"Ljava/lang/String;", // Player parameters proto buffer.
"Ljava/lang/String;", // PlaylistId.
"I",
"I",
"I"
)
val ENDS_WITH_PARAMETER_LIST = listOf(
"Ljava/util/Set;",
"Ljava/lang/String;",
"Ljava/lang/String;",
@ -22,4 +71,16 @@ internal object PlayerParameterBuilderFingerprint : MethodFingerprint(
"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
}
}