mirror of
https://github.com/revanced/revanced-patches
synced 2024-12-02 23:42:55 +01:00
feat(youtube/video-speed): change custom video speeds inside app settings (#2114)
This commit is contained in:
parent
6a2b6b6e03
commit
d97815af18
@ -1,6 +1,8 @@
|
|||||||
package app.revanced.patches.shared.settings.preference.impl
|
package app.revanced.patches.shared.settings.preference.impl
|
||||||
|
|
||||||
enum class InputType(val type: String) {
|
enum class InputType(val type: String) {
|
||||||
STRING("text"),
|
STRING("text"), // TODO: rename to "TEXT"
|
||||||
|
TEXT_CAP_CHARACTERS("textCapCharacters"),
|
||||||
|
TEXT_MULTI_LINE("textMultiLine"),
|
||||||
NUMBER("number"),
|
NUMBER("number"),
|
||||||
}
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
package app.revanced.patches.youtube.misc.video.speed
|
||||||
|
|
||||||
|
import app.revanced.patcher.annotation.Description
|
||||||
|
import app.revanced.patcher.annotation.Name
|
||||||
|
import app.revanced.patcher.annotation.Version
|
||||||
|
import app.revanced.patcher.data.BytecodeContext
|
||||||
|
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.patch.annotations.Patch
|
||||||
|
import app.revanced.patches.youtube.misc.video.speed.custom.patch.CustomVideoSpeedPatch
|
||||||
|
import app.revanced.patches.youtube.misc.video.speed.remember.patch.RememberPlaybackSpeedPatch
|
||||||
|
|
||||||
|
@Patch
|
||||||
|
@Name("video-speed")
|
||||||
|
@Description("Adds custom video speeds and ability to remember the playback speed you chose in the video playback speed flyout.")
|
||||||
|
@DependsOn([CustomVideoSpeedPatch::class, RememberPlaybackSpeedPatch::class])
|
||||||
|
@Version("0.0.1")
|
||||||
|
class VideoSpeeds : BytecodePatch() {
|
||||||
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
|
return PatchResultSuccess() // All sub patches succeeded.
|
||||||
|
}
|
||||||
|
}
|
@ -1,11 +0,0 @@
|
|||||||
package app.revanced.patches.youtube.misc.video.speed.custom.fingerprints
|
|
||||||
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
import org.jf.dexlib2.Opcode
|
|
||||||
|
|
||||||
object VideoSpeedPatchFingerprint : MethodFingerprint(
|
|
||||||
opcodes = listOf(Opcode.FILL_ARRAY_DATA),
|
|
||||||
customFingerprint = { methodDef ->
|
|
||||||
methodDef.definingClass.endsWith("CustomVideoSpeedPatch;") && methodDef.name == "<clinit>"
|
|
||||||
}
|
|
||||||
)
|
|
@ -8,37 +8,47 @@ import app.revanced.patcher.extensions.addInstructions
|
|||||||
import app.revanced.patcher.extensions.replaceInstruction
|
import app.revanced.patcher.extensions.replaceInstruction
|
||||||
import app.revanced.patcher.patch.*
|
import app.revanced.patcher.patch.*
|
||||||
import app.revanced.patcher.patch.annotations.DependsOn
|
import app.revanced.patcher.patch.annotations.DependsOn
|
||||||
import app.revanced.patcher.patch.annotations.Patch
|
import app.revanced.patches.shared.settings.preference.impl.InputType
|
||||||
|
import app.revanced.patches.shared.settings.preference.impl.StringResource
|
||||||
|
import app.revanced.patches.shared.settings.preference.impl.TextPreference
|
||||||
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.video.speed.custom.annotations.CustomPlaybackSpeedCompatibility
|
import app.revanced.patches.youtube.misc.video.speed.custom.annotations.CustomPlaybackSpeedCompatibility
|
||||||
import app.revanced.patches.youtube.misc.video.speed.custom.fingerprints.SpeedArrayGeneratorFingerprint
|
import app.revanced.patches.youtube.misc.video.speed.custom.fingerprints.SpeedArrayGeneratorFingerprint
|
||||||
import app.revanced.patches.youtube.misc.video.speed.custom.fingerprints.SpeedLimiterFingerprint
|
import app.revanced.patches.youtube.misc.video.speed.custom.fingerprints.SpeedLimiterFingerprint
|
||||||
import app.revanced.patches.youtube.misc.video.speed.custom.fingerprints.VideoSpeedPatchFingerprint
|
|
||||||
import org.jf.dexlib2.builder.instruction.BuilderArrayPayload
|
|
||||||
import org.jf.dexlib2.iface.instruction.NarrowLiteralInstruction
|
import org.jf.dexlib2.iface.instruction.NarrowLiteralInstruction
|
||||||
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.iface.instruction.ReferenceInstruction
|
||||||
import org.jf.dexlib2.iface.reference.FieldReference
|
import org.jf.dexlib2.iface.reference.FieldReference
|
||||||
import org.jf.dexlib2.iface.reference.MethodReference
|
import org.jf.dexlib2.iface.reference.MethodReference
|
||||||
import java.util.stream.DoubleStream
|
|
||||||
import kotlin.math.roundToInt
|
|
||||||
|
|
||||||
@Patch
|
|
||||||
@Name("custom-video-speed")
|
@Name("custom-video-speed")
|
||||||
@Description("Adds more video speed options.")
|
@Description("Adds custom video speed options.")
|
||||||
@DependsOn([IntegrationsPatch::class])
|
@DependsOn([IntegrationsPatch::class])
|
||||||
@CustomPlaybackSpeedCompatibility
|
@CustomPlaybackSpeedCompatibility
|
||||||
@Version("0.0.1")
|
@Version("0.0.1")
|
||||||
class CustomVideoSpeedPatch : BytecodePatch(
|
class CustomVideoSpeedPatch : BytecodePatch(
|
||||||
listOf(
|
listOf(
|
||||||
SpeedArrayGeneratorFingerprint, SpeedLimiterFingerprint, VideoSpeedPatchFingerprint
|
SpeedArrayGeneratorFingerprint, SpeedLimiterFingerprint
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
|
|
||||||
override fun execute(context: BytecodeContext): PatchResult {
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
val speedLimitMin = minVideoSpeed!!.toFloat()
|
SettingsPatch.PreferenceScreen.MISC.addPreferences(
|
||||||
val speedLimitMax = maxVideoSpeed!!.toFloat().coerceAtLeast(speedLimitMin)
|
TextPreference(
|
||||||
val speedsGranularity = videoSpeedsGranularity!!.toFloat()
|
key = "revanced_custom_video_speeds",
|
||||||
|
title = StringResource(
|
||||||
|
"revanced_custom_video_speeds_title",
|
||||||
|
"Custom playback speeds"
|
||||||
|
),
|
||||||
|
inputType = InputType.TEXT_MULTI_LINE,
|
||||||
|
summary = StringResource(
|
||||||
|
"revanced_custom_video_speeds_summary",
|
||||||
|
"Add or change the video speeds available"
|
||||||
|
),
|
||||||
|
default = "0.25\n0.5\n0.75\n0.9\n0.95\n1.0\n1.05\n1.1\n1.25\n1.5\n1.75\n2.0\n3.0\n4.0\n5.0"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
val arrayGenMethod = SpeedArrayGeneratorFingerprint.result?.mutableMethod!!
|
val arrayGenMethod = SpeedArrayGeneratorFingerprint.result?.mutableMethod!!
|
||||||
val arrayGenMethodImpl = arrayGenMethod.implementation!!
|
val arrayGenMethodImpl = arrayGenMethod.implementation!!
|
||||||
@ -61,7 +71,7 @@ class CustomVideoSpeedPatch : BytecodePatch(
|
|||||||
|
|
||||||
val arrayLengthConstDestination = (arrayLengthConst as OneRegisterInstruction).registerA
|
val arrayLengthConstDestination = (arrayLengthConst as OneRegisterInstruction).registerA
|
||||||
|
|
||||||
val videoSpeedsArrayType = "Lapp/revanced/integrations/patches/playback/speed/CustomVideoSpeedPatch;->videoSpeeds:[F"
|
val videoSpeedsArrayType = "Lapp/revanced/integrations/patches/playback/speed/CustomVideoSpeedPatch;->customVideoSpeeds:[F"
|
||||||
|
|
||||||
arrayGenMethod.addInstructions(
|
arrayGenMethod.addInstructions(
|
||||||
arrayLengthConstIndex + 1,
|
arrayLengthConstIndex + 1,
|
||||||
@ -96,100 +106,17 @@ class CustomVideoSpeedPatch : BytecodePatch(
|
|||||||
val limiterMinConstDestination = (limiterMinConst as OneRegisterInstruction).registerA
|
val limiterMinConstDestination = (limiterMinConst as OneRegisterInstruction).registerA
|
||||||
val limiterMaxConstDestination = (limiterMaxConst as OneRegisterInstruction).registerA
|
val limiterMaxConstDestination = (limiterMaxConst as OneRegisterInstruction).registerA
|
||||||
|
|
||||||
fun hexFloat(float: Float): String = "0x%08x".format(float.toRawBits())
|
// edit: alternatively this might work by overriding with fixed values such as 0.1x and 10x
|
||||||
|
|
||||||
limiterMethod.replaceInstruction(
|
limiterMethod.replaceInstruction(
|
||||||
limiterMinConstIndex,
|
limiterMinConstIndex,
|
||||||
"const/high16 v$limiterMinConstDestination, ${hexFloat(speedLimitMin)}"
|
"sget v$limiterMinConstDestination, Lapp/revanced/integrations/patches/playback/speed/CustomVideoSpeedPatch;->minVideoSpeed:F"
|
||||||
)
|
)
|
||||||
limiterMethod.replaceInstruction(
|
limiterMethod.replaceInstruction(
|
||||||
limiterMaxConstIndex,
|
limiterMaxConstIndex,
|
||||||
"const/high16 v$limiterMaxConstDestination, ${hexFloat(speedLimitMax)}"
|
"sget v$limiterMaxConstDestination, Lapp/revanced/integrations/patches/playback/speed/CustomVideoSpeedPatch;->maxVideoSpeed:F"
|
||||||
)
|
|
||||||
|
|
||||||
val constructorResult = VideoSpeedPatchFingerprint.result!!
|
|
||||||
val constructor = constructorResult.mutableMethod
|
|
||||||
val implementation = constructor.implementation!!
|
|
||||||
|
|
||||||
val stepsGranularity = 8F
|
|
||||||
val step = speedLimitMax
|
|
||||||
.minus(speedLimitMin) // calculate the range of the speeds
|
|
||||||
.div(speedsGranularity)
|
|
||||||
.times(stepsGranularity)
|
|
||||||
.roundToInt()
|
|
||||||
.div(stepsGranularity)// round to nearest multiple of stepsGranularity
|
|
||||||
.coerceAtLeast(1 / stepsGranularity) // ensure steps are at least 1/8th of the step granularity
|
|
||||||
|
|
||||||
val videoSpeedsArray = buildList<Number> {
|
|
||||||
DoubleStream
|
|
||||||
.iterate(speedLimitMin.toDouble()) { it + step } // create a stream of speeds
|
|
||||||
.let { speedStream ->
|
|
||||||
for (speed in speedStream) {
|
|
||||||
if (speed > speedLimitMax) break
|
|
||||||
add(speed.toFloat().toRawBits())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// adjust the new array of speeds size
|
|
||||||
constructor.replaceInstruction(
|
|
||||||
0,
|
|
||||||
"const/16 v0, ${videoSpeedsArray.size}"
|
|
||||||
)
|
|
||||||
|
|
||||||
// create the payload with the new speeds
|
|
||||||
val arrayPayloadIndex = implementation.instructions.size - 1
|
|
||||||
implementation.replaceInstruction(
|
|
||||||
arrayPayloadIndex,
|
|
||||||
BuilderArrayPayload(
|
|
||||||
4,
|
|
||||||
videoSpeedsArray
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return PatchResultSuccess()
|
return PatchResultSuccess()
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object : OptionsContainer() {
|
|
||||||
private fun String?.validate(max: Int? = null) = this?.toFloatOrNull() != null &&
|
|
||||||
toFloat().let { float ->
|
|
||||||
float > 0 && max?.let { max -> float <= max } ?: true
|
|
||||||
}
|
|
||||||
|
|
||||||
val videoSpeedsGranularity by option(
|
|
||||||
PatchOption.StringOption(
|
|
||||||
"granularity",
|
|
||||||
"16",
|
|
||||||
"Video speed granularity",
|
|
||||||
"The granularity of the video speeds. The higher the value, the more speeds will be available.",
|
|
||||||
true
|
|
||||||
) {
|
|
||||||
it.validate()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
val minVideoSpeed by option(
|
|
||||||
PatchOption.StringOption(
|
|
||||||
"min",
|
|
||||||
"0.25",
|
|
||||||
"Minimum video speed",
|
|
||||||
"The minimum video speed.",
|
|
||||||
true
|
|
||||||
) {
|
|
||||||
it.validate()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
val maxVideoSpeed by option(
|
|
||||||
PatchOption.StringOption(
|
|
||||||
"max",
|
|
||||||
"5.0",
|
|
||||||
"Maximum video speed",
|
|
||||||
"The maximum video speed. Must be greater than the minimum video speed and smaller than 5.",
|
|
||||||
true
|
|
||||||
) {
|
|
||||||
it.validate(5)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -21,13 +21,13 @@ 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
|
||||||
import app.revanced.patches.youtube.misc.video.information.patch.VideoInformationPatch.Companion.reference
|
import app.revanced.patches.youtube.misc.video.information.patch.VideoInformationPatch.Companion.reference
|
||||||
|
import app.revanced.patches.youtube.misc.video.speed.custom.patch.CustomVideoSpeedPatch
|
||||||
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.InitializePlaybackSpeedValuesFingerprint
|
||||||
|
|
||||||
@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, VideoInformationPatch::class])
|
@DependsOn([IntegrationsPatch::class, SettingsPatch::class, VideoInformationPatch::class, CustomVideoSpeedPatch::class])
|
||||||
@RememberPlaybackSpeedCompatibility
|
@RememberPlaybackSpeedCompatibility
|
||||||
@Version("0.0.1")
|
@Version("0.0.1")
|
||||||
class RememberPlaybackSpeedPatch : BytecodePatch(
|
class RememberPlaybackSpeedPatch : BytecodePatch(
|
||||||
|
Loading…
Reference in New Issue
Block a user