fix(youtube/sponsorblock): fix segments not skipping during background play (#1765)

Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
This commit is contained in:
LisoUseInAIKyrios 2023-03-20 02:21:34 +04:00 committed by GitHub
parent aad6e05538
commit 7620ea1752
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 66 additions and 11 deletions

View file

@ -81,7 +81,7 @@ class SponsorBlockBytecodePatch : BytecodePatch(
/* /*
Set current video id Set current video id
*/ */
VideoIdPatch.injectCall("$INTEGRATIONS_PLAYER_CONTROLLER_CLASS_DESCRIPTOR->setCurrentVideoId(Ljava/lang/String;)V") VideoIdPatch.injectCallBackgroundPlay("$INTEGRATIONS_PLAYER_CONTROLLER_CLASS_DESCRIPTOR->setCurrentVideoId(Ljava/lang/String;)V")
/* /*
Seekbar drawing Seekbar drawing

View file

@ -98,7 +98,9 @@ class VideoInformationPatch : BytecodePatch(
/* /*
Inject call for video id Inject call for video id
*/ */
VideoIdPatch.injectCall("$INTEGRATIONS_CLASS_DESCRIPTOR->setVideoId(Ljava/lang/String;)V") val videoIdMethodDescriptor = "$INTEGRATIONS_CLASS_DESCRIPTOR->setVideoId(Ljava/lang/String;)V"
VideoIdPatch.injectCall(videoIdMethodDescriptor)
VideoIdPatch.injectCallBackgroundPlay(videoIdMethodDescriptor)
/* /*
Set the video time method Set the video time method

View file

@ -0,0 +1,16 @@
package app.revanced.patches.youtube.misc.video.videoid.fingerprint
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
object VideoIdFingerprintBackgroundPlay : MethodFingerprint(
returnType = "V",
access = AccessFlags.DECLARED_SYNCHRONIZED or AccessFlags.FINAL or AccessFlags.PUBLIC,
parameters = listOf("L"),
opcodes = listOf(Opcode.INVOKE_INTERFACE),
customFingerprint = {
it.definingClass.endsWith("PlaybackLifecycleMonitor;")
}
)

View file

@ -15,6 +15,7 @@ import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
import app.revanced.patches.youtube.misc.video.videoid.annotation.VideoIdCompatibility import app.revanced.patches.youtube.misc.video.videoid.annotation.VideoIdCompatibility
import app.revanced.patches.youtube.misc.video.videoid.fingerprint.VideoIdFingerprint import app.revanced.patches.youtube.misc.video.videoid.fingerprint.VideoIdFingerprint
import app.revanced.patches.youtube.misc.video.videoid.fingerprint.VideoIdFingerprintBackgroundPlay
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
@Name("video-id-hook") @Name("video-id-hook")
@ -23,30 +24,50 @@ import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
@Version("0.0.1") @Version("0.0.1")
@DependsOn([IntegrationsPatch::class]) @DependsOn([IntegrationsPatch::class])
class VideoIdPatch : BytecodePatch( class VideoIdPatch : BytecodePatch(
listOf(VideoIdFingerprint) listOf(VideoIdFingerprint, VideoIdFingerprintBackgroundPlay)
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
VideoIdFingerprint.result?.let { VideoIdFingerprint.result?.let { result ->
val videoIdRegisterInstructionIndex = it.scanResult.patternScanResult!!.endIndex val videoIdRegisterInstructionIndex = result.scanResult.patternScanResult!!.endIndex
with(it.mutableMethod) { result.mutableMethod.also {
insertMethod = this insertMethod = it
}.apply {
videoIdRegister = (instruction(videoIdRegisterInstructionIndex) as OneRegisterInstruction).registerA videoIdRegister = (instruction(videoIdRegisterInstructionIndex) as OneRegisterInstruction).registerA
insertIndex = videoIdRegisterInstructionIndex + 1 insertIndex = videoIdRegisterInstructionIndex + 1
} }
} ?: return VideoIdFingerprint.toErrorResult() } ?: return VideoIdFingerprint.toErrorResult()
VideoIdFingerprintBackgroundPlay.result?.let { result ->
val endIndex = result.scanResult.patternScanResult!!.endIndex
result.mutableMethod.also {
backgroundPlaybackMethod = it
}.apply {
backgroundPlaybackVideoIdRegister = (instruction(endIndex + 1) as OneRegisterInstruction).registerA
backgroundPlaybackInsertIndex = endIndex + 2
}
} ?: return VideoIdFingerprintBackgroundPlay.toErrorResult()
return PatchResultSuccess() return PatchResultSuccess()
} }
companion object { companion object {
private var videoIdRegister = 0 private var videoIdRegister = 0
private var insertIndex = 0 private var insertIndex = 0
private lateinit var insertMethod: MutableMethod private lateinit var insertMethod: MutableMethod
private var backgroundPlaybackVideoIdRegister = 0
private var backgroundPlaybackInsertIndex = 0
private lateinit var backgroundPlaybackMethod: MutableMethod
/** /**
* Adds an invoke-static instruction, called with the new id when the video changes. * Adds an invoke-static instruction, called with the new id when the video changes.
*
* Supports all videos (regular videos, Shorts and Stories).
*
* _Does not function if playing in the background with no video visible_.
*
* Be aware, this can be called multiple times for the same video id. * Be aware, this can be called multiple times for the same video id.
* *
* @param methodDescriptor which method to call. Params have to be `Ljava/lang/String;` * @param methodDescriptor which method to call. Params have to be `Ljava/lang/String;`
@ -54,12 +75,28 @@ class VideoIdPatch : BytecodePatch(
fun injectCall( fun injectCall(
methodDescriptor: String methodDescriptor: String
) = insertMethod.addInstructions( ) = insertMethod.addInstructions(
// Keep injection calls in the order they're added. // Keep injection calls in the order they're added:
// Order has been proven to be important for the same reason that order of patch execution is important // Increment index. So if additional injection calls are added, those calls run after this injection call.
// such as for the VideoInformation patch.
insertIndex++, insertIndex++,
"invoke-static {v$videoIdRegister}, $methodDescriptor" "invoke-static {v$videoIdRegister}, $methodDescriptor"
) )
/**
* Alternate hook that supports only regular videos, but hook supports changing to new video
* during background play when no video is visible.
*
* _Does not support Shorts or Stories_.
*
* Be aware, the hook can be called multiple times for the same video id.
*
* @param methodDescriptor which method to call. Params have to be `Ljava/lang/String;`
*/
fun injectCallBackgroundPlay(
methodDescriptor: String
) = backgroundPlaybackMethod.addInstructions(
backgroundPlaybackInsertIndex++, // move-result-object offset
"invoke-static {v$backgroundPlaybackVideoIdRegister}, $methodDescriptor"
)
} }
} }