From b99c6218f7a22ad7f37aa77109e47610065d71b2 Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Sun, 23 Jun 2024 13:46:27 +0900 Subject: [PATCH] feat(YouTube): add support version `19.23.40`, drop support version `19.20.35`, `19.21.40` --- .../BackgroundPlaybackPatch.kt | 7 +- ...oundPlaybackPolicyControllerFingerprint.kt | 30 ------ ...aybackPolicyControllerParentFingerprint.kt | 21 +++++ .../youtube/utils/compatibility/Constants.kt | 3 +- .../InitializeButtonsFingerprint.kt | 1 - .../youtube/utils/settings/SettingsPatch.kt | 4 + .../video/playback/VideoPlaybackPatch.kt | 30 ++++-- .../fingerprints/HDRCapabilityFingerprint.kt | 14 ++- .../PlayerResponseMethodHookPatch.kt | 93 +++++++++++-------- .../PlayerParameterBuilderFingerprint.kt | 67 ++++++++++++- 10 files changed, 178 insertions(+), 92 deletions(-) create mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/fingerprints/KidsBackgroundPlaybackPolicyControllerParentFingerprint.kt diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/BackgroundPlaybackPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/BackgroundPlaybackPatch.kt index 29f0cd678..4d8d8b264 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/BackgroundPlaybackPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/BackgroundPlaybackPatch.kt @@ -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" diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/fingerprints/KidsBackgroundPlaybackPolicyControllerFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/fingerprints/KidsBackgroundPlaybackPolicyControllerFingerprint.kt index 0b24941e5..80da2fe0d 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/fingerprints/KidsBackgroundPlaybackPolicyControllerFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/fingerprints/KidsBackgroundPlaybackPolicyControllerFingerprint.kt @@ -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 } ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/fingerprints/KidsBackgroundPlaybackPolicyControllerParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/fingerprints/KidsBackgroundPlaybackPolicyControllerParentFingerprint.kt new file mode 100644 index 000000000..9f793667a --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/fingerprints/KidsBackgroundPlaybackPolicyControllerParentFingerprint.kt @@ -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()?.name == "miniplayerRenderer" + } >= 0 + } +) diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/compatibility/Constants.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/compatibility/Constants.kt index 6e5d30a38..02359d0f2 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/utils/compatibility/Constants.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/utils/compatibility/Constants.kt @@ -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. ) ) ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/fingerprints/InitializeButtonsFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/fingerprints/InitializeButtonsFingerprint.kt index e5c160ea1..0b054f08d 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/utils/fingerprints/InitializeButtonsFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/utils/fingerprints/InitializeButtonsFingerprint.kt @@ -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 } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/settings/SettingsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/settings/SettingsPatch.kt index d3abe6fc8..89474f468 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/utils/settings/SettingsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/utils/settings/SettingsPatch.kt @@ -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 } diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/playback/VideoPlaybackPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/playback/VideoPlaybackPatch.kt index 62b50b1af..4192063c1 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/video/playback/VideoPlaybackPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/playback/VideoPlaybackPatch.kt @@ -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() + 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 diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/playback/fingerprints/HDRCapabilityFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/playback/fingerprints/HDRCapabilityFingerprint.kt index 8b9896e2c..4b3bb4f75 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/video/playback/fingerprints/HDRCapabilityFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/playback/fingerprints/HDRCapabilityFingerprint.kt @@ -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" + ) ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/PlayerResponseMethodHookPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/PlayerResponseMethodHookPatch.kt index 2a0ff50db..9d52ae2ae 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/PlayerResponseMethodHookPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/PlayerResponseMethodHookPatch.kt @@ -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() - 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" + ) + } } } diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/fingerprint/PlayerParameterBuilderFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/fingerprint/PlayerParameterBuilderFingerprint.kt index 2fad7540b..0cb4f6f3d 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/fingerprint/PlayerParameterBuilderFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/fingerprint/PlayerParameterBuilderFingerprint.kt @@ -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.., + parameters2: Iterable + ): Boolean { + if (parameters1.count() != parameters2.count()) return false + val iterator1 = parameters1.iterator() + parameters2.forEach { + if (!it.startsWith(iterator1.next())) return false + } + return true + } +} \ No newline at end of file