fix(YouTube - SponsorBlock): Skip segments when casting (#3331)
Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
This commit is contained in:
parent
7a63b73aa4
commit
d9395fdbca
|
@ -14,6 +14,9 @@ import app.revanced.patches.youtube.video.information.fingerprints.*
|
||||||
import app.revanced.patches.youtube.video.playerresponse.PlayerResponseMethodHookPatch
|
import app.revanced.patches.youtube.video.playerresponse.PlayerResponseMethodHookPatch
|
||||||
import app.revanced.patches.youtube.video.videoid.VideoIdPatch
|
import app.revanced.patches.youtube.video.videoid.VideoIdPatch
|
||||||
import app.revanced.util.exception
|
import app.revanced.util.exception
|
||||||
|
import app.revanced.util.getReference
|
||||||
|
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||||
|
import app.revanced.util.resultOrThrow
|
||||||
import com.android.tools.smali.dexlib2.AccessFlags
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
import com.android.tools.smali.dexlib2.Opcode
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
import com.android.tools.smali.dexlib2.builder.BuilderInstruction
|
import com.android.tools.smali.dexlib2.builder.BuilderInstruction
|
||||||
|
@ -24,6 +27,9 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
|
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
|
||||||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
|
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
|
||||||
import com.android.tools.smali.dexlib2.util.MethodUtil
|
import com.android.tools.smali.dexlib2.util.MethodUtil
|
||||||
|
import com.android.tools.smali.dexlib2.iface.Method
|
||||||
|
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||||
|
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||||
|
|
||||||
@Patch(
|
@Patch(
|
||||||
description = "Hooks YouTube to get information about the current playing video.",
|
description = "Hooks YouTube to get information about the current playing video.",
|
||||||
|
@ -32,6 +38,7 @@ import com.android.tools.smali.dexlib2.util.MethodUtil
|
||||||
object VideoInformationPatch : BytecodePatch(
|
object VideoInformationPatch : BytecodePatch(
|
||||||
setOf(
|
setOf(
|
||||||
PlayerInitFingerprint,
|
PlayerInitFingerprint,
|
||||||
|
MdxPlayerDirectorSetVideoStageFingerprint,
|
||||||
CreateVideoPlayerSeekbarFingerprint,
|
CreateVideoPlayerSeekbarFingerprint,
|
||||||
PlayerControllerSetTimeReferenceFingerprint,
|
PlayerControllerSetTimeReferenceFingerprint,
|
||||||
OnPlaybackSpeedItemClickFingerprint
|
OnPlaybackSpeedItemClickFingerprint
|
||||||
|
@ -42,12 +49,16 @@ object VideoInformationPatch : BytecodePatch(
|
||||||
private lateinit var playerInitMethod: MutableMethod
|
private lateinit var playerInitMethod: MutableMethod
|
||||||
private var playerInitInsertIndex = 4
|
private var playerInitInsertIndex = 4
|
||||||
|
|
||||||
|
private lateinit var mdxInitMethod: MutableMethod
|
||||||
|
private var mdxInitInsertIndex = -1
|
||||||
|
private var mdxInitInsertRegister = -1
|
||||||
|
|
||||||
private lateinit var timeMethod: MutableMethod
|
private lateinit var timeMethod: MutableMethod
|
||||||
private var timeInitInsertIndex = 2
|
private var timeInitInsertIndex = 2
|
||||||
|
|
||||||
private lateinit var speedSelectionInsertMethod: MutableMethod
|
private lateinit var speedSelectionInsertMethod: MutableMethod
|
||||||
private var speedSelectionInsertIndex = 0
|
private var speedSelectionInsertIndex = -1
|
||||||
private var speedSelectionValueRegister = 0
|
private var speedSelectionValueRegister = -1
|
||||||
|
|
||||||
// Used by other patches.
|
// Used by other patches.
|
||||||
internal lateinit var setPlaybackSpeedContainerClassFieldReference: String
|
internal lateinit var setPlaybackSpeedContainerClassFieldReference: String
|
||||||
|
@ -55,44 +66,48 @@ object VideoInformationPatch : BytecodePatch(
|
||||||
internal lateinit var setPlaybackSpeedMethodReference: String
|
internal lateinit var setPlaybackSpeedMethodReference: String
|
||||||
|
|
||||||
override fun execute(context: BytecodeContext) {
|
override fun execute(context: BytecodeContext) {
|
||||||
with(PlayerInitFingerprint.result!!) {
|
|
||||||
|
with(PlayerInitFingerprint.resultOrThrow()) {
|
||||||
playerInitMethod = mutableClass.methods.first { MethodUtil.isConstructor(it) }
|
playerInitMethod = mutableClass.methods.first { MethodUtil.isConstructor(it) }
|
||||||
|
|
||||||
// hook the player controller for use through integrations
|
// hook the player controller for use through integrations
|
||||||
onCreateHook(INTEGRATIONS_CLASS_DESCRIPTOR, "initialize")
|
onCreateHook(INTEGRATIONS_CLASS_DESCRIPTOR, "initialize")
|
||||||
|
|
||||||
// seek method
|
// seek method
|
||||||
val seekFingerprintResultMethod = SeekFingerprint.also { it.resolve(context, classDef) }.result!!.method
|
val seekFingerprintResultMethod =
|
||||||
|
SeekFingerprint.also { it.resolve(context, classDef) }.resultOrThrow().method
|
||||||
|
|
||||||
// create helper method
|
// create helper method
|
||||||
val seekHelperMethod = ImmutableMethod(
|
val seekHelperMethod = generateSeekMethodHelper(seekFingerprintResultMethod)
|
||||||
seekFingerprintResultMethod.definingClass,
|
|
||||||
"seekTo",
|
|
||||||
listOf(ImmutableMethodParameter("J", null, "time")),
|
|
||||||
"Z",
|
|
||||||
AccessFlags.PUBLIC or AccessFlags.FINAL,
|
|
||||||
null, null,
|
|
||||||
MutableMethodImplementation(4)
|
|
||||||
).toMutable()
|
|
||||||
|
|
||||||
// get enum type for the seek helper method
|
|
||||||
val seekSourceEnumType = seekFingerprintResultMethod.parameterTypes[1].toString()
|
|
||||||
|
|
||||||
// insert helper method instructions
|
|
||||||
seekHelperMethod.addInstructions(
|
|
||||||
0,
|
|
||||||
"""
|
|
||||||
sget-object v0, $seekSourceEnumType->a:$seekSourceEnumType
|
|
||||||
invoke-virtual {p0, p1, p2, v0}, ${seekFingerprintResultMethod.definingClass}->${seekFingerprintResultMethod.name}(J$seekSourceEnumType)Z
|
|
||||||
move-result p1
|
|
||||||
return p1
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
|
|
||||||
// add the seekTo method to the class for the integrations to call
|
// add the seekTo method to the class for the integrations to call
|
||||||
mutableClass.methods.add(seekHelperMethod)
|
mutableClass.methods.add(seekHelperMethod)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
with(MdxPlayerDirectorSetVideoStageFingerprint.resultOrThrow()) {
|
||||||
|
mdxInitMethod = mutableClass.methods.first { MethodUtil.isConstructor(it) }
|
||||||
|
|
||||||
|
// find the location of the first invoke-direct call and extract the register storing the 'this' object reference
|
||||||
|
val initThisIndex = mdxInitMethod.indexOfFirstInstructionOrThrow {
|
||||||
|
opcode == Opcode.INVOKE_DIRECT && getReference<MethodReference>()?.name == "<init>"
|
||||||
|
}
|
||||||
|
mdxInitInsertRegister = mdxInitMethod.getInstruction<FiveRegisterInstruction>(initThisIndex).registerC
|
||||||
|
mdxInitInsertIndex = initThisIndex + 1
|
||||||
|
|
||||||
|
// hook the MDX director for use through integrations
|
||||||
|
onCreateHookMdx(INTEGRATIONS_CLASS_DESCRIPTOR, "initializeMdx")
|
||||||
|
|
||||||
|
// MDX seek method
|
||||||
|
val mdxSeekFingerprintResultMethod =
|
||||||
|
MdxSeekFingerprint.apply { resolve(context, classDef) }.resultOrThrow().method
|
||||||
|
|
||||||
|
// create helper method
|
||||||
|
val mdxSeekHelperMethod = generateSeekMethodHelper(mdxSeekFingerprintResultMethod)
|
||||||
|
|
||||||
|
// add the seekTo method to the class for the integrations to call
|
||||||
|
mutableClass.methods.add(mdxSeekHelperMethod)
|
||||||
|
}
|
||||||
|
|
||||||
with(CreateVideoPlayerSeekbarFingerprint.result!!) {
|
with(CreateVideoPlayerSeekbarFingerprint.result!!) {
|
||||||
val videoLengthMethodResult = VideoLengthFingerprint.also { it.resolve(context, classDef) }.result!!
|
val videoLengthMethodResult = VideoLengthFingerprint.also { it.resolve(context, classDef) }.result!!
|
||||||
|
|
||||||
|
@ -103,7 +118,7 @@ object VideoInformationPatch : BytecodePatch(
|
||||||
|
|
||||||
addInstruction(
|
addInstruction(
|
||||||
videoLengthMethodResult.scanResult.patternScanResult!!.endIndex,
|
videoLengthMethodResult.scanResult.patternScanResult!!.endIndex,
|
||||||
"invoke-static {v$videoLengthRegister, v$dummyRegisterForLong}, $INTEGRATIONS_CLASS_DESCRIPTOR->setVideoLength(J)V"
|
"invoke-static { v$videoLengthRegister, v$dummyRegisterForLong }, $INTEGRATIONS_CLASS_DESCRIPTOR->setVideoLength(J)V"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -158,6 +173,35 @@ object VideoInformationPatch : BytecodePatch(
|
||||||
userSelectedPlaybackSpeedHook(INTEGRATIONS_CLASS_DESCRIPTOR, "userSelectedPlaybackSpeed")
|
userSelectedPlaybackSpeedHook(INTEGRATIONS_CLASS_DESCRIPTOR, "userSelectedPlaybackSpeed")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun generateSeekMethodHelper(seekMethod: Method): MutableMethod {
|
||||||
|
|
||||||
|
// create helper method
|
||||||
|
val generatedMethod = ImmutableMethod(
|
||||||
|
seekMethod.definingClass,
|
||||||
|
"seekTo",
|
||||||
|
listOf(ImmutableMethodParameter("J", null, "time")),
|
||||||
|
"Z",
|
||||||
|
AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
|
null, null,
|
||||||
|
MutableMethodImplementation(4)
|
||||||
|
).toMutable()
|
||||||
|
|
||||||
|
// get enum type for the seek helper method
|
||||||
|
val seekSourceEnumType = seekMethod.parameterTypes[1].toString()
|
||||||
|
|
||||||
|
// insert helper method instructions
|
||||||
|
generatedMethod.addInstructions(
|
||||||
|
0,
|
||||||
|
"""
|
||||||
|
sget-object v0, $seekSourceEnumType->a:$seekSourceEnumType
|
||||||
|
invoke-virtual { p0, p1, p2, v0 }, $seekMethod
|
||||||
|
move-result p1
|
||||||
|
return p1
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
return generatedMethod
|
||||||
|
}
|
||||||
|
|
||||||
private fun MutableMethod.insert(insertIndex: Int, register: String, descriptor: String) =
|
private fun MutableMethod.insert(insertIndex: Int, register: String, descriptor: String) =
|
||||||
addInstruction(insertIndex, "invoke-static { $register }, $descriptor")
|
addInstruction(insertIndex, "invoke-static { $register }, $descriptor")
|
||||||
|
|
||||||
|
@ -180,6 +224,19 @@ object VideoInformationPatch : BytecodePatch(
|
||||||
"$targetMethodClass->$targetMethodName(Ljava/lang/Object;)V"
|
"$targetMethodClass->$targetMethodName(Ljava/lang/Object;)V"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook the MDX player director. Called when playing videos while casting to a big screen device.
|
||||||
|
*
|
||||||
|
* @param targetMethodClass The descriptor for the class to invoke when the player controller is created.
|
||||||
|
* @param targetMethodName The name of the static method to invoke when the player controller is created.
|
||||||
|
*/
|
||||||
|
internal fun onCreateHookMdx(targetMethodClass: String, targetMethodName: String) =
|
||||||
|
mdxInitMethod.insert(
|
||||||
|
mdxInitInsertIndex++,
|
||||||
|
"v$mdxInitInsertRegister",
|
||||||
|
"$targetMethodClass->$targetMethodName(Ljava/lang/Object;)V"
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook the video time.
|
* Hook the video time.
|
||||||
* The hook is usually called once per second.
|
* The hook is usually called once per second.
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
package app.revanced.patches.youtube.video.information.fingerprints
|
||||||
|
|
||||||
|
|
||||||
|
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||||
|
|
||||||
|
internal object MdxPlayerDirectorSetVideoStageFingerprint : MethodFingerprint(
|
||||||
|
strings = listOf("MdxDirector setVideoStage ad should be null when videoStage is not an Ad state ")
|
||||||
|
)
|
|
@ -0,0 +1,23 @@
|
||||||
|
package app.revanced.patches.youtube.video.information.fingerprints
|
||||||
|
|
||||||
|
import app.revanced.patcher.extensions.or
|
||||||
|
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||||
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
|
||||||
|
internal object MdxSeekFingerprint : MethodFingerprint(
|
||||||
|
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
|
returnType = "Z",
|
||||||
|
parameters = listOf("J", "L"),
|
||||||
|
opcodes = listOf(
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT,
|
||||||
|
Opcode.RETURN,
|
||||||
|
),
|
||||||
|
customFingerprint = { methodDef, _ ->
|
||||||
|
// The instruction count is necessary here to avoid matching the relative version
|
||||||
|
// of the seek method we're after, which has the same function signature as the
|
||||||
|
// regular one, is in the same class, and even has the exact same 3 opcodes pattern.
|
||||||
|
methodDef.implementation!!.instructions.count() == 3
|
||||||
|
}
|
||||||
|
)
|
Loading…
Reference in a new issue