feat(youtube): add save-video-speed settings

This commit is contained in:
inotia00
2023-01-08 00:51:37 +09:00
parent be62437ab3
commit a1a74e7c51
6 changed files with 124 additions and 95 deletions

View File

@ -0,0 +1,17 @@
package app.revanced.patches.youtube.video.speed.bytecode.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.Opcode
object VideoSpeedChangedFingerprint : MethodFingerprint(
opcodes = listOf(
Opcode.IGET_OBJECT,
Opcode.IF_EQZ,
Opcode.IF_EQZ,
Opcode.IGET,
Opcode.CHECK_CAST,
Opcode.IGET_OBJECT,
Opcode.INVOKE_VIRTUAL
),
customFingerprint = { it.name == "onItemClick" }
)

View File

@ -0,0 +1,8 @@
package app.revanced.patches.youtube.video.speed.bytecode.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
object VideoSpeedParentFingerprint : MethodFingerprint(
returnType = "V",
strings = listOf("PLAYBACK_RATE_MENU_BOTTOM_SHEET_FRAGMENT")
)

View File

@ -1,27 +0,0 @@
package app.revanced.patches.youtube.video.speed.bytecode.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
object VideoUserSpeedChangeFingerprint : MethodFingerprint(
"V",
AccessFlags.PUBLIC or AccessFlags.FINAL,
listOf("L","L","I","J"),
listOf(
Opcode.IGET_OBJECT,
Opcode.IF_EQZ,
Opcode.IF_EQZ,
Opcode.IGET,
Opcode.CHECK_CAST,
Opcode.IGET_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.IGET_OBJECT,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.INVOKE_VIRTUAL,
Opcode.RETURN_VOID
)
)

View File

@ -7,22 +7,25 @@ import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
import app.revanced.patcher.util.smali.toInstructions
import app.revanced.patches.youtube.video.speed.bytecode.fingerprints.VideoSpeedSetterFingerprint
import app.revanced.patches.youtube.video.speed.bytecode.fingerprints.VideoUserSpeedChangeFingerprint
import app.revanced.patches.youtube.misc.videoid.legacy.patch.LegacyVideoIdPatch
import app.revanced.patches.youtube.video.speed.bytecode.fingerprints.VideoSpeedChangedFingerprint
import app.revanced.patches.youtube.video.speed.bytecode.fingerprints.VideoSpeedParentFingerprint
import app.revanced.patches.youtube.video.speed.bytecode.fingerprints.VideoSpeedSetterFingerprint
import app.revanced.shared.annotation.YouTubeCompatibility
import app.revanced.shared.extensions.toErrorResult
import app.revanced.shared.util.bytecode.BytecodeHelper
import app.revanced.shared.util.integrations.Constants.VIDEO_PATH
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.dexbacked.reference.DexBackedMethodReference
import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.reference.FieldReference
import org.jf.dexlib2.iface.reference.MethodReference
import org.jf.dexlib2.immutable.ImmutableMethod
import org.jf.dexlib2.immutable.ImmutableMethodImplementation
import org.jf.dexlib2.immutable.ImmutableMethodParameter
@ -33,74 +36,83 @@ import org.jf.dexlib2.immutable.ImmutableMethodParameter
@Version("0.0.1")
class VideoSpeedBytecodePatch : BytecodePatch(
listOf(
VideoSpeedSetterFingerprint, VideoUserSpeedChangeFingerprint
VideoSpeedChangedFingerprint,
VideoSpeedParentFingerprint,
VideoSpeedSetterFingerprint
)
) {
private companion object {
const val INTEGRATIONS_VIDEO_SPEED_CLASS_DESCRIPTOR =
"$VIDEO_PATH/VideoSpeedPatch;"
}
override fun execute(context: BytecodeContext): PatchResult {
val userSpeedResult = VideoUserSpeedChangeFingerprint.result!!
val userSpeedMutableMethod = userSpeedResult.mutableMethod
VideoSpeedParentFingerprint.result?.let { parentResult ->
val parentClassDef = parentResult.classDef
val setterResult = VideoSpeedSetterFingerprint.result!!
val setterMutableMethod = setterResult.mutableMethod
VideoSpeedChangedFingerprint.also { it.resolve(context, parentClassDef) }.result?.let { result ->
startIndex = result.scanResult.patternScanResult!!.startIndex
endIndex = result.scanResult.patternScanResult!!.endIndex
with (result.method) {
val speedInstruction = implementation!!.instructions
VideoUserSpeedChangeFingerprint.resolve(context, setterResult.classDef)
val FirstReference =
VideoUserSpeedChangeFingerprint.result!!.method.let { method ->
(method.implementation!!.instructions.elementAt(5) as ReferenceInstruction).reference as FieldReference
}
val SecondReference =
VideoUserSpeedChangeFingerprint.result!!.method.let { method ->
(method.implementation!!.instructions.elementAt(10) as ReferenceInstruction).reference as FieldReference
}
val ThirdReference =
VideoUserSpeedChangeFingerprint.result!!.method.let { method ->
(method.implementation!!.instructions.elementAt(11) as ReferenceInstruction).reference as MethodReference
}
firstRef =
(speedInstruction.elementAt(startIndex) as ReferenceInstruction).reference as FieldReference
userSpeedMutableMethod.addInstruction(
0, "invoke-static {}, $INTEGRATIONS_VIDEO_SPEED_CLASS_DESCRIPTOR->userChangedSpeed()V"
)
secondRef =
(speedInstruction.elementAt(endIndex - 1) as ReferenceInstruction).reference as FieldReference
setterMutableMethod.addInstructions(
0,
"""
invoke-static {p1, p2}, $INTEGRATIONS_VIDEO_SPEED_CLASS_DESCRIPTOR->getSpeedValue([Ljava/lang/Object;I)F
move-result v0
invoke-direct {p0, v0}, ${setterResult.classDef.type}->overrideSpeed(F)V
""",
)
thirdRef =
(speedInstruction.elementAt(endIndex) as ReferenceInstruction).reference as DexBackedMethodReference
val classDef = userSpeedResult.mutableClass
classDef.methods.add(
ImmutableMethod(
classDef.type,
"overrideSpeed",
listOf(ImmutableMethodParameter("F", null, null)),
"V",
AccessFlags.PRIVATE or AccessFlags.PRIVATE,
null,
null,
ImmutableMethodImplementation(
4, """
const/4 v0, 0x0
cmpg-float v0, v3, v0
if-gez v0, :cond_0
return-void
:cond_0
iget-object v0, v2, ${setterResult.classDef.type}->${FirstReference.name}:${FirstReference.type}
check-cast v0, ${SecondReference.definingClass}
iget-object v1, v0, ${SecondReference.definingClass}->${SecondReference.name}:${SecondReference.type}
invoke-virtual {v1, v3}, $ThirdReference
return-void
""".toInstructions(), null, null
val register =
(speedInstruction.elementAt(endIndex) as FiveRegisterInstruction).registerD
result.mutableMethod.addInstruction(
endIndex,
"invoke-static { v$register }, $INTEGRATIONS_VIDEO_SPEED_CLASS_DESCRIPTOR" +
"->" +
"userChangedSpeed(F)V"
)
}
} ?: return VideoSpeedChangedFingerprint.toErrorResult()
val parentMutableClass = parentResult.mutableClass
parentMutableClass.methods.add(
ImmutableMethod(
parentMutableClass.type,
"overrideSpeed",
listOf(ImmutableMethodParameter("F", null, null)),
"V",
AccessFlags.PRIVATE or AccessFlags.PRIVATE,
null,
null,
ImmutableMethodImplementation(
4, """
const/4 v0, 0x0
cmpg-float v0, v3, v0
if-lez v0, :cond_0
iget-object v0, v2, ${parentClassDef.type}->${firstRef.name}:${firstRef.type}
check-cast v0, ${secondRef.definingClass}
iget-object v1, v0, ${secondRef.definingClass}->${secondRef.name}:${secondRef.type}
invoke-virtual {v1, v3}, $thirdRef
:cond_0
return-void
""".toInstructions(), null, null
)
).toMutable()
)
} ?: return VideoSpeedParentFingerprint.toErrorResult()
VideoSpeedSetterFingerprint.result?.let { result ->
result.mutableMethod.addInstructions(
0, """
invoke-static {}, $INTEGRATIONS_VIDEO_SPEED_CLASS_DESCRIPTOR->getSpeedValue()F
move-result v0
invoke-direct {p0, v0}, ${result.classDef.type}->overrideSpeed(F)V
""",
)
).toMutable()
)
} ?: return VideoSpeedSetterFingerprint.toErrorResult()
LegacyVideoIdPatch.injectCall("$INTEGRATIONS_VIDEO_SPEED_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;)V")
@ -108,4 +120,16 @@ class VideoSpeedBytecodePatch : BytecodePatch(
return PatchResultSuccess()
}
private companion object {
const val INTEGRATIONS_VIDEO_SPEED_CLASS_DESCRIPTOR =
"$VIDEO_PATH/VideoSpeedPatch;"
var startIndex: Int = 0
var endIndex: Int = 0
private lateinit var firstRef: FieldReference
private lateinit var secondRef: FieldReference
private lateinit var thirdRef: DexBackedMethodReference
}
}