mirror of
https://github.com/revanced/revanced-patches
synced 2024-12-04 19:42:59 +01:00
refactor(youtube/video-information): include video speed (#1843)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
This commit is contained in:
parent
7403fc86ae
commit
33f795350d
@ -4,19 +4,7 @@ import app.revanced.patcher.annotation.Compatibility
|
|||||||
import app.revanced.patcher.annotation.Package
|
import app.revanced.patcher.annotation.Package
|
||||||
|
|
||||||
@Compatibility(
|
@Compatibility(
|
||||||
[Package(
|
[Package("com.google.android.youtube", arrayOf("18.08.37"))]
|
||||||
"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"
|
|
||||||
)
|
|
||||||
)]
|
|
||||||
)
|
)
|
||||||
@Target(AnnotationTarget.CLASS)
|
@Target(AnnotationTarget.CLASS)
|
||||||
internal annotation class SponsorBlockCompatibility
|
internal annotation class SponsorBlockCompatibility
|
@ -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.playercontrols.bytecode.patch.PlayerControlsBytecodePatch
|
||||||
import app.revanced.patches.youtube.misc.playertype.patch.PlayerTypeHookPatch
|
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.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 app.revanced.patches.youtube.misc.video.videoid.patch.VideoIdPatch
|
||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
import org.jf.dexlib2.iface.instruction.*
|
import org.jf.dexlib2.iface.instruction.*
|
||||||
@ -41,11 +40,13 @@ import org.jf.dexlib2.iface.reference.StringReference
|
|||||||
@Patch
|
@Patch
|
||||||
@DependsOn(
|
@DependsOn(
|
||||||
dependencies = [
|
dependencies = [
|
||||||
VideoInformationPatch::class, // updates video information and adds method to seek in video
|
|
||||||
VideoIdPatch::class,
|
|
||||||
PlayerControlsBytecodePatch::class,
|
|
||||||
PlayerTypeHookPatch::class,
|
|
||||||
IntegrationsPatch::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,
|
SponsorBlockResourcePatch::class,
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
@ -75,7 +76,7 @@ class SponsorBlockBytecodePatch : BytecodePatch(
|
|||||||
|
|
||||||
override fun execute(context: BytecodeContext): PatchResult {
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
/*
|
/*
|
||||||
Hook the video time methods
|
* Hook the video time methods
|
||||||
*/
|
*/
|
||||||
with(VideoInformationPatch) {
|
with(VideoInformationPatch) {
|
||||||
videoTimeHook(
|
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")
|
VideoIdPatch.injectCallBackgroundPlay("$INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setCurrentVideoId(Ljava/lang/String;)V")
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Seekbar drawing
|
* Seekbar drawing
|
||||||
*/
|
*/
|
||||||
val seekbarSignatureResult = SeekbarFingerprint.result!!.let {
|
val seekbarSignatureResult = SeekbarFingerprint.result!!.let {
|
||||||
SeekbarOnDrawFingerprint.apply { resolve(context, it.mutableClass) }
|
SeekbarOnDrawFingerprint.apply { resolve(context, it.mutableClass) }
|
||||||
@ -99,7 +100,7 @@ class SponsorBlockBytecodePatch : BytecodePatch(
|
|||||||
val seekbarMethodInstructions = seekbarMethod.implementation!!.instructions
|
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()) {
|
for ((index, instruction) in seekbarMethodInstructions.withIndex()) {
|
||||||
if (instruction.opcode != Opcode.MOVE_OBJECT_FROM16) continue
|
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) ->
|
val drawRectangleInstructions = seekbarMethodInstructions.withIndex().filter { (_, instruction) ->
|
||||||
instruction is ReferenceInstruction && (instruction.reference as? MethodReference)?.name == "drawRect"
|
instruction is ReferenceInstruction && (instruction.reference as? MethodReference)?.name == "drawRect"
|
||||||
}.map { (index, instruction) -> // TODO: improve code
|
}.map { (index, instruction) -> // TODO: improve code
|
||||||
@ -150,8 +151,8 @@ class SponsorBlockBytecodePatch : BytecodePatch(
|
|||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Draw segment
|
* Draw segment
|
||||||
*/
|
*/
|
||||||
val drawSegmentInstructionInsertIndex = (seekbarMethodInstructions.size - 1 - 2)
|
val drawSegmentInstructionInsertIndex = (seekbarMethodInstructions.size - 1 - 2)
|
||||||
val (canvasInstance, centerY) = (seekbarMethodInstructions[drawSegmentInstructionInsertIndex] as FiveRegisterInstruction).let {
|
val (canvasInstance, centerY) = (seekbarMethodInstructions[drawSegmentInstructionInsertIndex] as FiveRegisterInstruction).let {
|
||||||
it.registerC to it.registerE
|
it.registerC to it.registerE
|
||||||
@ -162,7 +163,7 @@ class SponsorBlockBytecodePatch : BytecodePatch(
|
|||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Voting & Shield button
|
* Voting & Shield button
|
||||||
*/
|
*/
|
||||||
val controlsMethodResult = PlayerControlsBytecodePatch.showPlayerControlsFingerprintResult
|
val controlsMethodResult = PlayerControlsBytecodePatch.showPlayerControlsFingerprintResult
|
||||||
|
|
||||||
@ -268,7 +269,9 @@ class SponsorBlockBytecodePatch : BytecodePatch(
|
|||||||
} ?: return PatchResultError("Could not find the method which contains the replaceMeWith* strings")
|
} ?: 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()
|
AutoRepeatParentFingerprint.result ?: return AutoRepeatParentFingerprint.toErrorResult()
|
||||||
AutoRepeatFingerprint.also {
|
AutoRepeatFingerprint.also {
|
||||||
it.resolve(context, AutoRepeatParentFingerprint.result!!.classDef)
|
it.resolve(context, AutoRepeatParentFingerprint.result!!.classDef)
|
||||||
|
@ -4,19 +4,7 @@ import app.revanced.patcher.annotation.Compatibility
|
|||||||
import app.revanced.patcher.annotation.Package
|
import app.revanced.patcher.annotation.Package
|
||||||
|
|
||||||
@Compatibility(
|
@Compatibility(
|
||||||
[Package(
|
[Package("com.google.android.youtube", arrayOf("18.08.37"))]
|
||||||
"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"
|
|
||||||
)
|
|
||||||
)]
|
|
||||||
)
|
)
|
||||||
@Target(AnnotationTarget.CLASS)
|
@Target(AnnotationTarget.CLASS)
|
||||||
internal annotation class VideoInformationCompatibility
|
internal annotation class VideoInformationCompatibility
|
||||||
|
@ -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 app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
@ -1,5 +1,6 @@
|
|||||||
package app.revanced.patches.youtube.misc.video.information.patch
|
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.Description
|
||||||
import app.revanced.patcher.annotation.Name
|
import app.revanced.patcher.annotation.Name
|
||||||
import app.revanced.patcher.annotation.Version
|
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.integrations.patch.IntegrationsPatch
|
||||||
import app.revanced.patches.youtube.misc.video.information.annotation.VideoInformationCompatibility
|
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.information.fingerprints.*
|
||||||
|
import app.revanced.patches.youtube.misc.video.speed.remember.patch.RememberPlaybackSpeedPatch
|
||||||
import app.revanced.patches.youtube.misc.video.videoid.patch.VideoIdPatch
|
import app.revanced.patches.youtube.misc.video.videoid.patch.VideoIdPatch
|
||||||
import org.jf.dexlib2.AccessFlags
|
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.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.OneRegisterInstruction
|
||||||
|
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
|
||||||
import org.jf.dexlib2.immutable.ImmutableMethod
|
import org.jf.dexlib2.immutable.ImmutableMethod
|
||||||
import org.jf.dexlib2.immutable.ImmutableMethodParameter
|
import org.jf.dexlib2.immutable.ImmutableMethodParameter
|
||||||
import org.jf.dexlib2.util.MethodUtil
|
import org.jf.dexlib2.util.MethodUtil
|
||||||
@ -39,6 +46,7 @@ class VideoInformationPatch : BytecodePatch(
|
|||||||
CreateVideoPlayerSeekbarFingerprint,
|
CreateVideoPlayerSeekbarFingerprint,
|
||||||
PlayerControllerSetTimeReferenceFingerprint,
|
PlayerControllerSetTimeReferenceFingerprint,
|
||||||
VideoTimeFingerprint,
|
VideoTimeFingerprint,
|
||||||
|
OnPlaybackSpeedItemClickFingerprint,
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
override fun execute(context: BytecodeContext): PatchResult {
|
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"
|
val videoIdMethodDescriptor = "$INTEGRATIONS_CLASS_DESCRIPTOR->setVideoId(Ljava/lang/String;)V"
|
||||||
VideoIdPatch.injectCall(videoIdMethodDescriptor)
|
VideoIdPatch.injectCall(videoIdMethodDescriptor)
|
||||||
VideoIdPatch.injectCallBackgroundPlay(videoIdMethodDescriptor)
|
VideoIdPatch.injectCallBackgroundPlay(videoIdMethodDescriptor)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Set the video time method
|
* Set the video time method
|
||||||
*/
|
*/
|
||||||
with(PlayerControllerSetTimeReferenceFingerprint.result!!) {
|
with(PlayerControllerSetTimeReferenceFingerprint.result!!) {
|
||||||
timeMethod = context.toMethodWalker(method)
|
timeMethod = context.toMethodWalker(method)
|
||||||
.nextMethod(scanResult.patternScanResult!!.startIndex, true)
|
.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 =
|
highPrecisionTimeMethod =
|
||||||
(object : MethodFingerprint("V", null, listOf("J", "J", "J", "J", "I", "L"), null) {}).also {
|
(object : MethodFingerprint("V", null, listOf("J", "J", "J", "J", "I", "L"), null) {}).also {
|
||||||
@ -120,10 +128,31 @@ class VideoInformationPatch : BytecodePatch(
|
|||||||
}.result!!.mutableMethod
|
}.result!!.mutableMethod
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Hook the methods which set the time
|
* Hook the methods which set the time
|
||||||
*/
|
*/
|
||||||
highPrecisionTimeHook(INTEGRATIONS_CLASS_DESCRIPTOR, "setVideoTimeHighPrecision")
|
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()
|
return PatchResultSuccess()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,5 +214,30 @@ class VideoInformationPatch : BytecodePatch(
|
|||||||
TIME(2),
|
TIME(2),
|
||||||
HIGH_PRECISION_TIME(0),
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@ import app.revanced.patcher.annotation.Description
|
|||||||
import app.revanced.patcher.annotation.Name
|
import app.revanced.patcher.annotation.Name
|
||||||
import app.revanced.patcher.annotation.Version
|
import app.revanced.patcher.annotation.Version
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
import app.revanced.patcher.data.BytecodeContext
|
||||||
import app.revanced.patcher.extensions.addInstruction
|
|
||||||
import app.revanced.patcher.extensions.addInstructions
|
import app.revanced.patcher.extensions.addInstructions
|
||||||
import app.revanced.patcher.extensions.instruction
|
import app.revanced.patcher.extensions.instruction
|
||||||
import app.revanced.patcher.patch.*
|
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.shared.settings.preference.impl.SwitchPreference
|
||||||
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
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.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.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 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
|
@Patch
|
||||||
@Name("remember-playback-speed")
|
@Name("remember-playback-speed")
|
||||||
@Description("Adds the ability to remember the playback speed you chose in the video playback speed flyout.")
|
@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
|
@RememberPlaybackSpeedCompatibility
|
||||||
@Version("0.0.1")
|
@Version("0.0.1")
|
||||||
class RememberPlaybackSpeedPatch : BytecodePatch(
|
class RememberPlaybackSpeedPatch : BytecodePatch(
|
||||||
listOf(
|
listOf(
|
||||||
OnPlaybackSpeedItemClickFingerprint,
|
|
||||||
InitializePlaybackSpeedValuesFingerprint
|
InitializePlaybackSpeedValuesFingerprint
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
@ -59,38 +54,21 @@ class RememberPlaybackSpeedPatch : BytecodePatch(
|
|||||||
|
|
||||||
VideoIdPatch.injectCall("${INTEGRATIONS_CLASS_DESCRIPTOR}->newVideoLoaded(Ljava/lang/String;)V")
|
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
|
* Hook the code that is called when the playback speeds are initialized, and sets the 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.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
// Set the remembered playback speed.
|
|
||||||
InitializePlaybackSpeedValuesFingerprint.result?.apply {
|
InitializePlaybackSpeedValuesFingerprint.result?.apply {
|
||||||
// Infer everything necessary for calling the method setPlaybackSpeed().
|
// 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
|
val onItemClickListenerClassFieldReference = mutableMethod.instruction(0).reference
|
||||||
|
|
||||||
// Registers are not used at index 0, so they can be freely used.
|
// Registers are not used at index 0, so they can be freely used.
|
||||||
mutableMethod.addInstructions(
|
mutableMethod.addInstructions(
|
||||||
0,
|
0,
|
||||||
"""
|
"""
|
||||||
invoke-static { }, $INTEGRATIONS_CLASS_DESCRIPTOR->getCurrentPlaybackSpeed()F
|
invoke-static { }, $INTEGRATIONS_CLASS_DESCRIPTOR->getPlaybackSpeedOverride()F
|
||||||
move-result v0
|
move-result v0
|
||||||
|
|
||||||
# Check if the playback speed is not 1.0x.
|
# Check if the playback speed is not 1.0x.
|
||||||
@ -102,30 +80,18 @@ class RememberPlaybackSpeedPatch : BytecodePatch(
|
|||||||
iget-object v1, p0, $onItemClickListenerClassFieldReference
|
iget-object v1, p0, $onItemClickListenerClassFieldReference
|
||||||
|
|
||||||
# Get the container class field.
|
# Get the container class field.
|
||||||
iget-object v1, v1, $setPlaybackSpeedContainerClassFieldReference
|
iget-object v1, v1, ${VideoInformationPatch.setPlaybackSpeedContainerClassFieldReference}
|
||||||
|
|
||||||
# Get the field from its class.
|
# Get the field from its class.
|
||||||
iget-object v2, v1, $setPlaybackSpeedClassFieldReference
|
iget-object v2, v1, ${VideoInformationPatch.setPlaybackSpeedClassFieldReference}
|
||||||
|
|
||||||
# Invoke setPlaybackSpeed on that class.
|
# Invoke setPlaybackSpeed on that class.
|
||||||
invoke-virtual {v2, v0}, $setPlaybackSpeedMethodReference
|
invoke-virtual {v2, v0}, ${VideoInformationPatch.setPlaybackSpeedMethodReference}
|
||||||
""".trimIndent(),
|
""".trimIndent(),
|
||||||
listOf(ExternalLabel("do_not_override", mutableMethod.instruction(0)))
|
listOf(ExternalLabel("do_not_override", mutableMethod.instruction(0)))
|
||||||
)
|
)
|
||||||
} ?: return InitializePlaybackSpeedValuesFingerprint.toErrorResult()
|
} ?: 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()
|
return PatchResultSuccess()
|
||||||
}
|
}
|
||||||
@ -133,7 +99,5 @@ class RememberPlaybackSpeedPatch : BytecodePatch(
|
|||||||
private companion object {
|
private companion object {
|
||||||
const val INTEGRATIONS_CLASS_DESCRIPTOR =
|
const val INTEGRATIONS_CLASS_DESCRIPTOR =
|
||||||
"Lapp/revanced/integrations/patches/playback/speed/RememberPlaybackSpeedPatch;"
|
"Lapp/revanced/integrations/patches/playback/speed/RememberPlaybackSpeedPatch;"
|
||||||
|
|
||||||
val Instruction.reference get() = (this as ReferenceInstruction).reference.toString()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user