diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/DisableChapterSkipDoubleTapPatch.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/DisableChapterSkipDoubleTapPatch.java new file mode 100644 index 000000000..13a2c2f6c --- /dev/null +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/DisableChapterSkipDoubleTapPatch.java @@ -0,0 +1,16 @@ +package app.revanced.extension.youtube.patches; + +import app.revanced.extension.youtube.settings.Settings; + +@SuppressWarnings("unused") +public final class DisableChapterSkipDoubleTapPatch { + + /** + * Injection point. + * + * @return If "should skip to chapter start" flag is set. + */ + public static boolean disableDoubleTapChapters(boolean original) { + return original && !Settings.DISABLE_CHAPTER_SKIP_DOUBLE_TAP.get(); + } +} \ No newline at end of file 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 56017ad32..564dd5f31 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 @@ -146,6 +146,7 @@ public class Settings extends BaseSettings { public static final BooleanSetting COPY_VIDEO_URL = new BooleanSetting("revanced_copy_video_url", FALSE); public static final BooleanSetting COPY_VIDEO_URL_TIMESTAMP = new BooleanSetting("revanced_copy_video_url_timestamp", TRUE); public static final BooleanSetting DISABLE_AUTO_CAPTIONS = new BooleanSetting("revanced_disable_auto_captions", FALSE, true); + public static final BooleanSetting DISABLE_CHAPTER_SKIP_DOUBLE_TAP = new BooleanSetting("revanced_disable_chapter_skip_double_tap", FALSE); public static final BooleanSetting DISABLE_FULLSCREEN_AMBIENT_MODE = new BooleanSetting("revanced_disable_fullscreen_ambient_mode", TRUE, true); public static final BooleanSetting DISABLE_ROLLING_NUMBER_ANIMATIONS = new BooleanSetting("revanced_disable_rolling_number_animations", FALSE); public static final EnumSetting EXIT_FULLSCREEN = new EnumSetting<>("revanced_exit_fullscreen", FullscreenMode.DISABLED); diff --git a/patches/api/patches.api b/patches/api/patches.api index b1f57887c..c9f49557f 100644 --- a/patches/api/patches.api +++ b/patches/api/patches.api @@ -1236,6 +1236,10 @@ public final class app/revanced/patches/youtube/interaction/dialog/RemoveViewerD public static final fun getRemoveViewerDiscretionDialogPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } +public final class app/revanced/patches/youtube/interaction/doubletap/DisableChapterSkipDoubleTapPatchKt { + public static final fun getDisableChapterSkipDoubleTapPatch ()Lapp/revanced/patcher/patch/BytecodePatch; +} + public final class app/revanced/patches/youtube/interaction/downloads/DownloadsPatchKt { public static final fun getDownloadsPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/doubletap/DisableChapterSkipDoubleTapPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/doubletap/DisableChapterSkipDoubleTapPatch.kt new file mode 100644 index 000000000..95d30ed5d --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/doubletap/DisableChapterSkipDoubleTapPatch.kt @@ -0,0 +1,63 @@ +package app.revanced.patches.youtube.interaction.doubletap + +import app.revanced.patcher.extensions.InstructionExtensions.addInstructions +import app.revanced.patcher.patch.bytecodePatch +import app.revanced.patches.all.misc.resources.addResources +import app.revanced.patches.all.misc.resources.addResourcesPatch +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference +import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch +import app.revanced.patches.youtube.misc.settings.PreferenceScreen +import app.revanced.patches.youtube.misc.settings.settingsPatch + +private const val EXTENSION_CLASS_DESCRIPTOR = + "Lapp/revanced/extension/youtube/patches/DisableChapterSkipDoubleTapPatch;" + +@Suppress("unused") +val disableChapterSkipDoubleTapPatch = bytecodePatch( + name = "Disable double tap actions", + description = "Adds an option to disable player double tap gestures.", +) { + dependsOn( + sharedExtensionPatch, + settingsPatch, + addResourcesPatch, + ) + + compatibleWith( + "com.google.android.youtube"( + "19.34.42", + "19.43.41", + "19.47.53", + "20.07.39", + "20.12.46", + "20.13.41", + ) + ) + + execute { + addResources("youtube", "interaction.doubletap.disableChapterSkipDoubleTapPatch") + + PreferenceScreen.PLAYER.addPreferences( + SwitchPreference("revanced_disable_chapter_skip_double_tap"), + ) + + // Force isChapterSeek flag to false. + doubleTapInfoGetSeekSourceFingerprint.method.addInstructions( + 0, + """ + invoke-static { p1 }, $EXTENSION_CLASS_DESCRIPTOR->disableDoubleTapChapters(Z)Z + move-result p1 + """ + ) + + doubleTapInfoCtorFingerprint.match( + doubleTapInfoGetSeekSourceFingerprint.classDef + ).method.addInstructions( + 0, + """ + invoke-static { p3 }, $EXTENSION_CLASS_DESCRIPTOR->disableDoubleTapChapters(Z)Z + move-result p3 + """ + ) + } +} \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/doubletap/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/doubletap/Fingerprints.kt new file mode 100644 index 000000000..0e16e0b5c --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/doubletap/Fingerprints.kt @@ -0,0 +1,31 @@ +package app.revanced.patches.youtube.interaction.doubletap + +import app.revanced.patcher.fingerprint +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.Opcode + +internal val doubleTapInfoGetSeekSourceFingerprint = fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) + parameters("Z") + returns("L") // Enum SeekSource, but name obfuscated. + opcodes( + Opcode.IF_EQZ, + Opcode.SGET_OBJECT, + Opcode.RETURN_OBJECT, + Opcode.SGET_OBJECT, + Opcode.RETURN_OBJECT, + ) + custom { _, classDef -> + classDef.fields.count() == 4 + } +} + +internal val doubleTapInfoCtorFingerprint = fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) + parameters( + "Landroid/view/MotionEvent;", + "I", + "Z", + "Lj\$/time/Duration;" + ) +} diff --git a/patches/src/main/resources/addresources/values/strings.xml b/patches/src/main/resources/addresources/values/strings.xml index c209df5e1..f66de4941 100644 --- a/patches/src/main/resources/addresources/values/strings.xml +++ b/patches/src/main/resources/addresources/values/strings.xml @@ -516,6 +516,11 @@ This feature is only available for older devices" Dialog will be shown This does not bypass the age restriction. It just accepts it automatically. + + Disable double tap chapter skip + Double tap can never trigger a skip to the next/previous chapter + Double tap can occasionally trigger a skip to the next/previous chapter + External downloads Settings for using an external downloader