diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/information/VideoInformationPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/information/VideoInformationPatch.kt index 511bd8f79..6be7d654c 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/video/information/VideoInformationPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/information/VideoInformationPatch.kt @@ -14,7 +14,6 @@ import app.revanced.patcher.util.proxy.mutableTypes.MutableClass import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable import app.revanced.patcher.util.smali.toInstructions -import app.revanced.patches.youtube.utils.fingerprints.OrganicPlaybackContextModelFingerprint import app.revanced.patches.youtube.utils.fingerprints.VideoEndFingerprint import app.revanced.patches.youtube.utils.integrations.Constants.SHARED_PATH import app.revanced.patches.youtube.utils.playertype.PlayerTypeHookPatch @@ -26,6 +25,7 @@ import app.revanced.patches.youtube.video.information.fingerprints.OnPlaybackSpe import app.revanced.patches.youtube.video.information.fingerprints.PlaybackInitializationFingerprint import app.revanced.patches.youtube.video.information.fingerprints.PlaybackSpeedClassFingerprint import app.revanced.patches.youtube.video.information.fingerprints.PlayerControllerSetTimeReferenceFingerprint +import app.revanced.patches.youtube.video.information.fingerprints.SeekRelativeFingerprint import app.revanced.patches.youtube.video.information.fingerprints.VideoIdFingerprint import app.revanced.patches.youtube.video.information.fingerprints.VideoIdFingerprintBackgroundPlay import app.revanced.patches.youtube.video.information.fingerprints.VideoIdFingerprintShorts @@ -36,6 +36,7 @@ import app.revanced.patches.youtube.video.information.fingerprints.VideoTitleFin import app.revanced.patches.youtube.video.playerresponse.PlayerResponseMethodHookPatch import app.revanced.patches.youtube.video.videoid.VideoIdPatch import app.revanced.util.addFieldAndInstructions +import app.revanced.util.alsoResolve import app.revanced.util.getReference import app.revanced.util.getTargetIndexOrThrow import app.revanced.util.getTargetIndexReversedOrThrow @@ -71,7 +72,6 @@ object VideoInformationPatch : BytecodePatch( ChannelNameFingerprint, MdxPlayerDirectorSetVideoStageFingerprint, OnPlaybackSpeedItemClickFingerprint, - OrganicPlaybackContextModelFingerprint, PlaybackInitializationFingerprint, PlaybackSpeedClassFingerprint, PlayerControllerSetTimeReferenceFingerprint, @@ -117,10 +117,11 @@ object VideoInformationPatch : BytecodePatch( /** * Used in [VideoEndFingerprint] and [MdxPlayerDirectorSetVideoStageFingerprint]. * Since both classes are inherited from the same class, - * [VideoEndFingerprint] and [MdxPlayerDirectorSetVideoStageFingerprint] always have the same [seekSourceEnumType] and [seekSourceMethodName]. + * [VideoEndFingerprint] and [MdxPlayerDirectorSetVideoStageFingerprint] always have the same [seekSourceEnumType], [seekSourceMethodName] and [seekRelativeSourceMethodName]. */ private var seekSourceEnumType = "" private var seekSourceMethodName = "" + private var seekRelativeSourceMethodName = "" private lateinit var videoInformationMutableClass: MutableClass private lateinit var context: BytecodeContext @@ -138,28 +139,18 @@ object VideoInformationPatch : BytecodePatch( internal lateinit var speedSelectionInsertMethod: MutableMethod internal lateinit var videoEndMethod: MutableMethod - private fun getSeekToConstructorMethod( + private fun addSeekInterfaceMethods( result: MethodFingerprintResult, + seekMethodName: String, methodName: String, + fieldMethodName: String, fieldName: String - ): Pair { + ) { result.mutableMethod.apply { - val constructorMethod = - result.mutableClass.methods.first { method -> MethodUtil.isConstructor(method) } - - val constructorInsertIndex = indexOfFirstInstructionOrThrow { - opcode == Opcode.INVOKE_DIRECT && getReference()?.name == "" - } + 1 - - if (seekSourceEnumType.isEmpty() && seekSourceMethodName.isEmpty()) { - seekSourceEnumType = parameterTypes[1].toString() - seekSourceMethodName = name - } - result.mutableClass.methods.add( ImmutableMethod( definingClass, - "seekTo", + fieldMethodName, listOf(ImmutableMethodParameter("J", annotations, "time")), "Z", AccessFlags.PUBLIC or AccessFlags.FINAL, @@ -167,8 +158,9 @@ object VideoInformationPatch : BytecodePatch( null, ImmutableMethodImplementation( 4, """ + # first enum (field a) is SEEK_SOURCE_UNKNOWN sget-object v0, $seekSourceEnumType->a:$seekSourceEnumType - invoke-virtual {p0, p1, p2, v0}, ${definingClass}->$seekSourceMethodName(J$seekSourceEnumType)Z + invoke-virtual {p0, p1, p2, v0}, ${definingClass}->$seekMethodName(J$seekSourceEnumType)Z move-result p1 return p1 """.toInstructions(), @@ -181,7 +173,7 @@ object VideoInformationPatch : BytecodePatch( val smaliInstructions = """ if-eqz v0, :ignore - invoke-virtual {v0, p0, p1}, $definingClass->seekTo(J)Z + invoke-virtual {v0, p0, p1}, $definingClass->$fieldMethodName(J)Z move-result v0 return v0 :ignore @@ -197,8 +189,6 @@ object VideoInformationPatch : BytecodePatch( smaliInstructions, true ) - - return Pair(constructorMethod, constructorInsertIndex) } } @@ -208,16 +198,37 @@ object VideoInformationPatch : BytecodePatch( context.findClass(INTEGRATIONS_CLASS_DESCRIPTOR)!!.mutableClass VideoEndFingerprint.resultOrThrow().let { - val (playerConstructorMethod, playerConstructorInsertIndex) = - getSeekToConstructorMethod(it, "overrideVideoTime", "videoInformationClass") - - this.playerConstructorMethod = playerConstructorMethod - this.playerConstructorInsertIndex = playerConstructorInsertIndex - - // hook the player controller for use through integrations - onCreateHook(INTEGRATIONS_CLASS_DESCRIPTOR, "initialize") - it.mutableMethod.apply { + playerConstructorMethod = + it.mutableClass.methods.first { method -> MethodUtil.isConstructor(method) } + + playerConstructorInsertIndex = playerConstructorMethod.indexOfFirstInstructionOrThrow { + opcode == Opcode.INVOKE_DIRECT && getReference()?.name == "" + } + 1 + + // hook the player controller for use through integrations + onCreateHook(INTEGRATIONS_CLASS_DESCRIPTOR, "initialize") + + seekSourceEnumType = parameterTypes[1].toString() + seekSourceMethodName = name + seekRelativeSourceMethodName = SeekRelativeFingerprint.alsoResolve(context, VideoEndFingerprint).mutableMethod.name + + // Create integrations interface methods. + addSeekInterfaceMethods( + it, + seekSourceMethodName, + "overrideVideoTime", + "seekTo", + "videoInformationClass" + ) + addSeekInterfaceMethods( + it, + seekRelativeSourceMethodName, + "overrideVideoTimeRelative", + "seekToRelative", + "videoInformationClass" + ) + val literalIndex = getWideLiteralInstructionIndex(45368273) val walkerIndex = getTargetIndexReversedOrThrow(literalIndex, Opcode.INVOKE_VIRTUAL_RANGE) @@ -228,14 +239,33 @@ object VideoInformationPatch : BytecodePatch( } MdxPlayerDirectorSetVideoStageFingerprint.resultOrThrow().let { - val (mdxConstructorMethod, mdxConstructorInsertIndex) = - getSeekToConstructorMethod(it, "overrideMDXVideoTime", "videoInformationMDXClass") + it.mutableMethod.apply { + mdxConstructorMethod = + it.mutableClass.methods.first { method -> MethodUtil.isConstructor(method) } - this.mdxConstructorMethod = mdxConstructorMethod - this.mdxConstructorInsertIndex = mdxConstructorInsertIndex + mdxConstructorInsertIndex = mdxConstructorMethod.indexOfFirstInstructionOrThrow { + opcode == Opcode.INVOKE_DIRECT && getReference()?.name == "" + } + 1 - // hook the MDX director for use through integrations - onCreateHookMdx(INTEGRATIONS_CLASS_DESCRIPTOR, "initialize") + // hook the MDX director for use through integrations + onCreateHookMdx(INTEGRATIONS_CLASS_DESCRIPTOR, "initializeMdx") + + // Create integrations interface methods. + addSeekInterfaceMethods( + it, + seekSourceMethodName, + "overrideMDXVideoTime", + "seekTo", + "videoInformationMDXClass" + ) + addSeekInterfaceMethods( + it, + seekRelativeSourceMethodName, + "overrideMDXVideoTimeRelative", + "seekToRelative", + "videoInformationMDXClass" + ) + } } /** @@ -495,7 +525,7 @@ object VideoInformationPatch : BytecodePatch( internal fun onCreateHook(targetMethodClass: String, targetMethodName: String) = playerConstructorMethod.addInstruction( playerConstructorInsertIndex++, - "invoke-static/range { p0 .. p0 }, $targetMethodClass->$targetMethodName(Ljava/lang/Object;)V" + "invoke-static { }, $targetMethodClass->$targetMethodName()V" ) /** @@ -507,7 +537,7 @@ object VideoInformationPatch : BytecodePatch( internal fun onCreateHookMdx(targetMethodClass: String, targetMethodName: String) = mdxConstructorMethod.addInstruction( mdxConstructorInsertIndex++, - "invoke-static/range { p0 .. p0 }, $targetMethodClass->$targetMethodName(Ljava/lang/Object;)V" + "invoke-static { }, $targetMethodClass->$targetMethodName(Ljava/lang/Object;)V" ) /** diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/SeekRelativeFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/SeekRelativeFingerprint.kt new file mode 100644 index 000000000..a73ab1966 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/SeekRelativeFingerprint.kt @@ -0,0 +1,22 @@ +package app.revanced.patches.youtube.video.information.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.MethodFingerprint +import app.revanced.patches.youtube.utils.fingerprints.VideoEndFingerprint +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.Opcode + +/** + * Resolves using class found in [VideoEndFingerprint]. + */ +internal object SeekRelativeFingerprint : MethodFingerprint( + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + returnType = "Z", + parameters = listOf("J", "L"), + opcodes = listOf( + Opcode.ADD_LONG_2ADDR, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT, + Opcode.RETURN + ) +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/util/BytecodeUtils.kt b/src/main/kotlin/app/revanced/util/BytecodeUtils.kt index c156daa32..e2c42f0ac 100644 --- a/src/main/kotlin/app/revanced/util/BytecodeUtils.kt +++ b/src/main/kotlin/app/revanced/util/BytecodeUtils.kt @@ -19,6 +19,7 @@ import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod 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.Instruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction @@ -647,15 +648,22 @@ fun MutableClass.addFieldAndInstructions( .filter { method -> method.name == "" } .forEach { mutableMethod -> mutableMethod.apply { - val initializeIndex = getTargetIndexWithMethodReferenceName("") + val initializeIndex = indexOfFirstInstructionOrThrow { + opcode == Opcode.INVOKE_DIRECT && getReference()?.name == "" + } val insertIndex = if (initializeIndex == -1) 1 else initializeIndex + 1 + val initializeRegister = if (initializeIndex == -1) + "p0" + else + "v${getInstruction(initializeIndex).registerC}" + addInstruction( insertIndex, - "sput-object p0, $objectCall" + "sput-object $initializeRegister, $objectCall" ) } }