diff --git a/src/main/kotlin/app/revanced/patches/youtube/general/components/LayoutComponentsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/general/components/LayoutComponentsPatch.kt
index fb3eff3b3..94654e28e 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/general/components/LayoutComponentsPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/general/components/LayoutComponentsPatch.kt
@@ -106,7 +106,7 @@ object LayoutComponentsPatch : BaseBytecodePatch(
1,
"const/4 p1, 0x0"
)
-
+
// endregion
// region patch for hide account menu
diff --git a/src/main/kotlin/app/revanced/patches/youtube/player/seekbar/SeekbarComponentsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/player/seekbar/SeekbarComponentsPatch.kt
index fc7c0ce79..428166042 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/player/seekbar/SeekbarComponentsPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/player/seekbar/SeekbarComponentsPatch.kt
@@ -20,6 +20,7 @@ import app.revanced.patches.youtube.utils.fingerprints.PlayerSeekbarColorFingerp
import app.revanced.patches.youtube.utils.fingerprints.SeekbarFingerprint
import app.revanced.patches.youtube.utils.fingerprints.SeekbarOnDrawFingerprint
import app.revanced.patches.youtube.utils.fingerprints.TotalTimeFingerprint
+import app.revanced.patches.youtube.utils.flyoutmenu.FlyoutMenuHookPatch
import app.revanced.patches.youtube.utils.integrations.Constants.PLAYER_CLASS_DESCRIPTOR
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.InlineTimeBarColorizedBarPlayedColorDark
@@ -50,6 +51,7 @@ object SeekbarComponentsPatch : BaseBytecodePatch(
description = "Adds options to hide or change components related to player.",
dependencies = setOf(
DrawableColorPatch::class,
+ FlyoutMenuHookPatch::class,
SettingsPatch::class,
SharedResourceIdPatch::class,
VideoInformationPatch::class
diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/flyoutmenu/FlyoutMenuHookPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/flyoutmenu/FlyoutMenuHookPatch.kt
new file mode 100644
index 000000000..de312377a
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/youtube/utils/flyoutmenu/FlyoutMenuHookPatch.kt
@@ -0,0 +1,81 @@
+package app.revanced.patches.youtube.utils.flyoutmenu
+
+import app.revanced.patcher.data.BytecodeContext
+import app.revanced.patcher.patch.BytecodePatch
+import app.revanced.patcher.patch.PatchException
+import app.revanced.patcher.patch.annotation.Patch
+import app.revanced.patches.youtube.utils.flyoutmenu.fingerprints.PlaybackRateBottomSheetClassFingerprint
+import app.revanced.patches.youtube.utils.flyoutmenu.fingerprints.VideoQualityBottomSheetClassFingerprint
+import app.revanced.patches.youtube.utils.integrations.Constants.INTEGRATIONS_PATH
+import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch
+import app.revanced.util.addFieldAndInstructions
+import app.revanced.util.resultOrThrow
+
+@Patch(
+ description = "Hooks YouTube to open the playback speed or video quality flyout menu in the integration.",
+ dependencies = [SharedResourceIdPatch::class]
+)
+object FlyoutMenuHookPatch : BytecodePatch(
+ setOf(
+ PlaybackRateBottomSheetClassFingerprint,
+ VideoQualityBottomSheetClassFingerprint
+ )
+) {
+ private const val INTEGRATIONS_VIDEO_UTILS_CLASS_DESCRIPTOR =
+ "$INTEGRATIONS_PATH/utils/VideoUtils;"
+
+ override fun execute(context: BytecodeContext) {
+
+ val videoUtilsMutableClass = context.findClass(
+ INTEGRATIONS_VIDEO_UTILS_CLASS_DESCRIPTOR
+ )!!.mutableClass
+
+ PlaybackRateBottomSheetClassFingerprint.resultOrThrow().let {
+ it.mutableMethod.apply {
+ val playbackRateBottomSheetBuilderMethodName =
+ it.mutableClass.methods.find { method -> method.parameters.isEmpty() && method.returnType == "V" }
+ ?.name
+ ?: throw PatchException("Could not find PlaybackRateBottomSheetBuilderMethod")
+
+ val smaliInstructions =
+ """
+ if-eqz v0, :ignore
+ invoke-virtual {v0}, $definingClass->$playbackRateBottomSheetBuilderMethodName()V
+ :ignore
+ return-void
+ """
+
+ videoUtilsMutableClass.addFieldAndInstructions(
+ context,
+ "showPlaybackSpeedFlyoutMenu",
+ "playbackRateBottomSheetClass",
+ definingClass,
+ smaliInstructions,
+ true
+ )
+ }
+ }
+
+ VideoQualityBottomSheetClassFingerprint.resultOrThrow().let {
+ it.mutableMethod.apply {
+ val smaliInstructions =
+ """
+ if-eqz v0, :ignore
+ const/4 v1, 0x1
+ invoke-virtual {v0, v1}, $definingClass->$name(Z)V
+ :ignore
+ return-void
+ """
+
+ videoUtilsMutableClass.addFieldAndInstructions(
+ context,
+ "showVideoQualityFlyoutMenu",
+ "videoQualityBottomSheetClass",
+ definingClass,
+ smaliInstructions,
+ true
+ )
+ }
+ }
+ }
+}
diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/flyoutpanel/fingerprints/PlaybackRateBottomSheetClassFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/flyoutmenu/fingerprints/PlaybackRateBottomSheetClassFingerprint.kt
similarity index 85%
rename from src/main/kotlin/app/revanced/patches/youtube/utils/flyoutpanel/fingerprints/PlaybackRateBottomSheetClassFingerprint.kt
rename to src/main/kotlin/app/revanced/patches/youtube/utils/flyoutmenu/fingerprints/PlaybackRateBottomSheetClassFingerprint.kt
index 18a6a5a5b..0ee51db6c 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/utils/flyoutpanel/fingerprints/PlaybackRateBottomSheetClassFingerprint.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/utils/flyoutmenu/fingerprints/PlaybackRateBottomSheetClassFingerprint.kt
@@ -1,4 +1,4 @@
-package app.revanced.patches.youtube.utils.flyoutpanel.fingerprints
+package app.revanced.patches.youtube.utils.flyoutmenu.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/flyoutmenu/fingerprints/VideoQualityBottomSheetClassFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/flyoutmenu/fingerprints/VideoQualityBottomSheetClassFingerprint.kt
new file mode 100644
index 000000000..411644568
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/youtube/utils/flyoutmenu/fingerprints/VideoQualityBottomSheetClassFingerprint.kt
@@ -0,0 +1,13 @@
+package app.revanced.patches.youtube.utils.flyoutmenu.fingerprints
+
+import app.revanced.patcher.extensions.or
+import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.VideoQualityUnavailableAnnouncement
+import app.revanced.util.fingerprint.LiteralValueFingerprint
+import com.android.tools.smali.dexlib2.AccessFlags
+
+internal object VideoQualityBottomSheetClassFingerprint : LiteralValueFingerprint(
+ accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
+ returnType = "V",
+ parameters = listOf("Z"),
+ literalSupplier = { VideoQualityUnavailableAnnouncement }
+)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/flyoutpanel/PlaybackSpeedFlyoutPanelHookPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/flyoutpanel/PlaybackSpeedFlyoutPanelHookPatch.kt
deleted file mode 100644
index c073e82fd..000000000
--- a/src/main/kotlin/app/revanced/patches/youtube/utils/flyoutpanel/PlaybackSpeedFlyoutPanelHookPatch.kt
+++ /dev/null
@@ -1,73 +0,0 @@
-package app.revanced.patches.youtube.utils.flyoutpanel
-
-import app.revanced.patcher.data.BytecodeContext
-import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
-import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
-import app.revanced.patcher.extensions.or
-import app.revanced.patcher.patch.BytecodePatch
-import app.revanced.patcher.patch.PatchException
-import app.revanced.patcher.patch.annotation.Patch
-import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable
-import app.revanced.patches.youtube.utils.flyoutpanel.fingerprints.PlaybackRateBottomSheetClassFingerprint
-import app.revanced.patches.youtube.utils.integrations.Constants.INTEGRATIONS_PATH
-import app.revanced.util.resultOrThrow
-import com.android.tools.smali.dexlib2.AccessFlags
-import com.android.tools.smali.dexlib2.immutable.ImmutableField
-
-@Patch(description = "Hooks YouTube to open the playback speed flyout panel in the integration.")
-object PlaybackSpeedFlyoutPanelHookPatch : BytecodePatch(
- setOf(PlaybackRateBottomSheetClassFingerprint)
-) {
- private const val INTEGRATIONS_VIDEO_UTILS_CLASS_DESCRIPTOR =
- "$INTEGRATIONS_PATH/utils/VideoUtils;"
-
- override fun execute(context: BytecodeContext) {
-
- PlaybackRateBottomSheetClassFingerprint.resultOrThrow().let {
- it.mutableMethod.apply {
- val playbackRateBottomSheetClass = definingClass
- val playbackRateBottomSheetBuilderMethodName =
- it.mutableClass.methods.find { method -> method.parameters.isEmpty() && method.returnType == "V" }
- ?.name
- ?: throw PatchException("Could not find PlaybackRateBottomSheetBuilderMethod")
-
- // set playback rate bottom sheet class
- addInstruction(
- 0,
- "sput-object p0, $INTEGRATIONS_VIDEO_UTILS_CLASS_DESCRIPTOR->playbackRateBottomSheetClass:$playbackRateBottomSheetClass"
- )
-
- val videoUtilsMutableClass = context.findClass(
- INTEGRATIONS_VIDEO_UTILS_CLASS_DESCRIPTOR
- )!!.mutableClass
- videoUtilsMutableClass.methods.single { method ->
- method.name == "showPlaybackSpeedFlyoutMenu"
- }.apply {
- // add playback rate bottom sheet class
- videoUtilsMutableClass.staticFields.add(
- ImmutableField(
- definingClass,
- "playbackRateBottomSheetClass",
- playbackRateBottomSheetClass,
- AccessFlags.PUBLIC or AccessFlags.STATIC,
- null,
- annotations,
- null
- ).toMutable()
- )
-
- // call playback rate bottom sheet method
- addInstructionsWithLabels(
- 0, """
- sget-object v0, $INTEGRATIONS_VIDEO_UTILS_CLASS_DESCRIPTOR->playbackRateBottomSheetClass:$playbackRateBottomSheetClass
- if-eqz v0, :ignore
- invoke-virtual {v0}, $playbackRateBottomSheetClass->$playbackRateBottomSheetBuilderMethodName()V
- :ignore
- return-void
- """
- )
- }
- }
- }
- }
-}
diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/resourceid/SharedResourceIdPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/resourceid/SharedResourceIdPatch.kt
index 1682896b3..abe3f0701 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/utils/resourceid/SharedResourceIdPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/utils/resourceid/SharedResourceIdPatch.kt
@@ -93,6 +93,7 @@ object SharedResourceIdPatch : ResourcePatch() {
var TotalTime = -1L
var TouchArea = -1L
var VideoQualityBottomSheet = -1L
+ var VideoQualityUnavailableAnnouncement = -1L
var VoiceSearch = -1L
var YouTubeControlsOverlaySubtitleButton = -1L
var YtOutlinePiPWhite = -1L
@@ -181,6 +182,7 @@ object SharedResourceIdPatch : ResourcePatch() {
TotalTime = getId(STRING, "total_time")
TouchArea = getId(ID, "touch_area")
VideoQualityBottomSheet = getId(LAYOUT, "video_quality_bottom_sheet_list_fragment_title")
+ VideoQualityUnavailableAnnouncement = getId(STRING, "video_quality_unavailable_announcement")
VoiceSearch = getId(ID, "voice_search")
YouTubeControlsOverlaySubtitleButton = getId(LAYOUT, "youtube_controls_overlay_subtitle_button")
YtOutlinePiPWhite = getId(DRAWABLE, "yt_outline_picture_in_picture_white_24")
diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/playback/VideoPlaybackPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/playback/VideoPlaybackPatch.kt
index 24667ccdf..850a744c6 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/video/playback/VideoPlaybackPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/video/playback/VideoPlaybackPatch.kt
@@ -12,7 +12,7 @@ import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PAC
import app.revanced.patches.youtube.utils.fingerprints.QualityMenuViewInflateFingerprint
import app.revanced.patches.youtube.utils.fingerprints.VideoEndFingerprint
import app.revanced.patches.youtube.utils.fix.shortsplayback.ShortsPlaybackPatch
-import app.revanced.patches.youtube.utils.flyoutpanel.PlaybackSpeedFlyoutPanelHookPatch
+import app.revanced.patches.youtube.utils.flyoutmenu.FlyoutMenuHookPatch
import app.revanced.patches.youtube.utils.integrations.Constants.COMPONENTS_PATH
import app.revanced.patches.youtube.utils.integrations.Constants.PATCH_STATUS_CLASS_DESCRIPTOR
import app.revanced.patches.youtube.utils.integrations.Constants.VIDEO_PATH
@@ -52,8 +52,8 @@ object VideoPlaybackPatch : BaseBytecodePatch(
dependencies = setOf(
BottomSheetRecyclerViewPatch::class,
CustomPlaybackSpeedPatch::class,
+ FlyoutMenuHookPatch::class,
LithoFilterPatch::class,
- PlaybackSpeedFlyoutPanelHookPatch::class,
PlayerTypeHookPatch::class,
SettingsPatch::class,
ShortsPlaybackPatch::class,
diff --git a/src/main/resources/youtube/settings/host/values/strings.xml b/src/main/resources/youtube/settings/host/values/strings.xml
index a7f709f62..e94ec8421 100644
--- a/src/main/resources/youtube/settings/host/values/strings.xml
+++ b/src/main/resources/youtube/settings/host/values/strings.xml
@@ -816,6 +816,9 @@ Please download %2$s from the website."
Append information type
Append video quality.
Append playback speed.
+ Replace time stamp action
+ Tap to open playback speed or video quality flyout menu.
+ Tap to show the remaining time.
Enable custom seekbar color
Custom seekbar color is enabled.
Custom seekbar color is disabled.
diff --git a/src/main/resources/youtube/settings/xml/revanced_prefs.xml b/src/main/resources/youtube/settings/xml/revanced_prefs.xml
index 836d09f82..77936b35f 100644
--- a/src/main/resources/youtube/settings/xml/revanced_prefs.xml
+++ b/src/main/resources/youtube/settings/xml/revanced_prefs.xml
@@ -346,7 +346,8 @@