refactor(youtube/video-information): include video speed (#1843)

Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
This commit is contained in:
LisoUseInAIKyrios 2023-04-04 11:00:13 +04:00 committed by oSumAtrIX
parent 7403fc86ae
commit 33f795350d
No known key found for this signature in database
GPG Key ID: A9B3094ACDB604B4
7 changed files with 93 additions and 96 deletions

View File

@ -4,19 +4,7 @@ import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
"17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
"18.05.40",
"18.08.37"
)
)]
[Package("com.google.android.youtube", arrayOf("18.08.37"))]
)
@Target(AnnotationTarget.CLASS)
internal annotation class SponsorBlockCompatibility

View File

@ -29,7 +29,6 @@ import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
import app.revanced.patches.youtube.misc.playercontrols.bytecode.patch.PlayerControlsBytecodePatch
import app.revanced.patches.youtube.misc.playertype.patch.PlayerTypeHookPatch
import app.revanced.patches.youtube.misc.video.information.patch.VideoInformationPatch
import app.revanced.patches.youtube.misc.video.speed.remember.patch.RememberPlaybackSpeedPatch
import app.revanced.patches.youtube.misc.video.videoid.patch.VideoIdPatch
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.instruction.*
@ -41,11 +40,13 @@ import org.jf.dexlib2.iface.reference.StringReference
@Patch
@DependsOn(
dependencies = [
VideoInformationPatch::class, // updates video information and adds method to seek in video
VideoIdPatch::class,
PlayerControlsBytecodePatch::class,
PlayerTypeHookPatch::class,
IntegrationsPatch::class,
VideoIdPatch::class,
// Required to skip segments on time.
VideoInformationPatch::class,
// Used to prevent SponsorBlock from running on Shorts because SponsorBlock does not yet support Shorts.
PlayerTypeHookPatch::class,
PlayerControlsBytecodePatch::class,
SponsorBlockResourcePatch::class,
]
)
@ -75,7 +76,7 @@ class SponsorBlockBytecodePatch : BytecodePatch(
override fun execute(context: BytecodeContext): PatchResult {
/*
Hook the video time methods
* Hook the video time methods
*/
with(VideoInformationPatch) {
videoTimeHook(
@ -85,12 +86,12 @@ class SponsorBlockBytecodePatch : BytecodePatch(
}
/*
Set current video id
* Set current video id
*/
VideoIdPatch.injectCallBackgroundPlay("$INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setCurrentVideoId(Ljava/lang/String;)V")
/*
Seekbar drawing
* Seekbar drawing
*/
val seekbarSignatureResult = SeekbarFingerprint.result!!.let {
SeekbarOnDrawFingerprint.apply { resolve(context, it.mutableClass) }
@ -99,7 +100,7 @@ class SponsorBlockBytecodePatch : BytecodePatch(
val seekbarMethodInstructions = seekbarMethod.implementation!!.instructions
/*
Get the instance of the seekbar rectangle
* Get the instance of the seekbar rectangle
*/
for ((index, instruction) in seekbarMethodInstructions.withIndex()) {
if (instruction.opcode != Opcode.MOVE_OBJECT_FROM16) continue
@ -127,8 +128,8 @@ class SponsorBlockBytecodePatch : BytecodePatch(
}
/*
Set rectangle absolute left and right positions
*/
* Set rectangle absolute left and right positions
*/
val drawRectangleInstructions = seekbarMethodInstructions.withIndex().filter { (_, instruction) ->
instruction is ReferenceInstruction && (instruction.reference as? MethodReference)?.name == "drawRect"
}.map { (index, instruction) -> // TODO: improve code
@ -150,8 +151,8 @@ class SponsorBlockBytecodePatch : BytecodePatch(
)
/*
Draw segment
*/
* Draw segment
*/
val drawSegmentInstructionInsertIndex = (seekbarMethodInstructions.size - 1 - 2)
val (canvasInstance, centerY) = (seekbarMethodInstructions[drawSegmentInstructionInsertIndex] as FiveRegisterInstruction).let {
it.registerC to it.registerE
@ -162,7 +163,7 @@ class SponsorBlockBytecodePatch : BytecodePatch(
)
/*
Voting & Shield button
* Voting & Shield button
*/
val controlsMethodResult = PlayerControlsBytecodePatch.showPlayerControlsFingerprintResult
@ -268,7 +269,9 @@ class SponsorBlockBytecodePatch : BytecodePatch(
} ?: return PatchResultError("Could not find the method which contains the replaceMeWith* strings")
// detect end of the video has been reached
// The vote and create segment buttons automatically change their visibility when appropriate,
// but if buttons are showing when the end of the video is reached then they will not automatically hide.
// Add a hook to forcefully hide when the end of the video is reached.
AutoRepeatParentFingerprint.result ?: return AutoRepeatParentFingerprint.toErrorResult()
AutoRepeatFingerprint.also {
it.resolve(context, AutoRepeatParentFingerprint.result!!.classDef)

View File

@ -4,19 +4,7 @@ import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
"17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
"18.05.40",
"18.08.37"
)
)]
[Package("com.google.android.youtube", arrayOf("18.08.37"))]
)
@Target(AnnotationTarget.CLASS)
internal annotation class VideoInformationCompatibility

View File

@ -1,4 +1,4 @@
package app.revanced.patches.youtube.misc.video.speed.remember.fingerprint
package app.revanced.patches.youtube.misc.video.information.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.Opcode

View File

@ -1,5 +1,6 @@
package app.revanced.patches.youtube.misc.video.information.patch
import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
@ -20,10 +21,16 @@ import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMu
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
import app.revanced.patches.youtube.misc.video.information.annotation.VideoInformationCompatibility
import app.revanced.patches.youtube.misc.video.information.fingerprints.*
import app.revanced.patches.youtube.misc.video.speed.remember.patch.RememberPlaybackSpeedPatch
import app.revanced.patches.youtube.misc.video.videoid.patch.VideoIdPatch
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.builder.BuilderInstruction
import org.jf.dexlib2.builder.MutableMethodImplementation
import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction
import org.jf.dexlib2.iface.instruction.Instruction
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.immutable.ImmutableMethod
import org.jf.dexlib2.immutable.ImmutableMethodParameter
import org.jf.dexlib2.util.MethodUtil
@ -39,6 +46,7 @@ class VideoInformationPatch : BytecodePatch(
CreateVideoPlayerSeekbarFingerprint,
PlayerControllerSetTimeReferenceFingerprint,
VideoTimeFingerprint,
OnPlaybackSpeedItemClickFingerprint,
)
) {
override fun execute(context: BytecodeContext): PatchResult {
@ -96,15 +104,15 @@ class VideoInformationPatch : BytecodePatch(
}
/*
Inject call for video id
* Inject call for video id
*/
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
*/
with(PlayerControllerSetTimeReferenceFingerprint.result!!) {
timeMethod = context.toMethodWalker(method)
.nextMethod(scanResult.patternScanResult!!.startIndex, true)
@ -112,7 +120,7 @@ class VideoInformationPatch : BytecodePatch(
}
/*
Set the high precision video time method
* Set the high precision video time method
*/
highPrecisionTimeMethod =
(object : MethodFingerprint("V", null, listOf("J", "J", "J", "J", "I", "L"), null) {}).also {
@ -120,10 +128,31 @@ class VideoInformationPatch : BytecodePatch(
}.result!!.mutableMethod
/*
Hook the methods which set the time
* Hook the methods which set the time
*/
highPrecisionTimeHook(INTEGRATIONS_CLASS_DESCRIPTOR, "setVideoTimeHighPrecision")
/*
* Hook the user playback speed selection
*/
OnPlaybackSpeedItemClickFingerprint.result?.apply {
speedSelectionInsertMethod = mutableMethod
speedSelectionInsertIndex = scanResult.patternScanResult!!.startIndex - 3
speedSelectionValueRegister =
(mutableMethod.instruction(speedSelectionInsertIndex) as FiveRegisterInstruction).registerD
val speedSelectionMethodInstructions = mutableMethod.implementation!!.instructions
setPlaybackSpeedContainerClassFieldReference =
getReference(speedSelectionMethodInstructions, -1, Opcode.IF_EQZ)
setPlaybackSpeedClassFieldReference =
getReference(speedSelectionMethodInstructions, 1, Opcode.IGET)
setPlaybackSpeedMethodReference =
getReference(speedSelectionMethodInstructions, 2, Opcode.IGET)
} ?: return OnPlaybackSpeedItemClickFingerprint.toErrorResult()
userSelectedPlaybackSpeedHook(INTEGRATIONS_CLASS_DESCRIPTOR, "userSelectedPlaybackSpeed")
return PatchResultSuccess()
}
@ -185,5 +214,30 @@ class VideoInformationPatch : BytecodePatch(
TIME(2),
HIGH_PRECISION_TIME(0),
}
private fun getReference(instructions: List<BuilderInstruction>, offset: Int, opcode: Opcode) =
instructions[instructions.indexOfFirst { it.opcode == opcode } + offset].reference
val Instruction.reference get() = (this as ReferenceInstruction).reference.toString()
private lateinit var speedSelectionInsertMethod: MutableMethod
private var speedSelectionInsertIndex = 0
private var speedSelectionValueRegister = 0
/**
* Hook the video speed selected by the user.
*/
internal fun userSelectedPlaybackSpeedHook(targetMethodClass: String, targetMethodName: String) =
speedSelectionInsertMethod.addInstruction(
speedSelectionInsertIndex++,
"invoke-static {v$speedSelectionValueRegister}, $targetMethodClass->$targetMethodName(F)V"
)
/**
* Used by [RememberPlaybackSpeedPatch]
*/
internal lateinit var setPlaybackSpeedContainerClassFieldReference: String
internal lateinit var setPlaybackSpeedClassFieldReference: String
internal lateinit var setPlaybackSpeedMethodReference: String
}
}

View File

@ -1,4 +1,4 @@
package app.revanced.patches.youtube.misc.video.speed.remember.fingerprint
package app.revanced.patches.youtube.misc.video.speed.current.fingerprint
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint

View File

@ -5,7 +5,6 @@ import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.instruction
import app.revanced.patcher.patch.*
@ -16,24 +15,20 @@ import app.revanced.patches.shared.settings.preference.impl.StringResource
import app.revanced.patches.shared.settings.preference.impl.SwitchPreference
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
import app.revanced.patches.youtube.misc.video.information.patch.VideoInformationPatch
import app.revanced.patches.youtube.misc.video.information.patch.VideoInformationPatch.Companion.reference
import app.revanced.patches.youtube.misc.video.speed.current.fingerprint.InitializePlaybackSpeedValuesFingerprint
import app.revanced.patches.youtube.misc.video.speed.remember.annotation.RememberPlaybackSpeedCompatibility
import app.revanced.patches.youtube.misc.video.speed.remember.fingerprint.InitializePlaybackSpeedValuesFingerprint
import app.revanced.patches.youtube.misc.video.speed.remember.fingerprint.OnPlaybackSpeedItemClickFingerprint
import app.revanced.patches.youtube.misc.video.videoid.patch.VideoIdPatch
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction
import org.jf.dexlib2.iface.instruction.Instruction
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
@Patch
@Name("remember-playback-speed")
@Description("Adds the ability to remember the playback speed you chose in the video playback speed flyout.")
@DependsOn([IntegrationsPatch::class, SettingsPatch::class, VideoIdPatch::class])
@DependsOn([IntegrationsPatch::class, SettingsPatch::class, VideoIdPatch::class, VideoInformationPatch::class])
@RememberPlaybackSpeedCompatibility
@Version("0.0.1")
class RememberPlaybackSpeedPatch : BytecodePatch(
listOf(
OnPlaybackSpeedItemClickFingerprint,
InitializePlaybackSpeedValuesFingerprint
)
) {
@ -59,38 +54,21 @@ class RememberPlaybackSpeedPatch : BytecodePatch(
VideoIdPatch.injectCall("${INTEGRATIONS_CLASS_DESCRIPTOR}->newVideoLoaded(Ljava/lang/String;)V")
VideoInformationPatch.userSelectedPlaybackSpeedHook(
INTEGRATIONS_CLASS_DESCRIPTOR, "userSelectedPlaybackSpeed")
/*
* The following code works by hooking the method which is called when the user selects a playback speed
* to remember the last selected playback speed.
*
* It also hooks the method which is called when the playback speeds are initialized.
* Conveniently, at this point the playback speed is set to the remembered playback speed.
* Hook the code that is called when the playback speeds are initialized, and sets the playback speed
*/
// Set the remembered playback speed.
InitializePlaybackSpeedValuesFingerprint.result?.apply {
// Infer everything necessary for calling the method setPlaybackSpeed().
val instructions = OnPlaybackSpeedItemClickFingerprint.result!!.mutableMethod.implementation!!.instructions
fun getReference(offset: Int = 0, opcode: Opcode) =
instructions[instructions.indexOfFirst { it.opcode == opcode } + offset].reference
val setPlaybackSpeedContainerClassFieldReference =
getReference(-1, Opcode.IF_EQZ)
val setPlaybackSpeedClassFieldReference =
getReference(1, Opcode.IGET)
val setPlaybackSpeedMethodReference =
getReference(2, Opcode.IGET)
val onItemClickListenerClassFieldReference = mutableMethod.instruction(0).reference
// Registers are not used at index 0, so they can be freely used.
mutableMethod.addInstructions(
0,
"""
invoke-static { }, $INTEGRATIONS_CLASS_DESCRIPTOR->getCurrentPlaybackSpeed()F
invoke-static { }, $INTEGRATIONS_CLASS_DESCRIPTOR->getPlaybackSpeedOverride()F
move-result v0
# Check if the playback speed is not 1.0x.
@ -102,30 +80,18 @@ class RememberPlaybackSpeedPatch : BytecodePatch(
iget-object v1, p0, $onItemClickListenerClassFieldReference
# Get the container class field.
iget-object v1, v1, $setPlaybackSpeedContainerClassFieldReference
iget-object v1, v1, ${VideoInformationPatch.setPlaybackSpeedContainerClassFieldReference}
# Get the field from its class.
iget-object v2, v1, $setPlaybackSpeedClassFieldReference
iget-object v2, v1, ${VideoInformationPatch.setPlaybackSpeedClassFieldReference}
# Invoke setPlaybackSpeed on that class.
invoke-virtual {v2, v0}, $setPlaybackSpeedMethodReference
invoke-virtual {v2, v0}, ${VideoInformationPatch.setPlaybackSpeedMethodReference}
""".trimIndent(),
listOf(ExternalLabel("do_not_override", mutableMethod.instruction(0)))
)
} ?: return InitializePlaybackSpeedValuesFingerprint.toErrorResult()
// Remember the selected playback speed.
OnPlaybackSpeedItemClickFingerprint.result?.apply {
val setPlaybackSpeedIndex = scanResult.patternScanResult!!.startIndex - 3
val selectedPlaybackSpeedRegister =
(mutableMethod.instruction(setPlaybackSpeedIndex) as FiveRegisterInstruction).registerD
mutableMethod.addInstruction(
setPlaybackSpeedIndex,
"invoke-static { v$selectedPlaybackSpeedRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->setPlaybackSpeed(F)V"
)
} ?: return OnPlaybackSpeedItemClickFingerprint.toErrorResult()
return PatchResultSuccess()
}
@ -133,7 +99,5 @@ class RememberPlaybackSpeedPatch : BytecodePatch(
private companion object {
const val INTEGRATIONS_CLASS_DESCRIPTOR =
"Lapp/revanced/integrations/patches/playback/speed/RememberPlaybackSpeedPatch;"
val Instruction.reference get() = (this as ReferenceInstruction).reference.toString()
}
}