From 02fb26e9458fb8635d497e6e78f964055244d738 Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Sat, 18 Jan 2025 11:37:34 +0200 Subject: [PATCH] feat(YouTube - Playback speed): Add option to change 2x tap and hold speed (#4307) --- .../speed/CustomPlaybackSpeedPatch.java | 35 ++++++++++++++---- .../extension/youtube/settings/Settings.java | 1 + patches/api/patches.api | 5 +-- .../misc/settings/preference/InputType.kt | 1 + .../speed/custom/CustomPlaybackSpeedPatch.kt | 37 ++++++++++++++++++- .../resources/addresources/values/strings.xml | 2 + 6 files changed, 68 insertions(+), 13 deletions(-) diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/playback/speed/CustomPlaybackSpeedPatch.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/playback/speed/CustomPlaybackSpeedPatch.java index 22d8df37e..ae2a09f92 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/playback/speed/CustomPlaybackSpeedPatch.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/playback/speed/CustomPlaybackSpeedPatch.java @@ -32,6 +32,11 @@ public class CustomPlaybackSpeedPatch { */ public static final float PLAYBACK_SPEED_MAXIMUM = 8; + /** + * Tap and hold speed. + */ + private static final float TAP_AND_HOLD_SPEED; + /** * Custom playback speeds. */ @@ -48,12 +53,27 @@ public class CustomPlaybackSpeedPatch { private static String[] preferenceListEntries, preferenceListEntryValues; static { + final float holdSpeed = Settings.SPEED_TAP_AND_HOLD.get(); + if (holdSpeed > 0 && holdSpeed <= PLAYBACK_SPEED_MAXIMUM) { + TAP_AND_HOLD_SPEED = holdSpeed; + } else { + showInvalidCustomSpeedToast(); + Settings.SPEED_TAP_AND_HOLD.resetToDefault(); + TAP_AND_HOLD_SPEED = Settings.SPEED_TAP_AND_HOLD.get(); + } + loadCustomSpeeds(); } - private static void resetCustomSpeeds(@NonNull String toastMessage) { - Utils.showToastLong(toastMessage); - Settings.CUSTOM_PLAYBACK_SPEEDS.resetToDefault(); + /** + * Injection point. + */ + public static float tapAndHoldSpeed() { + return TAP_AND_HOLD_SPEED; + } + + private static void showInvalidCustomSpeedToast() { + Utils.showToastLong(str("revanced_custom_playback_speeds_invalid", PLAYBACK_SPEED_MAXIMUM)); } private static void loadCustomSpeeds() { @@ -74,17 +94,18 @@ public class CustomPlaybackSpeedPatch { } if (speedFloat >= PLAYBACK_SPEED_MAXIMUM) { - resetCustomSpeeds(str("revanced_custom_playback_speeds_invalid", PLAYBACK_SPEED_MAXIMUM)); + showInvalidCustomSpeedToast(); + Settings.CUSTOM_PLAYBACK_SPEEDS.resetToDefault(); loadCustomSpeeds(); return; } - customPlaybackSpeeds[i] = speedFloat; - i++; + customPlaybackSpeeds[i++] = speedFloat; } } catch (Exception ex) { Logger.printInfo(() -> "parse error", ex); - resetCustomSpeeds(str("revanced_custom_playback_speeds_parse_exception")); + Utils.showToastLong(str("revanced_custom_playback_speeds_parse_exception")); + Settings.CUSTOM_PLAYBACK_SPEEDS.resetToDefault(); loadCustomSpeeds(); } } diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/Settings.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/Settings.java index 93515648a..c14b8b7d3 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/Settings.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/Settings.java @@ -50,6 +50,7 @@ public class Settings extends BaseSettings { public static final IntegerSetting VIDEO_QUALITY_DEFAULT_WIFI = new IntegerSetting("revanced_video_quality_default_wifi", -2); public static final IntegerSetting VIDEO_QUALITY_DEFAULT_MOBILE = new IntegerSetting("revanced_video_quality_default_mobile", -2); // Speed + public static final FloatSetting SPEED_TAP_AND_HOLD = new FloatSetting("revanced_speed_tap_and_hold", 2.0f, true); public static final BooleanSetting REMEMBER_PLAYBACK_SPEED_LAST_SELECTED = new BooleanSetting("revanced_remember_playback_speed_last_selected", FALSE); public static final BooleanSetting CUSTOM_SPEED_MENU = new BooleanSetting("revanced_custom_speed_menu", TRUE); public static final FloatSetting PLAYBACK_SPEED_DEFAULT = new FloatSetting("revanced_playback_speed_default", -2.0f); diff --git a/patches/api/patches.api b/patches/api/patches.api index 92ca7f946..d9e095cca 100644 --- a/patches/api/patches.api +++ b/patches/api/patches.api @@ -662,6 +662,7 @@ public class app/revanced/patches/shared/misc/settings/preference/BasePreference public final class app/revanced/patches/shared/misc/settings/preference/InputType : java/lang/Enum { public static final field NUMBER Lapp/revanced/patches/shared/misc/settings/preference/InputType; + public static final field NUMBER_DECIMAL Lapp/revanced/patches/shared/misc/settings/preference/InputType; public static final field TEXT Lapp/revanced/patches/shared/misc/settings/preference/InputType; public static final field TEXT_CAP_CHARACTERS Lapp/revanced/patches/shared/misc/settings/preference/InputType; public static final field TEXT_MULTI_LINE Lapp/revanced/patches/shared/misc/settings/preference/InputType; @@ -1447,10 +1448,6 @@ public final class app/revanced/patches/youtube/video/speed/button/PlaybackSpeed public static final fun getPlaybackSpeedButtonPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } -public final class app/revanced/patches/youtube/video/speed/custom/CustomPlaybackSpeedPatchKt { - public static final fun getSpeedUnavailableId ()J -} - public final class app/revanced/patches/youtube/video/videoid/VideoIdPatchKt { public static final fun getVideoIdPatch ()Lapp/revanced/patcher/patch/BytecodePatch; public static final fun hookBackgroundPlayVideoId (Ljava/lang/String;)V diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/InputType.kt b/patches/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/InputType.kt index e5142d92e..88857cd7f 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/InputType.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/InputType.kt @@ -5,4 +5,5 @@ enum class InputType(val type: String) { TEXT_CAP_CHARACTERS("textCapCharacters"), TEXT_MULTI_LINE("textMultiLine"), NUMBER("number"), + NUMBER_DECIMAL("numberDecimal"), } \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/CustomPlaybackSpeedPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/CustomPlaybackSpeedPatch.kt index bd6668993..695642c5a 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/CustomPlaybackSpeedPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/CustomPlaybackSpeedPatch.kt @@ -17,22 +17,26 @@ import app.revanced.patches.shared.misc.mapping.resourceMappings import app.revanced.patches.shared.misc.settings.preference.InputType import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.shared.misc.settings.preference.TextPreference +import app.revanced.patches.youtube.interaction.seekbar.disableFastForwardNoticeFingerprint import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch import app.revanced.patches.youtube.misc.litho.filter.addLithoFilter import app.revanced.patches.youtube.misc.litho.filter.lithoFilterPatch +import app.revanced.patches.youtube.misc.playservice.is_19_25_or_greater +import app.revanced.patches.youtube.misc.playservice.versionCheckPatch import app.revanced.patches.youtube.misc.recyclerviewtree.hook.addRecyclerViewTreeHook import app.revanced.patches.youtube.misc.recyclerviewtree.hook.recyclerViewTreeHookPatch import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.settingsPatch import app.revanced.util.* import com.android.tools.smali.dexlib2.AccessFlags +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.reference.FieldReference import com.android.tools.smali.dexlib2.iface.reference.MethodReference import com.android.tools.smali.dexlib2.immutable.ImmutableField -var speedUnavailableId = -1L - internal set +internal var speedUnavailableId = -1L + private set private val customPlaybackSpeedResourcePatch = resourcePatch { dependsOn(resourceMappingPatch) @@ -61,6 +65,7 @@ internal val customPlaybackSpeedPatch = bytecodePatch( recyclerViewTreeHookPatch, customPlaybackSpeedResourcePatch, addResourcesPatch, + versionCheckPatch ) execute { @@ -71,6 +76,12 @@ internal val customPlaybackSpeedPatch = bytecodePatch( TextPreference("revanced_custom_playback_speeds", inputType = InputType.TEXT_MULTI_LINE), ) + if (is_19_25_or_greater) { + PreferenceScreen.VIDEO.addPreferences( + TextPreference("revanced_speed_tap_and_hold", inputType = InputType.NUMBER_DECIMAL), + ) + } + // Replace the speeds float array with custom speeds. speedArrayGeneratorFingerprint.method.apply { val sizeCallIndex = indexOfFirstInstructionOrThrow { getReference()?.name == "size" } @@ -166,5 +177,27 @@ internal val customPlaybackSpeedPatch = bytecodePatch( addLithoFilter(FILTER_CLASS_DESCRIPTOR) // endregion + + + // region Custom tap and hold 2x speed. + + if (is_19_25_or_greater) { + disableFastForwardNoticeFingerprint.method.apply { + val index = indexOfFirstInstructionOrThrow { + (this as? NarrowLiteralInstruction)?.narrowLiteral == 2.0f.toRawBits() + } + val register = getInstruction(index).registerA + + addInstructions( + index + 1, + """ + invoke-static {}, $EXTENSION_CLASS_DESCRIPTOR->tapAndHoldSpeed()F + move-result v$register + """ + ) + } + } + + // endregion } } diff --git a/patches/src/main/resources/addresources/values/strings.xml b/patches/src/main/resources/addresources/values/strings.xml index e9e78eac4..9f9b28790 100644 --- a/patches/src/main/resources/addresources/values/strings.xml +++ b/patches/src/main/resources/addresources/values/strings.xml @@ -1351,6 +1351,8 @@ Enabling this can unlock higher video qualities" Custom speeds must be less than %s Invalid custom playback speeds Auto + Custom tap and hold speed + Playback speed between 0-8 Remember playback speed changes