fix(YouTube - Player components): Speed overlay value only works when set to 1.0 or higher https://github.com/inotia00/ReVanced_Extended/issues/2849

This commit is contained in:
inotia00
2025-03-24 21:23:46 +09:00
parent fd32e4a854
commit 529e0163cc
4 changed files with 81 additions and 16 deletions

View File

@ -88,6 +88,8 @@ internal val speedOverlayFingerprint = legacyFingerprint(
literals = listOf(SPEED_OVERLAY_FEATURE_FLAG),
)
internal const val SPEED_OVERLAY_LEGACY_FEATURE_FLAG = 45411328L
/**
* This value is the key for the playback speed overlay value.
* Deprecated in YouTube v19.18.41+.
@ -97,7 +99,7 @@ internal val speedOverlayFloatValueFingerprint = legacyFingerprint(
returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
opcodes = listOf(Opcode.DOUBLE_TO_FLOAT),
literals = listOf(45411328L),
literals = listOf(SPEED_OVERLAY_LEGACY_FEATURE_FLAG),
)
internal val speedOverlayTextValueFingerprint = legacyFingerprint(

View File

@ -24,9 +24,11 @@ import app.revanced.patches.youtube.utils.engagement.engagementPanelIdRegister
import app.revanced.patches.youtube.utils.extension.Constants.COMPONENTS_PATH
import app.revanced.patches.youtube.utils.extension.Constants.PLAYER_CLASS_DESCRIPTOR
import app.revanced.patches.youtube.utils.extension.Constants.SPANS_PATH
import app.revanced.patches.youtube.utils.extension.sharedExtensionPatch
import app.revanced.patches.youtube.utils.fix.suggestedvideoendscreen.suggestedVideoEndScreenPatch
import app.revanced.patches.youtube.utils.patch.PatchList.PLAYER_COMPONENTS
import app.revanced.patches.youtube.utils.playertype.playerTypeHookPatch
import app.revanced.patches.youtube.utils.playservice.is_19_18_or_greater
import app.revanced.patches.youtube.utils.playservice.is_20_02_or_greater
import app.revanced.patches.youtube.utils.playservice.is_20_03_or_greater
import app.revanced.patches.youtube.utils.playservice.is_20_05_or_greater
@ -45,23 +47,27 @@ import app.revanced.patches.youtube.video.information.videoInformationPatch
import app.revanced.util.REGISTER_TEMPLATE_REPLACEMENT
import app.revanced.util.Utils.printWarn
import app.revanced.util.findMethodOrThrow
import app.revanced.util.findMutableMethodOf
import app.revanced.util.fingerprint.injectLiteralInstructionBooleanCall
import app.revanced.util.fingerprint.injectLiteralInstructionViewCall
import app.revanced.util.fingerprint.matchOrThrow
import app.revanced.util.fingerprint.methodOrThrow
import app.revanced.util.fingerprint.mutableClassOrThrow
import app.revanced.util.fingerprint.resolvable
import app.revanced.util.getReference
import app.revanced.util.getWalkerMethod
import app.revanced.util.indexOfFirstInstruction
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
import app.revanced.util.indexOfFirstLiteralInstructionOrThrow
import app.revanced.util.or
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
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.NarrowLiteralInstruction
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.ThreeRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.WideLiteralInstruction
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
@ -70,7 +76,11 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
private val speedOverlayPatch = bytecodePatch(
description = "speedOverlayPatch"
) {
dependsOn(sharedResourceIdPatch)
dependsOn(
sharedExtensionPatch,
sharedResourceIdPatch,
versionCheckPatch,
)
execute {
fun MutableMethod.hookSpeedOverlay(
@ -87,11 +97,19 @@ private val speedOverlayPatch = bytecodePatch(
)
}
val resolvable = restoreSlideToSeekBehaviorFingerprint.resolvable() &&
speedOverlayFingerprint.resolvable() &&
speedOverlayFloatValueFingerprint.resolvable()
fun MutableMethod.hookRelativeSpeedValue(startIndex: Int) {
val relativeIndex = indexOfFirstInstructionOrThrow(startIndex, Opcode.CMPL_FLOAT)
val relativeRegister = getInstruction<ThreeRegisterInstruction>(relativeIndex).registerB
if (resolvable) {
addInstructions(
relativeIndex, """
invoke-static {v$relativeRegister}, $PLAYER_CLASS_DESCRIPTOR->speedOverlayRelativeValue(F)F
move-result v$relativeRegister
"""
)
}
if (!is_19_18_or_greater) {
// Used on YouTube 18.29.38 ~ YouTube 19.17.41
// region patch for Disable speed overlay (Enable slide to seek)
@ -110,17 +128,51 @@ private val speedOverlayPatch = bytecodePatch(
// region patch for Custom speed overlay float value
speedOverlayFloatValueFingerprint.matchOrThrow().let {
it.method.apply {
val index = it.patternMatch!!.startIndex
val register = getInstruction<TwoRegisterInstruction>(index).registerA
val speedFieldReference = with (speedOverlayFloatValueFingerprint.methodOrThrow()) {
val literalIndex = indexOfFirstLiteralInstructionOrThrow(SPEED_OVERLAY_LEGACY_FEATURE_FLAG)
val floatIndex = indexOfFirstInstructionOrThrow(literalIndex, Opcode.DOUBLE_TO_FLOAT)
val floatRegister = getInstruction<TwoRegisterInstruction>(floatIndex).registerA
addInstructions(
index + 1, """
invoke-static {v$register}, $PLAYER_CLASS_DESCRIPTOR->speedOverlayValue(F)F
move-result v$register
addInstructions(
floatIndex + 1, """
invoke-static {v$floatRegister}, $PLAYER_CLASS_DESCRIPTOR->speedOverlayValue(F)F
move-result v$floatRegister
"""
)
)
val speedFieldIndex = indexOfFirstInstructionOrThrow(literalIndex) {
opcode == Opcode.IPUT &&
getReference<FieldReference>()?.type == "F"
}
getInstruction<ReferenceInstruction>(speedFieldIndex).reference.toString()
}
fun indexOfFirstSpeedFieldInstruction(method: Method) =
method.indexOfFirstInstruction {
opcode == Opcode.IGET &&
getReference<FieldReference>()?.toString() == speedFieldReference
}
val isSyntheticMethod: Method.() -> Boolean = {
name == "run" &&
accessFlags == AccessFlags.PUBLIC or AccessFlags.FINAL &&
parameterTypes.isEmpty() &&
indexOfFirstSpeedFieldInstruction(this) >= 0 &&
indexOfFirstInstruction(Opcode.CMPL_FLOAT) >= 0
}
classes.forEach { classDef ->
classDef.methods.forEach { method ->
if (method.isSyntheticMethod()) {
proxy(classDef)
.mutableClass
.findMutableMethodOf(method)
.apply {
val speedFieldIndex = indexOfFirstSpeedFieldInstruction(this)
hookRelativeSpeedValue(speedFieldIndex)
}
}
}
}
@ -241,6 +293,8 @@ private val speedOverlayPatch = bytecodePatch(
move-result v$speedOverlayFloatValueRegister
"""
)
hookRelativeSpeedValue(speedOverlayFloatValueIndex)
}
// Removed in YouTube 20.03+

View File

@ -31,6 +31,8 @@ var is_19_16_or_greater = false
private set
var is_19_17_or_greater = false
private set
var is_19_18_or_greater = false
private set
var is_19_23_or_greater = false
private set
var is_19_25_or_greater = false
@ -97,6 +99,7 @@ val versionCheckPatch = resourcePatch(
is_19_15_or_greater = 241602000 <= playStoreServicesVersion
is_19_16_or_greater = 241702000 <= playStoreServicesVersion
is_19_17_or_greater = 241802000 <= playStoreServicesVersion
is_19_18_or_greater = 241902000 <= playStoreServicesVersion
is_19_23_or_greater = 242402000 <= playStoreServicesVersion
is_19_25_or_greater = 242599000 <= playStoreServicesVersion
is_19_26_or_greater = 242705000 <= playStoreServicesVersion