@@ -6,6 +6,7 @@ import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
66import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
77import app.revanced.patcher.extensions.or
88import app.revanced.patcher.fingerprint.MethodFingerprint
9+ import app.revanced.patcher.fingerprint.MethodFingerprintResult
910import app.revanced.patcher.patch.BytecodePatch
1011import app.revanced.patcher.patch.PatchException
1112import app.revanced.patcher.patch.annotation.Patch
@@ -19,6 +20,7 @@ import app.revanced.patches.youtube.utils.playertype.PlayerTypeHookPatch
1920import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch
2021import app.revanced.patches.youtube.video.information.fingerprints.ChannelIdFingerprint
2122import app.revanced.patches.youtube.video.information.fingerprints.ChannelNameFingerprint
23+ import app.revanced.patches.youtube.video.information.fingerprints.MdxPlayerDirectorSetVideoStageFingerprint
2224import app.revanced.patches.youtube.video.information.fingerprints.OnPlaybackSpeedItemClickFingerprint
2325import app.revanced.patches.youtube.video.information.fingerprints.PlaybackInitializationFingerprint
2426import app.revanced.patches.youtube.video.information.fingerprints.PlaybackSpeedClassFingerprint
@@ -37,6 +39,7 @@ import app.revanced.util.getReference
3739import app.revanced.util.getTargetIndexOrThrow
3840import app.revanced.util.getTargetIndexReversedOrThrow
3941import app.revanced.util.getWalkerMethod
42+ import app.revanced.util.getWideLiteralInstructionIndex
4043import app.revanced.util.indexOfFirstInstructionOrThrow
4144import app.revanced.util.resultOrThrow
4245import com.android.tools.smali.dexlib2.AccessFlags
@@ -60,10 +63,12 @@ import com.android.tools.smali.dexlib2.util.MethodUtil
6063 VideoIdPatch ::class
6164 ]
6265)
66+ @Suppress(" MemberVisibilityCanBePrivate" )
6367object VideoInformationPatch : BytecodePatch(
6468 setOf(
6569 ChannelIdFingerprint ,
6670 ChannelNameFingerprint ,
71+ MdxPlayerDirectorSetVideoStageFingerprint ,
6772 OnPlaybackSpeedItemClickFingerprint ,
6873 OrganicPlaybackContextModelFingerprint ,
6974 PlaybackInitializationFingerprint ,
@@ -108,8 +113,19 @@ object VideoInformationPatch : BytecodePatch(
108113 private lateinit var backgroundVideoInformationMethod: MutableMethod
109114 private lateinit var shortsVideoInformationMethod: MutableMethod
110115
116+ /* *
117+ * Used in [VideoEndFingerprint] and [MdxPlayerDirectorSetVideoStageFingerprint].
118+ * Since both classes are inherited from the same class,
119+ * [VideoEndFingerprint] and [MdxPlayerDirectorSetVideoStageFingerprint] always have the same [seekSourceEnumType] and [seekSourceMethodName].
120+ */
121+ private var seekSourceEnumType = " "
122+ private var seekSourceMethodName = " "
123+
111124 private lateinit var playerConstructorMethod: MutableMethod
112- private var playerConstructorInsertIndex = 4
125+ private var playerConstructorInsertIndex = - 1
126+
127+ private lateinit var mdxConstructorMethod: MutableMethod
128+ private var mdxConstructorInsertIndex = - 1
113129
114130 private lateinit var videoTimeConstructorMethod: MutableMethod
115131 private var videoTimeConstructorInsertIndex = 2
@@ -118,66 +134,78 @@ object VideoInformationPatch : BytecodePatch(
118134 internal lateinit var speedSelectionInsertMethod: MutableMethod
119135 internal lateinit var videoEndMethod: MutableMethod
120136
137+ private fun getSeekToConstructorMethod (result : MethodFingerprintResult ): Pair <MutableMethod , Int > {
138+ result.mutableMethod.apply {
139+ val constructorMethod =
140+ result.mutableClass.methods.first { method -> MethodUtil .isConstructor(method) }
141+
142+ val constructorInsertIndex = indexOfFirstInstructionOrThrow {
143+ opcode == Opcode .INVOKE_DIRECT && getReference<MethodReference >()?.name == " <init>"
144+ } + 1
145+
146+ if (seekSourceEnumType.isEmpty() && seekSourceMethodName.isEmpty()) {
147+ seekSourceEnumType = parameterTypes[1 ].toString()
148+ seekSourceMethodName = name
149+ }
150+
151+ result.mutableClass.methods.add(
152+ ImmutableMethod (
153+ definingClass,
154+ " seekTo" ,
155+ listOf (ImmutableMethodParameter (" J" , annotations, " time" )),
156+ " Z" ,
157+ AccessFlags .PUBLIC or AccessFlags .FINAL ,
158+ annotations,
159+ null ,
160+ ImmutableMethodImplementation (
161+ 4 , """
162+ sget-object v0, $seekSourceEnumType ->a:$seekSourceEnumType
163+ invoke-virtual {p0, p1, p2, v0}, ${definingClass} ->$seekSourceMethodName (J$seekSourceEnumType )Z
164+ move-result p1
165+ return p1
166+ """ .toInstructions(),
167+ null ,
168+ null
169+ )
170+ ).toMutable()
171+ )
172+
173+ return Pair (constructorMethod, constructorInsertIndex)
174+ }
175+ }
176+
121177 override fun execute (context : BytecodeContext ) {
122178 val videoInformationMutableClass =
123179 context.findClass(INTEGRATIONS_CLASS_DESCRIPTOR )!! .mutableClass
124180
125181 VideoEndFingerprint .resultOrThrow().let {
182+ val (playerConstructorMethod, playerConstructorInsertIndex) =
183+ getSeekToConstructorMethod(it)
126184
127- playerConstructorMethod =
128- it.mutableClass.methods.first { method -> MethodUtil .isConstructor(method) }
185+ this . playerConstructorMethod = playerConstructorMethod
186+ this .playerConstructorInsertIndex = playerConstructorInsertIndex
129187
130188 // hook the player controller for use through integrations
131189 onCreateHook(INTEGRATIONS_CLASS_DESCRIPTOR , " initialize" )
132190
133191 it.mutableMethod.apply {
134- val seekSourceEnumType = parameterTypes[1 ].toString()
192+ val literalIndex = getWideLiteralInstructionIndex(45368273 )
193+ val walkerIndex = getTargetIndexReversedOrThrow(literalIndex, Opcode .INVOKE_VIRTUAL_RANGE )
135194
136- it.mutableClass.methods.add(
137- ImmutableMethod (
138- definingClass,
139- " seekTo" ,
140- listOf (ImmutableMethodParameter (" J" , annotations, " time" )),
141- " Z" ,
142- AccessFlags .PUBLIC or AccessFlags .FINAL ,
143- annotations,
144- null ,
145- ImmutableMethodImplementation (
146- 4 , """
147- sget-object v0, $seekSourceEnumType ->a:$seekSourceEnumType
148- invoke-virtual {p0, p1, p2, v0}, ${definingClass} ->${name} (J$seekSourceEnumType )Z
149- move-result p1
150- return p1
151- """ .toInstructions(),
152- null ,
153- null
154- )
155- ).toMutable()
156- )
195+ videoEndMethod =
196+ getWalkerMethod(context, walkerIndex)
197+ }
198+ }
157199
158- val smaliInstructions =
159- """
160- if-eqz v0, :ignore
161- invoke-virtual {v0, p0, p1}, $definingClass ->seekTo(J)Z
162- move-result v0
163- return v0
164- :ignore
165- const/4 v0, 0x0
166- return v0
167- """
200+ MdxPlayerDirectorSetVideoStageFingerprint .resultOrThrow().let {
201+ val (mdxConstructorMethod, mdxConstructorInsertIndex) =
202+ getSeekToConstructorMethod(it)
168203
169- videoInformationMutableClass.addFieldAndInstructions(
170- context,
171- " overrideVideoTime" ,
172- " videoInformationClass" ,
173- definingClass,
174- smaliInstructions,
175- true
176- )
204+ this .mdxConstructorMethod = mdxConstructorMethod
205+ this .mdxConstructorInsertIndex = mdxConstructorInsertIndex
177206
178- videoEndMethod =
179- getWalkerMethod(context, it.scanResult.patternScanResult!! .startIndex + 1 )
180- }
207+ // hook the MDX director for use through integrations
208+ onCreateHookMdx(INTEGRATIONS_CLASS_DESCRIPTOR , " initialize" )
181209 }
182210
183211 /* *
@@ -437,7 +465,19 @@ object VideoInformationPatch : BytecodePatch(
437465 internal fun onCreateHook (targetMethodClass : String , targetMethodName : String ) =
438466 playerConstructorMethod.addInstruction(
439467 playerConstructorInsertIndex++ ,
440- " invoke-static {}, $targetMethodClass ->$targetMethodName ()V"
468+ " invoke-static/range { p0 .. p0 }, $targetMethodClass ->$targetMethodName (Ljava/lang/Object;)V"
469+ )
470+
471+ /* *
472+ * Hook the MDX player director. Called when playing videos while casting to a big screen device.
473+ *
474+ * @param targetMethodClass The descriptor for the class to invoke when the player controller is created.
475+ * @param targetMethodName The name of the static method to invoke when the player controller is created.
476+ */
477+ internal fun onCreateHookMdx (targetMethodClass : String , targetMethodName : String ) =
478+ mdxConstructorMethod.addInstruction(
479+ mdxConstructorInsertIndex++ ,
480+ " invoke-static/range { p0 .. p0 }, $targetMethodClass ->$targetMethodName (Ljava/lang/Object;)V"
441481 )
442482
443483 /* *
0 commit comments