Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(YouTube - Playback speed): Remember playback speed with new speed menu #3810

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package app.revanced.patches.youtube.video.quality.fingerprints
package app.revanced.patches.youtube.shared.fingerprints

import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,28 @@ import app.revanced.patcher.util.proxy.mutableTypes.MutableClass
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
import app.revanced.patches.youtube.shared.fingerprints.NewVideoQualityChangedFingerprint
import app.revanced.patches.youtube.video.information.fingerprints.*
import app.revanced.patches.youtube.video.playerresponse.PlayerResponseMethodHookPatch
import app.revanced.patches.youtube.video.quality.fingerprints.PlaybackSpeedMenuSpeedChangedFingerprint
import app.revanced.patches.youtube.video.videoid.VideoIdPatch
import app.revanced.util.alsoResolve
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.Opcode
import com.android.tools.smali.dexlib2.builder.BuilderInstruction
import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation
import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
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(
description = "Hooks YouTube to get information about the current playing video.",
Expand All @@ -43,7 +44,8 @@ object VideoInformationPatch : BytecodePatch(
MdxPlayerDirectorSetVideoStageFingerprint,
CreateVideoPlayerSeekbarFingerprint,
PlayerControllerSetTimeReferenceFingerprint,
OnPlaybackSpeedItemClickFingerprint
OnPlaybackSpeedItemClickFingerprint,
NewVideoQualityChangedFingerprint
)
) {
private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/youtube/patches/VideoInformation;"
Expand All @@ -60,6 +62,12 @@ object VideoInformationPatch : BytecodePatch(
private lateinit var timeMethod: MutableMethod
private var timeInitInsertIndex = 2

// Old speed menu, where speeds are entries in a list. Method is also used by the player speed button.
private lateinit var legacySpeedSelectionInsertMethod: MutableMethod
private var legacySpeedSelectionInsertIndex = -1
private var legacySpeedSelectionValueRegister = -1

// New speed menu, with preset buttons and 0.05x fine adjustments buttons.
private lateinit var speedSelectionInsertMethod: MutableMethod
private var speedSelectionInsertIndex = -1
private var speedSelectionValueRegister = -1
Expand Down Expand Up @@ -158,22 +166,33 @@ object VideoInformationPatch : BytecodePatch(
/*
* Hook the user playback speed selection
*/
OnPlaybackSpeedItemClickFingerprint.result?.mutableMethod?.apply {
speedSelectionInsertMethod = this
OnPlaybackSpeedItemClickFingerprint.resultOrThrow().mutableMethod.apply {
legacySpeedSelectionInsertMethod = this
val speedSelectionMethodInstructions = this.implementation!!.instructions
val speedSelectionValueInstructionIndex = speedSelectionMethodInstructions.indexOfFirst {
it.opcode == Opcode.IGET
}
speedSelectionValueRegister =
legacySpeedSelectionValueRegister =
getInstruction<TwoRegisterInstruction>(speedSelectionValueInstructionIndex).registerA
setPlaybackSpeedClassFieldReference =
getInstruction<ReferenceInstruction>(speedSelectionValueInstructionIndex + 1).reference.toString()
setPlaybackSpeedMethodReference =
getInstruction<ReferenceInstruction>(speedSelectionValueInstructionIndex + 2).reference.toString()
setPlaybackSpeedContainerClassFieldReference =
getReference(speedSelectionMethodInstructions, -1, Opcode.IF_EQZ)
speedSelectionInsertIndex = speedSelectionValueInstructionIndex + 1
} ?: throw OnPlaybackSpeedItemClickFingerprint.exception
legacySpeedSelectionInsertIndex = speedSelectionValueInstructionIndex + 1
}

// New playback speed menu.
PlaybackSpeedMenuSpeedChangedFingerprint.alsoResolve(
context,
NewVideoQualityChangedFingerprint
).mutableMethod.apply {
val index = indexOfFirstInstructionOrThrow(Opcode.IGET)
speedSelectionInsertMethod = this
speedSelectionInsertIndex = index + 1
speedSelectionValueRegister = getInstruction<TwoRegisterInstruction>(index).registerA
}

userSelectedPlaybackSpeedHook(INTEGRATIONS_CLASS_DESCRIPTOR, "userSelectedPlaybackSpeed")
}
Expand Down Expand Up @@ -278,9 +297,15 @@ object VideoInformationPatch : BytecodePatch(
/**
* Hook the video speed selected by the user.
*/
internal fun userSelectedPlaybackSpeedHook(targetMethodClass: String, targetMethodName: String) =
internal fun userSelectedPlaybackSpeedHook(targetMethodClass: String, targetMethodName: String) {
legacySpeedSelectionInsertMethod.addInstruction(
legacySpeedSelectionInsertIndex++,
"invoke-static { v$legacySpeedSelectionValueRegister }, $targetMethodClass->$targetMethodName(F)V"
)

speedSelectionInsertMethod.addInstruction(
speedSelectionInsertIndex++,
"invoke-static {v$speedSelectionValueRegister}, $targetMethodClass->$targetMethodName(F)V"
"invoke-static { v$speedSelectionValueRegister }, $targetMethodClass->$targetMethodName(F)V"
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ import app.revanced.patches.shared.misc.settings.preference.ListPreference
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
import app.revanced.patches.youtube.misc.settings.SettingsPatch
import app.revanced.patches.youtube.shared.fingerprints.NewVideoQualityChangedFingerprint
import app.revanced.patches.youtube.video.information.VideoInformationPatch
import app.revanced.patches.youtube.video.quality.fingerprints.NewVideoQualityChangedFingerprint
import app.revanced.patches.youtube.video.quality.fingerprints.SetQualityByIndexMethodClassFieldReferenceFingerprint
import app.revanced.patches.youtube.video.quality.fingerprints.VideoQualityItemOnClickParentFingerprint
import app.revanced.patches.youtube.video.quality.fingerprints.VideoQualitySetterFingerprint
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package app.revanced.patches.youtube.video.quality.fingerprints

import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patches.youtube.shared.fingerprints.NewVideoQualityChangedFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode

/**
* Resolves with the class found in [NewVideoQualityChangedFingerprint].
*/
internal object PlaybackSpeedMenuSpeedChangedFingerprint : MethodFingerprint(
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
returnType = "L",
parameters = listOf("L"),
opcodes = listOf(
Opcode.IGET_OBJECT,
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT_OBJECT,
Opcode.IF_EQZ,
Opcode.IGET_OBJECT,
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT_OBJECT,
Opcode.IGET,
Opcode.INVOKE_VIRTUAL,
Opcode.SGET_OBJECT,
Opcode.RETURN_OBJECT,
)
)
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch
import app.revanced.patches.youtube.video.information.VideoInformationPatch
import app.revanced.patches.youtube.video.speed.custom.CustomPlaybackSpeedPatch
import app.revanced.patches.youtube.video.speed.remember.fingerprint.InitializePlaybackSpeedValuesFingerprint
import app.revanced.util.exception
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction

@Patch(
Expand Down Expand Up @@ -54,7 +54,7 @@ object RememberPlaybackSpeedPatch : BytecodePatch(
/*
* Hook the code that is called when the playback speeds are initialized, and sets the playback speed
*/
InitializePlaybackSpeedValuesFingerprint.result?.apply {
InitializePlaybackSpeedValuesFingerprint.resultOrThrow().apply {
// Infer everything necessary for calling the method setPlaybackSpeed().
val onItemClickListenerClassFieldReference =
mutableMethod.getInstruction<ReferenceInstruction>(0).reference
Expand All @@ -67,7 +67,7 @@ object RememberPlaybackSpeedPatch : BytecodePatch(
move-result v0

# Check if the playback speed is not 1.0x.
const/high16 v1, 0x3f800000 # 1.0f
const/high16 v1, 1.0f
cmpg-float v1, v0, v1
if-eqz v1, :do_not_override

Expand All @@ -82,9 +82,9 @@ object RememberPlaybackSpeedPatch : BytecodePatch(

# Invoke setPlaybackSpeed on that class.
invoke-virtual {v2, v0}, ${VideoInformationPatch.setPlaybackSpeedMethodReference}
""".trimIndent(),
""",
ExternalLabel("do_not_override", mutableMethod.getInstruction(0))
)
} ?: throw InitializePlaybackSpeedValuesFingerprint.exception
}
}
}
Loading