mirror of
https://github.com/revanced/revanced-patches
synced 2024-12-27 11:25:50 +01:00
fix(YouTube - Playback speed): Allow long press 2x speed when using custom playback speeds (#3990)
This commit is contained in:
parent
d3a2fb17f1
commit
79a543a574
@ -1,14 +1,14 @@
|
|||||||
package app.revanced.extension.youtube.patches;
|
package app.revanced.extension.youtube.patches;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import app.revanced.extension.youtube.patches.playback.speed.RememberPlaybackSpeedPatch;
|
|
||||||
import app.revanced.extension.youtube.shared.VideoState;
|
|
||||||
import app.revanced.extension.shared.Logger;
|
|
||||||
import app.revanced.extension.shared.Utils;
|
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import app.revanced.extension.shared.Logger;
|
||||||
|
import app.revanced.extension.shared.Utils;
|
||||||
|
import app.revanced.extension.youtube.shared.VideoState;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hooking class for the current playing video.
|
* Hooking class for the current playing video.
|
||||||
* @noinspection unused
|
* @noinspection unused
|
||||||
@ -120,6 +120,16 @@ public final class VideoInformation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point.
|
||||||
|
*/
|
||||||
|
public static void videoSpeedChanged(float currentVideoSpeed) {
|
||||||
|
if (playbackSpeed != currentVideoSpeed) {
|
||||||
|
Logger.printDebug(() -> "Video speed changed: " + currentVideoSpeed);
|
||||||
|
playbackSpeed = currentVideoSpeed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Injection point.
|
* Injection point.
|
||||||
* Called when user selects a playback speed.
|
* Called when user selects a playback speed.
|
||||||
@ -131,18 +141,6 @@ public final class VideoInformation {
|
|||||||
playbackSpeed = userSelectedPlaybackSpeed;
|
playbackSpeed = userSelectedPlaybackSpeed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Overrides the current playback speed.
|
|
||||||
* <p>
|
|
||||||
* <b> Used exclusively by {@link RememberPlaybackSpeedPatch} </b>
|
|
||||||
*/
|
|
||||||
public static void overridePlaybackSpeed(float speedOverride) {
|
|
||||||
if (playbackSpeed != speedOverride) {
|
|
||||||
Logger.printDebug(() -> "Overriding playback speed to: " + speedOverride);
|
|
||||||
playbackSpeed = speedOverride;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Injection point.
|
* Injection point.
|
||||||
*
|
*
|
||||||
|
@ -12,6 +12,8 @@ public final class RememberPlaybackSpeedPatch {
|
|||||||
|
|
||||||
private static final long TOAST_DELAY_MILLISECONDS = 750;
|
private static final long TOAST_DELAY_MILLISECONDS = 750;
|
||||||
|
|
||||||
|
private static volatile boolean newVideoStarted;
|
||||||
|
|
||||||
private static long lastTimeSpeedChanged;
|
private static long lastTimeSpeedChanged;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -19,7 +21,7 @@ public final class RememberPlaybackSpeedPatch {
|
|||||||
*/
|
*/
|
||||||
public static void newVideoStarted(VideoInformation.PlaybackController ignoredPlayerController) {
|
public static void newVideoStarted(VideoInformation.PlaybackController ignoredPlayerController) {
|
||||||
Logger.printDebug(() -> "newVideoStarted");
|
Logger.printDebug(() -> "newVideoStarted");
|
||||||
VideoInformation.overridePlaybackSpeed(Settings.PLAYBACK_SPEED_DEFAULT.get());
|
newVideoStarted = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -29,42 +31,56 @@ public final class RememberPlaybackSpeedPatch {
|
|||||||
* @param playbackSpeed The playback speed the user selected
|
* @param playbackSpeed The playback speed the user selected
|
||||||
*/
|
*/
|
||||||
public static void userSelectedPlaybackSpeed(float playbackSpeed) {
|
public static void userSelectedPlaybackSpeed(float playbackSpeed) {
|
||||||
if (Settings.REMEMBER_PLAYBACK_SPEED_LAST_SELECTED.get()) {
|
try {
|
||||||
// With the 0.05x menu, if the speed is set by integrations to higher than 2.0x
|
if (Settings.REMEMBER_PLAYBACK_SPEED_LAST_SELECTED.get()) {
|
||||||
// then the menu will allow increasing without bounds but the max speed is
|
// With the 0.05x menu, if the speed is set by integrations to higher than 2.0x
|
||||||
// still capped to under 8.0x.
|
// then the menu will allow increasing without bounds but the max speed is
|
||||||
playbackSpeed = Math.min(playbackSpeed, CustomPlaybackSpeedPatch.PLAYBACK_SPEED_MAXIMUM - 0.05f);
|
// still capped to under 8.0x.
|
||||||
|
playbackSpeed = Math.min(playbackSpeed, CustomPlaybackSpeedPatch.PLAYBACK_SPEED_MAXIMUM - 0.05f);
|
||||||
|
|
||||||
// Prevent toast spamming if using the 0.05x adjustments.
|
// Prevent toast spamming if using the 0.05x adjustments.
|
||||||
// Show exactly one toast after the user stops interacting with the speed menu.
|
// Show exactly one toast after the user stops interacting with the speed menu.
|
||||||
final long now = System.currentTimeMillis();
|
final long now = System.currentTimeMillis();
|
||||||
lastTimeSpeedChanged = now;
|
lastTimeSpeedChanged = now;
|
||||||
|
|
||||||
final float finalPlaybackSpeed = playbackSpeed;
|
final float finalPlaybackSpeed = playbackSpeed;
|
||||||
Utils.runOnMainThreadDelayed(() -> {
|
Utils.runOnMainThreadDelayed(() -> {
|
||||||
if (lastTimeSpeedChanged != now) {
|
if (lastTimeSpeedChanged != now) {
|
||||||
// The user made additional speed adjustments and this call is outdated.
|
// The user made additional speed adjustments and this call is outdated.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Settings.PLAYBACK_SPEED_DEFAULT.get() == finalPlaybackSpeed) {
|
if (Settings.PLAYBACK_SPEED_DEFAULT.get() == finalPlaybackSpeed) {
|
||||||
// User changed to a different speed and immediately changed back.
|
// User changed to a different speed and immediately changed back.
|
||||||
// Or the user is going past 8.0x in the glitched out 0.05x menu.
|
// Or the user is going past 8.0x in the glitched out 0.05x menu.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Settings.PLAYBACK_SPEED_DEFAULT.save(finalPlaybackSpeed);
|
Settings.PLAYBACK_SPEED_DEFAULT.save(finalPlaybackSpeed);
|
||||||
|
|
||||||
Utils.showToastLong(str("revanced_remember_playback_speed_toast", (finalPlaybackSpeed + "x")));
|
Utils.showToastLong(str("revanced_remember_playback_speed_toast", (finalPlaybackSpeed + "x")));
|
||||||
}, TOAST_DELAY_MILLISECONDS);
|
}, TOAST_DELAY_MILLISECONDS);
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Logger.printException(() -> "userSelectedPlaybackSpeed failure", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Injection point.
|
* Injection point.
|
||||||
* Overrides the video speed. Called after video loads, and immediately after user selects a different playback speed
|
* Overrides the video speed. Called after video loads,
|
||||||
|
* and immediately after the user selects a different playback speed.
|
||||||
*/
|
*/
|
||||||
public static float getPlaybackSpeedOverride() {
|
public static float getPlaybackSpeedOverride() {
|
||||||
return VideoInformation.getPlaybackSpeed();
|
if (newVideoStarted) {
|
||||||
|
newVideoStarted = false;
|
||||||
|
|
||||||
|
final float defaultSpeed = Settings.PLAYBACK_SPEED_DEFAULT.get();
|
||||||
|
if (defaultSpeed > 0) {
|
||||||
|
return defaultSpeed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -2.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1370,11 +1370,9 @@ public final class app/revanced/patches/youtube/shared/FingerprintsKt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final class app/revanced/patches/youtube/video/information/VideoInformationPatchKt {
|
public final class app/revanced/patches/youtube/video/information/VideoInformationPatchKt {
|
||||||
public static final fun getSetPlaybackSpeedClassFieldReference ()Ljava/lang/String;
|
|
||||||
public static final fun getSetPlaybackSpeedContainerClassFieldReference ()Ljava/lang/String;
|
|
||||||
public static final fun getSetPlaybackSpeedMethodReference ()Ljava/lang/String;
|
|
||||||
public static final fun getVideoInformationPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getVideoInformationPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
public static final fun userSelectedPlaybackSpeedHook (Ljava/lang/String;Ljava/lang/String;)V
|
public static final fun userSelectedPlaybackSpeedHook (Ljava/lang/String;Ljava/lang/String;)V
|
||||||
|
public static final fun videoSpeedChangedHook (Ljava/lang/String;Ljava/lang/String;)V
|
||||||
public static final fun videoTimeHook (Ljava/lang/String;Ljava/lang/String;)V
|
public static final fun videoTimeHook (Ljava/lang/String;Ljava/lang/String;)V
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,13 +20,13 @@ import app.revanced.util.getReference
|
|||||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||||
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.MutableMethodImplementation
|
import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation
|
||||||
import com.android.tools.smali.dexlib2.iface.Method
|
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.FiveRegisterInstruction
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
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.ReferenceInstruction
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||||
|
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||||
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
|
||||||
@ -57,12 +57,16 @@ private lateinit var speedSelectionInsertMethod: MutableMethod
|
|||||||
private var speedSelectionInsertIndex = -1
|
private var speedSelectionInsertIndex = -1
|
||||||
private var speedSelectionValueRegister = -1
|
private var speedSelectionValueRegister = -1
|
||||||
|
|
||||||
|
// Change playback speed method.
|
||||||
|
private lateinit var setPlaybackSpeedMethod: MutableMethod
|
||||||
|
private var setPlaybackSpeedMethodIndex = -1
|
||||||
|
|
||||||
// Used by other patches.
|
// Used by other patches.
|
||||||
lateinit var setPlaybackSpeedContainerClassFieldReference: String
|
internal lateinit var setPlaybackSpeedContainerClassFieldReference: FieldReference
|
||||||
private set
|
private set
|
||||||
lateinit var setPlaybackSpeedClassFieldReference: String
|
internal lateinit var setPlaybackSpeedClassFieldReference: FieldReference
|
||||||
private set
|
private set
|
||||||
lateinit var setPlaybackSpeedMethodReference: String
|
internal lateinit var setPlaybackSpeedMethodReference: MethodReference
|
||||||
private set
|
private set
|
||||||
|
|
||||||
val videoInformationPatch = bytecodePatch(
|
val videoInformationPatch = bytecodePatch(
|
||||||
@ -164,24 +168,27 @@ val videoInformationPatch = bytecodePatch(
|
|||||||
videoTimeHook(EXTENSION_CLASS_DESCRIPTOR, "setVideoTime")
|
videoTimeHook(EXTENSION_CLASS_DESCRIPTOR, "setVideoTime")
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Hook the user playback speed selection
|
* Hook the user playback speed selection.
|
||||||
*/
|
*/
|
||||||
onPlaybackSpeedItemClickFingerprint.method.apply {
|
onPlaybackSpeedItemClickFingerprint.method.apply {
|
||||||
val speedSelectionMethodInstructions = implementation!!.instructions
|
val speedSelectionValueInstructionIndex = indexOfFirstInstructionOrThrow(Opcode.IGET)
|
||||||
val speedSelectionValueInstructionIndex = speedSelectionMethodInstructions.indexOfFirst {
|
|
||||||
it.opcode == Opcode.IGET
|
|
||||||
}
|
|
||||||
legacySpeedSelectionInsertMethod = this
|
legacySpeedSelectionInsertMethod = this
|
||||||
legacySpeedSelectionInsertIndex = speedSelectionValueInstructionIndex + 1
|
legacySpeedSelectionInsertIndex = speedSelectionValueInstructionIndex + 1
|
||||||
legacySpeedSelectionValueRegister =
|
legacySpeedSelectionValueRegister =
|
||||||
getInstruction<TwoRegisterInstruction>(speedSelectionValueInstructionIndex).registerA
|
getInstruction<TwoRegisterInstruction>(speedSelectionValueInstructionIndex).registerA
|
||||||
|
|
||||||
setPlaybackSpeedClassFieldReference =
|
|
||||||
getInstruction<ReferenceInstruction>(speedSelectionValueInstructionIndex + 1).reference.toString()
|
|
||||||
setPlaybackSpeedMethodReference =
|
setPlaybackSpeedMethodReference =
|
||||||
getInstruction<ReferenceInstruction>(speedSelectionValueInstructionIndex + 2).reference.toString()
|
getInstruction<ReferenceInstruction>(speedSelectionValueInstructionIndex + 2).reference as MethodReference
|
||||||
|
setPlaybackSpeedClassFieldReference =
|
||||||
|
getInstruction<ReferenceInstruction>(speedSelectionValueInstructionIndex + 1).reference as FieldReference
|
||||||
setPlaybackSpeedContainerClassFieldReference =
|
setPlaybackSpeedContainerClassFieldReference =
|
||||||
getReference(speedSelectionMethodInstructions, -1, Opcode.IF_EQZ)
|
getInstruction<ReferenceInstruction>(indexOfFirstInstructionOrThrow(Opcode.IF_EQZ) - 1).reference as FieldReference
|
||||||
|
|
||||||
|
setPlaybackSpeedMethod =
|
||||||
|
proxy(classes.first { it.type == setPlaybackSpeedMethodReference.definingClass })
|
||||||
|
.mutableClass.methods.first { it.name == setPlaybackSpeedMethodReference.name }
|
||||||
|
setPlaybackSpeedMethodIndex = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle new playback speed menu.
|
// Handle new playback speed menu.
|
||||||
@ -195,6 +202,7 @@ val videoInformationPatch = bytecodePatch(
|
|||||||
speedSelectionValueRegister = getInstruction<TwoRegisterInstruction>(index).registerA
|
speedSelectionValueRegister = getInstruction<TwoRegisterInstruction>(index).registerA
|
||||||
}
|
}
|
||||||
|
|
||||||
|
videoSpeedChangedHook(EXTENSION_CLASS_DESCRIPTOR, "videoSpeedChanged")
|
||||||
userSelectedPlaybackSpeedHook(EXTENSION_CLASS_DESCRIPTOR, "userSelectedPlaybackSpeed")
|
userSelectedPlaybackSpeedHook(EXTENSION_CLASS_DESCRIPTOR, "userSelectedPlaybackSpeed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -295,9 +303,14 @@ fun videoTimeHook(targetMethodClass: String, targetMethodName: String) =
|
|||||||
"$targetMethodClass->$targetMethodName(J)V",
|
"$targetMethodClass->$targetMethodName(J)V",
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun getReference(instructions: List<BuilderInstruction>, offset: Int, opcode: Opcode) =
|
/**
|
||||||
(instructions[instructions.indexOfFirst { it.opcode == opcode } + offset] as ReferenceInstruction)
|
* Hook when the video speed is changed for any reason _except when the user manually selects a new speed_.
|
||||||
.reference.toString()
|
*/
|
||||||
|
fun videoSpeedChangedHook(targetMethodClass: String, targetMethodName: String) =
|
||||||
|
setPlaybackSpeedMethod.addInstruction(
|
||||||
|
setPlaybackSpeedMethodIndex++,
|
||||||
|
"invoke-static { p1 }, $targetMethodClass->$targetMethodName(F)V"
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook the video speed selected by the user.
|
* Hook the video speed selected by the user.
|
||||||
@ -312,4 +325,4 @@ fun userSelectedPlaybackSpeedHook(targetMethodClass: String, targetMethodName: S
|
|||||||
speedSelectionInsertIndex++,
|
speedSelectionInsertIndex++,
|
||||||
"invoke-static { v$speedSelectionValueRegister }, $targetMethodClass->$targetMethodName(F)V",
|
"invoke-static { v$speedSelectionValueRegister }, $targetMethodClass->$targetMethodName(F)V",
|
||||||
)
|
)
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user