diff --git a/api/revanced-patches.api b/api/revanced-patches.api
index 75d89226..9f253870 100644
--- a/api/revanced-patches.api
+++ b/api/revanced-patches.api
@@ -1528,6 +1528,12 @@ public final class app/revanced/patches/youtube/layout/hide/time/HideTimestampPa
 	public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
 }
 
+public final class app/revanced/patches/youtube/layout/miniplayer/MiniplayerPatch : app/revanced/patcher/patch/BytecodePatch {
+	public static final field INSTANCE Lapp/revanced/patches/youtube/layout/miniplayer/MiniplayerPatch;
+	public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
+	public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
+}
+
 public final class app/revanced/patches/youtube/layout/panels/popup/PlayerPopupPanelsPatch : app/revanced/patcher/patch/BytecodePatch {
 	public static final field INSTANCE Lapp/revanced/patches/youtube/layout/panels/popup/PlayerPopupPanelsPatch;
 	public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
@@ -1894,6 +1900,7 @@ public final class app/revanced/patches/yuka/misc/unlockpremium/UnlockPremiumPat
 public final class app/revanced/util/BytecodeUtilsKt {
 	public static final fun containsWideLiteralInstructionValue (Lcom/android/tools/smali/dexlib2/iface/Method;J)Z
 	public static final fun findMutableMethodOf (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableClass;Lcom/android/tools/smali/dexlib2/iface/Method;)Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;
+	public static final fun findOpcodeIndicesReversed (Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/Opcode;)Ljava/util/List;
 	public static final fun getException (Lapp/revanced/patcher/fingerprint/MethodFingerprint;)Lapp/revanced/patcher/patch/PatchException;
 	public static final fun indexOfFirstInstruction (Lcom/android/tools/smali/dexlib2/iface/Method;ILkotlin/jvm/functions/Function1;)I
 	public static final fun indexOfFirstInstruction (Lcom/android/tools/smali/dexlib2/iface/Method;Lkotlin/jvm/functions/Function1;)I
@@ -1901,6 +1908,7 @@ public final class app/revanced/util/BytecodeUtilsKt {
 	public static final fun indexOfFirstInstructionOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;ILkotlin/jvm/functions/Function1;)I
 	public static synthetic fun indexOfFirstInstructionOrThrow$default (Lcom/android/tools/smali/dexlib2/iface/Method;ILkotlin/jvm/functions/Function1;ILjava/lang/Object;)I
 	public static final fun indexOfFirstWideLiteralInstructionValue (Lcom/android/tools/smali/dexlib2/iface/Method;J)I
+	public static final fun indexOfFirstWideLiteralInstructionValueOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;J)I
 	public static final fun indexOfIdResource (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/String;)I
 	public static final fun indexOfIdResourceOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/String;)I
 	public static final fun injectHideViewCall (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;IILjava/lang/String;Ljava/lang/String;)V
diff --git a/src/main/kotlin/app/revanced/patches/shared/misc/mapping/ResourceMappingPatch.kt b/src/main/kotlin/app/revanced/patches/shared/misc/mapping/ResourceMappingPatch.kt
index 388c4ef6..2c165e1f 100644
--- a/src/main/kotlin/app/revanced/patches/shared/misc/mapping/ResourceMappingPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/shared/misc/mapping/ResourceMappingPatch.kt
@@ -1,6 +1,7 @@
 package app.revanced.patches.shared.misc.mapping
 
 import app.revanced.patcher.data.ResourceContext
+import app.revanced.patcher.patch.PatchException
 import app.revanced.patcher.patch.ResourcePatch
 import org.w3c.dom.Element
 import java.util.*
@@ -51,9 +52,10 @@ object ResourceMappingPatch : ResourcePatch() {
         threadPoolExecutor.also { it.shutdown() }.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS)
     }
 
-    operator fun get(type: String, name: String) = resourceMappings.first {
-        it.type == type && it.name == name
-    }.id
+    operator fun get(type: String, name: String) =
+        resourceMappings.firstOrNull {
+            it.type == type && it.name == name
+        }?.id ?: throw PatchException("Could not find resource type: $type name: $name")
 
     data class ResourceElement(val type: String, val name: String, val id: Long)
 }
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/MiniplayerPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/MiniplayerPatch.kt
new file mode 100644
index 00000000..4d7c52a4
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/MiniplayerPatch.kt
@@ -0,0 +1,370 @@
+package app.revanced.patches.youtube.layout.miniplayer
+
+import app.revanced.patcher.data.BytecodeContext
+import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
+import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
+import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
+import app.revanced.patcher.extensions.InstructionExtensions.removeInstruction
+import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
+import app.revanced.patcher.patch.BytecodePatch
+import app.revanced.patcher.patch.annotation.CompatiblePackage
+import app.revanced.patcher.patch.annotation.Patch
+import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
+import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
+import app.revanced.patches.all.misc.resources.AddResourcesPatch
+import app.revanced.patches.shared.misc.settings.preference.InputType
+import app.revanced.patches.shared.misc.settings.preference.ListPreference
+import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen
+import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen.Sorting
+import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
+import app.revanced.patches.shared.misc.settings.preference.TextPreference
+import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch.modernMiniplayerClose
+import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch.modernMiniplayerExpand
+import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch.modernMiniplayerForwardButton
+import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch.modernMiniplayerRewindButton
+import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch.scrimOverlay
+import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch.ytOutlinePictureInPictureWhite24
+import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch.ytOutlineXWhite24
+import app.revanced.patches.youtube.layout.miniplayer.fingerprints.MiniplayerDimensionsCalculatorParentFingerprint
+import app.revanced.patches.youtube.layout.miniplayer.fingerprints.MiniplayerModernAddViewListenerFingerprint
+import app.revanced.patches.youtube.layout.miniplayer.fingerprints.MiniplayerModernCloseButtonFingerprint
+import app.revanced.patches.youtube.layout.miniplayer.fingerprints.MiniplayerModernConstructorFingerprint
+import app.revanced.patches.youtube.layout.miniplayer.fingerprints.MiniplayerModernExpandButtonFingerprint
+import app.revanced.patches.youtube.layout.miniplayer.fingerprints.MiniplayerModernExpandCloseDrawablesFingerprint
+import app.revanced.patches.youtube.layout.miniplayer.fingerprints.MiniplayerModernForwardButtonFingerprint
+import app.revanced.patches.youtube.layout.miniplayer.fingerprints.MiniplayerModernOverlayViewFingerprint
+import app.revanced.patches.youtube.layout.miniplayer.fingerprints.MiniplayerModernRewindButtonFingerprint
+import app.revanced.patches.youtube.layout.miniplayer.fingerprints.MiniplayerModernViewParentFingerprint
+import app.revanced.patches.youtube.layout.miniplayer.fingerprints.MiniplayerOverrideFingerprint
+import app.revanced.patches.youtube.layout.miniplayer.fingerprints.MiniplayerOverrideNoContextFingerprint
+import app.revanced.patches.youtube.layout.miniplayer.fingerprints.MiniplayerResponseModelSizeCheckFingerprint
+import app.revanced.patches.youtube.layout.miniplayer.fingerprints.YouTubePlayerOverlaysLayoutFingerprint
+import app.revanced.patches.youtube.layout.miniplayer.fingerprints.YouTubePlayerOverlaysLayoutFingerprint.YOUTUBE_PLAYER_OVERLAYS_LAYOUT_CLASS_NAME
+import app.revanced.patches.youtube.layout.tablet.fingerprints.GetFormFactorFingerprint
+import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
+import app.revanced.patches.youtube.misc.settings.SettingsPatch
+import app.revanced.util.findOpcodeIndicesReversed
+import app.revanced.util.getReference
+import app.revanced.util.indexOfFirstInstructionOrThrow
+import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow
+import app.revanced.util.patch.LiteralValueFingerprint
+import app.revanced.util.resultOrThrow
+import com.android.tools.smali.dexlib2.AccessFlags
+import com.android.tools.smali.dexlib2.Opcode
+import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation
+import com.android.tools.smali.dexlib2.iface.Method
+import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
+import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
+import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
+import com.android.tools.smali.dexlib2.iface.reference.FieldReference
+import com.android.tools.smali.dexlib2.iface.reference.TypeReference
+import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
+import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
+
+// YT uses "Miniplayer" without a space between 'mini' and 'player: https://support.google.com/youtube/answer/9162927.
+@Patch(
+    name = "Miniplayer",
+    description = "Adds options to change the in app minimized player, " +
+            "and if patching target 19.16+ adds options to use modern miniplayers.",
+    dependencies = [
+        IntegrationsPatch::class,
+        SettingsPatch::class,
+        AddResourcesPatch::class,
+        MiniplayerResourcePatch::class
+    ],
+    compatiblePackages = [
+        CompatiblePackage(
+            "com.google.android.youtube", [
+                "18.32.39",
+                "18.37.36",
+                "18.38.44",
+                "18.43.45",
+                "18.44.41",
+                "18.45.43",
+                "18.48.39",
+                "18.49.37",
+                "19.01.34",
+                "19.02.39",
+                "19.03.36",
+                "19.04.38",
+                "19.05.36",
+                "19.06.39",
+                "19.07.40",
+                "19.08.36",
+                "19.09.38",
+                "19.10.39",
+                "19.11.43",
+                "19.12.41",
+                "19.13.37",
+                // 19.14 is left out, as it has incomplete miniplayer code and missing some UI resources.
+                // It's simpler to not bother with supporting this single old version.
+                // 19.15 has a different code for handling sub title texts,
+                // and also probably not worth making changes just to support this single old version.
+                "19.16.39" // Earliest supported version with modern miniplayers.
+            ]
+        )
+    ]
+)
+@Suppress("unused")
+object MiniplayerPatch : BytecodePatch(
+    setOf(GetFormFactorFingerprint,
+        MiniplayerDimensionsCalculatorParentFingerprint,
+        MiniplayerResponseModelSizeCheckFingerprint,
+        MiniplayerOverrideFingerprint,
+        MiniplayerModernConstructorFingerprint,
+        MiniplayerModernViewParentFingerprint,
+        YouTubePlayerOverlaysLayoutFingerprint
+    )
+) {
+    private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/youtube/patches/MiniplayerPatch;"
+
+    override fun execute(context: BytecodeContext) {
+        AddResourcesPatch(this::class)
+
+        // Modern mini player is only present and functional in 19.15+.
+        // Resource is not present in older versions. Using it to determine, if patching an old version.
+        val isPatchingOldVersion = ytOutlinePictureInPictureWhite24 < 0
+
+        SettingsPatch.PreferenceScreen.PLAYER.addPreferences(
+            PreferenceScreen(
+                key = "revanced_miniplayer_screen",
+                sorting = Sorting.UNSORTED,
+                preferences =
+                if (isPatchingOldVersion) {
+                    setOf(
+                        ListPreference(
+                            "revanced_miniplayer_type",
+                            summaryKey = null,
+                            entriesKey = "revanced_miniplayer_type_legacy_entries",
+                            entryValuesKey = "revanced_miniplayer_type_legacy_entry_values"
+                        )
+                    )
+                } else {
+                    setOf(
+                        ListPreference(
+                            "revanced_miniplayer_type",
+                            summaryKey = null,
+                            entriesKey = "revanced_miniplayer_type_19_15_entries",
+                            entryValuesKey = "revanced_miniplayer_type_19_15_entry_values"
+                        ),
+                        SwitchPreference("revanced_miniplayer_hide_expand_close"),
+                        SwitchPreference("revanced_miniplayer_hide_subtext"),
+                        SwitchPreference("revanced_miniplayer_hide_rewind_forward"),
+                        TextPreference("revanced_miniplayer_opacity", inputType = InputType.NUMBER)
+                    )
+                }
+            )
+        )
+
+        // region Enable tablet miniplayer.
+
+        MiniplayerOverrideNoContextFingerprint.resolve(
+            context,
+            MiniplayerDimensionsCalculatorParentFingerprint.resultOrThrow().classDef
+        )
+        MiniplayerOverrideNoContextFingerprint.resultOrThrow().mutableMethod.apply {
+            findReturnIndicesReversed().forEach { index -> insertLegacyTabletMiniplayerOverride(index) }
+        }
+
+        // endregion
+
+        // region Legacy tablet Miniplayer hooks.
+
+        MiniplayerOverrideFingerprint.resultOrThrow().let {
+            val appNameStringIndex = it.scanResult.stringsScanResult!!.matches.first().index + 2
+
+            it.mutableMethod.apply {
+                val walkerMethod = context.toMethodWalker(this)
+                    .nextMethod(appNameStringIndex, true)
+                    .getMethod() as MutableMethod
+
+                walkerMethod.apply {
+                    findReturnIndicesReversed().forEach { index -> insertLegacyTabletMiniplayerOverride(index) }
+                }
+            }
+        }
+
+        MiniplayerResponseModelSizeCheckFingerprint.resultOrThrow().let {
+            it.mutableMethod.insertLegacyTabletMiniplayerOverride(it.scanResult.patternScanResult!!.endIndex)
+        }
+
+        if (isPatchingOldVersion) {
+            // Return here, as patch below is only intended for new versions of the app.
+            return
+        }
+
+        // endregion
+
+
+        // region Enable modern miniplayer.
+
+        MiniplayerModernConstructorFingerprint.resultOrThrow().mutableClass.methods.forEach {
+            it.apply {
+                if (AccessFlags.CONSTRUCTOR.isSet(accessFlags)) {
+                    val iPutIndex = indexOfFirstInstructionOrThrow {
+                        this.opcode == Opcode.IPUT && this.getReference<FieldReference>()?.type == "I"
+                    }
+
+                    insertModernMiniplayerTypeOverride(iPutIndex)
+                } else {
+                    findReturnIndicesReversed().forEach { index -> insertModernMiniplayerOverride(index) }
+                }
+            }
+        }
+
+        // endregion
+
+        // region Fix 19.16 using mixed up drawables for tablet modern.
+        // YT fixed this mistake in 19.17.
+        // Fix this, by swapping the drawable resource values with each other.
+
+        MiniplayerModernExpandCloseDrawablesFingerprint.apply {
+            resolve(
+                context,
+                MiniplayerModernViewParentFingerprint.resultOrThrow().classDef
+            )
+        }.resultOrThrow().mutableMethod.apply {
+            listOf(
+                ytOutlinePictureInPictureWhite24 to ytOutlineXWhite24,
+                ytOutlineXWhite24 to ytOutlinePictureInPictureWhite24,
+            ).forEach { (originalResource, replacementResource) ->
+                val imageResourceIndex = indexOfFirstWideLiteralInstructionValueOrThrow(originalResource)
+                val register = getInstruction<OneRegisterInstruction>(imageResourceIndex).registerA
+
+                replaceInstruction(imageResourceIndex, "const v$register, $replacementResource")
+            }
+        }
+
+        // endregion
+
+
+        // region Add hooks to hide tablet modern miniplayer buttons.
+
+        listOf(
+            Triple(MiniplayerModernExpandButtonFingerprint, modernMiniplayerExpand,"hideMiniplayerExpandClose"),
+            Triple(MiniplayerModernCloseButtonFingerprint, modernMiniplayerClose, "hideMiniplayerExpandClose"),
+            Triple(MiniplayerModernRewindButtonFingerprint, modernMiniplayerRewindButton, "hideMiniplayerRewindForward"),
+            Triple(MiniplayerModernForwardButtonFingerprint, modernMiniplayerForwardButton, "hideMiniplayerRewindForward"),
+            Triple(MiniplayerModernOverlayViewFingerprint, scrimOverlay, "adjustMiniplayerOpacity")
+        ).forEach { (fingerprint, literalValue, methodName) ->
+            fingerprint.resolve(
+                context,
+                MiniplayerModernViewParentFingerprint.resultOrThrow().classDef
+            )
+
+            fingerprint.hookInflatedView(
+                literalValue,
+                "Landroid/widget/ImageView;",
+                "$INTEGRATIONS_CLASS_DESCRIPTOR->$methodName(Landroid/widget/ImageView;)V"
+            )
+        }
+
+        MiniplayerModernAddViewListenerFingerprint.apply {
+            resolve(
+                context,
+                MiniplayerModernViewParentFingerprint.resultOrThrow().classDef
+            )
+        }.resultOrThrow().mutableMethod.addInstruction(
+            0,
+            "invoke-static { p1 }, $INTEGRATIONS_CLASS_DESCRIPTOR->" +
+                    "hideMiniplayerSubTexts(Landroid/view/View;)V"
+        )
+
+
+        // Modern 2 has a broken overlay subtitle view that is always present.
+        // Modern 2 uses the same overlay controls as the regular video player,
+        // and the overlay views are added at runtime.
+        // Add a hook to the overlay class, and pass the added views to integrations.
+        YouTubePlayerOverlaysLayoutFingerprint.resultOrThrow().mutableClass.methods.add(
+            ImmutableMethod(
+                YOUTUBE_PLAYER_OVERLAYS_LAYOUT_CLASS_NAME,
+                "addView",
+                listOf(
+                    ImmutableMethodParameter("Landroid/view/View;", null, null),
+                    ImmutableMethodParameter("I", null, null),
+                    ImmutableMethodParameter("Landroid/view/ViewGroup\$LayoutParams;", null, null),
+                ),
+                "V",
+                AccessFlags.PUBLIC.value,
+                null,
+                null,
+                MutableMethodImplementation(4),
+            ).toMutable().apply {
+                addInstructions(
+                    """
+                        invoke-super { p0, p1, p2, p3 }, Landroid/view/ViewGroup;->addView(Landroid/view/View;ILandroid/view/ViewGroup${'$'}LayoutParams;)V
+                        invoke-static { p1 }, $INTEGRATIONS_CLASS_DESCRIPTOR->playerOverlayGroupCreated(Landroid/view/View;)V
+                        return-void
+                    """,
+                )
+            }
+        )
+
+        // endregion
+    }
+
+    private fun Method.findReturnIndicesReversed() = findOpcodeIndicesReversed(Opcode.RETURN)
+
+    /**
+     * Adds an override to force legacy tablet miniplayer to be used or not used.
+     */
+    private fun MutableMethod.insertLegacyTabletMiniplayerOverride(index: Int) {
+        insertBooleanOverride(index, "getLegacyTabletMiniplayerOverride")
+    }
+
+    /**
+     * Adds an override to force modern miniplayer to be used or not used.
+     */
+    private fun MutableMethod.insertModernMiniplayerOverride(index: Int) {
+        insertBooleanOverride(index, "getModernMiniplayerOverride")
+    }
+
+    private fun MutableMethod.insertBooleanOverride(index: Int, methodName: String) {
+        val register = getInstruction<OneRegisterInstruction>(index).registerA
+        addInstructions(
+            index,
+            """
+                invoke-static {v$register}, $INTEGRATIONS_CLASS_DESCRIPTOR->$methodName(Z)Z
+                move-result v$register
+            """
+        )
+    }
+
+    /**
+     * Adds an override to specify which modern miniplayer is used.
+     */
+    private fun MutableMethod.insertModernMiniplayerTypeOverride(iPutIndex: Int) {
+        val targetInstruction = getInstruction<TwoRegisterInstruction>(iPutIndex)
+        val targetReference = (targetInstruction as ReferenceInstruction).reference
+
+        addInstructions(
+            iPutIndex + 1, """
+                invoke-static { v${targetInstruction.registerA} }, $INTEGRATIONS_CLASS_DESCRIPTOR->getModernMiniplayerOverrideType(I)I
+                move-result v${targetInstruction.registerA}
+                # Original instruction
+                iput v${targetInstruction.registerA}, v${targetInstruction.registerB}, $targetReference 
+            """
+        )
+        removeInstruction(iPutIndex)
+    }
+
+    private fun LiteralValueFingerprint.hookInflatedView(
+        literalValue: Long,
+        hookedClassType: String,
+        integrationsMethodName: String,
+    ) {
+        resultOrThrow().mutableMethod.apply {
+            val imageViewIndex = indexOfFirstInstructionOrThrow(
+                indexOfFirstWideLiteralInstructionValueOrThrow(literalValue)
+            ) {
+                opcode == Opcode.CHECK_CAST && getReference<TypeReference>()?.type == hookedClassType
+            }
+
+            val register = getInstruction<OneRegisterInstruction>(imageViewIndex).registerA
+            addInstruction(
+                imageViewIndex + 1,
+                "invoke-static { v$register }, $integrationsMethodName"
+            )
+        }
+    }
+}
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/MiniplayerResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/MiniplayerResourcePatch.kt
new file mode 100644
index 00000000..3870f065
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/MiniplayerResourcePatch.kt
@@ -0,0 +1,81 @@
+package app.revanced.patches.youtube.layout.miniplayer
+
+import app.revanced.patcher.data.ResourceContext
+import app.revanced.patcher.patch.PatchException
+import app.revanced.patcher.patch.ResourcePatch
+import app.revanced.patcher.patch.annotation.Patch
+import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch
+
+@Patch(dependencies = [ResourceMappingPatch::class])
+internal object MiniplayerResourcePatch : ResourcePatch() {
+    var floatyBarButtonTopMargin = -1L
+
+    // Only available in 19.15 and upwards.
+    var ytOutlineXWhite24 = -1L
+    var ytOutlinePictureInPictureWhite24 = -1L
+    var scrimOverlay = -1L
+    var modernMiniplayerClose = -1L
+    var modernMiniplayerExpand = -1L
+    var modernMiniplayerRewindButton = -1L
+    var modernMiniplayerForwardButton = -1L
+    var playerOverlays = -1L
+
+    override fun execute(context: ResourceContext) {
+        floatyBarButtonTopMargin = ResourceMappingPatch[
+            "dimen",
+            "floaty_bar_button_top_margin"
+        ]
+
+        try {
+            ytOutlinePictureInPictureWhite24 = ResourceMappingPatch[
+                "drawable",
+                "yt_outline_picture_in_picture_white_24"
+            ]
+        } catch (exception: PatchException) {
+            // Ignore, and assume the app is 19.14 or earlier.
+            return
+        }
+
+        ytOutlineXWhite24 = ResourceMappingPatch[
+            "drawable",
+            "yt_outline_x_white_24"
+        ]
+
+        scrimOverlay = ResourceMappingPatch[
+            "id",
+            "scrim_overlay"
+        ]
+
+        modernMiniplayerClose = ResourceMappingPatch[
+            "id",
+            "modern_miniplayer_close"
+        ]
+
+        modernMiniplayerExpand = ResourceMappingPatch[
+            "id",
+            "modern_miniplayer_expand"
+        ]
+
+        modernMiniplayerRewindButton = ResourceMappingPatch[
+            "id",
+            "modern_miniplayer_rewind_button"
+        ]
+
+        modernMiniplayerForwardButton = ResourceMappingPatch[
+            "id",
+            "modern_miniplayer_forward_button"
+        ]
+
+        playerOverlays = ResourceMappingPatch[
+            "layout",
+            "player_overlays"
+        ]
+
+        // Resource id is not used during patching, but is used by integrations.
+        // Verify the resource is present while patching.
+        ResourceMappingPatch[
+            "id",
+            "modern_miniplayer_subtitle_text"
+        ]
+    }
+}
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerDimensionsCalculatorParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerDimensionsCalculatorParentFingerprint.kt
new file mode 100644
index 00000000..bc156e7a
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerDimensionsCalculatorParentFingerprint.kt
@@ -0,0 +1,13 @@
+package app.revanced.patches.youtube.layout.miniplayer.fingerprints
+
+import app.revanced.patcher.extensions.or
+import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch
+import app.revanced.util.patch.LiteralValueFingerprint
+import com.android.tools.smali.dexlib2.AccessFlags
+
+internal object MiniplayerDimensionsCalculatorParentFingerprint : LiteralValueFingerprint(
+    accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
+    returnType = "V",
+    parameters = listOf("L"),
+    literalSupplier = { MiniplayerResourcePatch.floatyBarButtonTopMargin }
+)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerModernAddViewListenerFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerModernAddViewListenerFingerprint.kt
new file mode 100644
index 00000000..c4e94724
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerModernAddViewListenerFingerprint.kt
@@ -0,0 +1,14 @@
+package app.revanced.patches.youtube.layout.miniplayer.fingerprints
+
+import app.revanced.patcher.extensions.or
+import app.revanced.patcher.fingerprint.MethodFingerprint
+import com.android.tools.smali.dexlib2.AccessFlags
+
+/**
+ * Resolves using the class found in [MiniplayerModernViewParentFingerprint].
+ */
+internal object MiniplayerModernAddViewListenerFingerprint : MethodFingerprint(
+    accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
+    returnType = "V",
+    parameters = listOf("Landroid/view/View;")
+)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerModernCloseButtonFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerModernCloseButtonFingerprint.kt
new file mode 100644
index 00000000..e4bbd9aa
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerModernCloseButtonFingerprint.kt
@@ -0,0 +1,16 @@
+package app.revanced.patches.youtube.layout.miniplayer.fingerprints
+
+import app.revanced.patcher.extensions.or
+import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch
+import app.revanced.util.patch.LiteralValueFingerprint
+import com.android.tools.smali.dexlib2.AccessFlags
+
+/**
+ * Resolves using the class found in [MiniplayerModernViewParentFingerprint].
+ */
+internal object MiniplayerModernCloseButtonFingerprint : LiteralValueFingerprint(
+    accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
+    returnType = "Landroid/widget/ImageView;",
+    parameters = listOf(),
+    literalSupplier = { MiniplayerResourcePatch.modernMiniplayerClose }
+)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerModernConstructorFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerModernConstructorFingerprint.kt
new file mode 100644
index 00000000..0afb5e52
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerModernConstructorFingerprint.kt
@@ -0,0 +1,11 @@
+package app.revanced.patches.youtube.layout.miniplayer.fingerprints
+
+import app.revanced.patcher.extensions.or
+import app.revanced.util.patch.LiteralValueFingerprint
+import com.android.tools.smali.dexlib2.AccessFlags
+
+internal object MiniplayerModernConstructorFingerprint : LiteralValueFingerprint(
+    accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
+    parameters = listOf("L"),
+    literalSupplier = { 45623000L } // Magic number found in the constructor.
+)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerModernExpandButtonFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerModernExpandButtonFingerprint.kt
new file mode 100644
index 00000000..35629e30
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerModernExpandButtonFingerprint.kt
@@ -0,0 +1,16 @@
+package app.revanced.patches.youtube.layout.miniplayer.fingerprints
+
+import app.revanced.patcher.extensions.or
+import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch
+import app.revanced.util.patch.LiteralValueFingerprint
+import com.android.tools.smali.dexlib2.AccessFlags
+
+/**
+ * Resolves using the class found in [MiniplayerModernViewParentFingerprint].
+ */
+internal object MiniplayerModernExpandButtonFingerprint : LiteralValueFingerprint(
+    accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
+    returnType = "Landroid/widget/ImageView;",
+    parameters = listOf(),
+    literalSupplier = { MiniplayerResourcePatch.modernMiniplayerExpand }
+)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerModernExpandCloseDrawablesFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerModernExpandCloseDrawablesFingerprint.kt
new file mode 100644
index 00000000..9ee56819
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerModernExpandCloseDrawablesFingerprint.kt
@@ -0,0 +1,16 @@
+package app.revanced.patches.youtube.layout.miniplayer.fingerprints
+
+import app.revanced.patcher.extensions.or
+import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch
+import app.revanced.util.patch.LiteralValueFingerprint
+import com.android.tools.smali.dexlib2.AccessFlags
+
+/**
+ * Resolves using the class found in [MiniplayerModernViewParentFingerprint].
+ */
+internal object MiniplayerModernExpandCloseDrawablesFingerprint : LiteralValueFingerprint(
+    accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
+    returnType = "V",
+    parameters = listOf("L"),
+    literalSupplier = { MiniplayerResourcePatch.ytOutlinePictureInPictureWhite24 }
+)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerModernForwardButtonFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerModernForwardButtonFingerprint.kt
new file mode 100644
index 00000000..52053750
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerModernForwardButtonFingerprint.kt
@@ -0,0 +1,16 @@
+package app.revanced.patches.youtube.layout.miniplayer.fingerprints
+
+import app.revanced.patcher.extensions.or
+import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch
+import app.revanced.util.patch.LiteralValueFingerprint
+import com.android.tools.smali.dexlib2.AccessFlags
+
+/**
+ * Resolves using the class found in [MiniplayerModernViewParentFingerprint].
+ */
+internal object MiniplayerModernForwardButtonFingerprint : LiteralValueFingerprint(
+    accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
+    returnType = "Landroid/widget/ImageView;",
+    parameters = listOf(),
+    literalSupplier = { MiniplayerResourcePatch.modernMiniplayerForwardButton }
+)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerModernOverlayViewFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerModernOverlayViewFingerprint.kt
new file mode 100644
index 00000000..02730f44
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerModernOverlayViewFingerprint.kt
@@ -0,0 +1,16 @@
+package app.revanced.patches.youtube.layout.miniplayer.fingerprints
+
+import app.revanced.patcher.extensions.or
+import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch
+import app.revanced.util.patch.LiteralValueFingerprint
+import com.android.tools.smali.dexlib2.AccessFlags
+
+/**
+ * Resolves using the class found in [MiniplayerModernViewParentFingerprint].
+ */
+internal object MiniplayerModernOverlayViewFingerprint : LiteralValueFingerprint(
+    accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
+    returnType = "V",
+    parameters = listOf(),
+    literalSupplier = { MiniplayerResourcePatch.scrimOverlay }
+)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerModernRewindButtonFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerModernRewindButtonFingerprint.kt
new file mode 100644
index 00000000..71b9c054
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerModernRewindButtonFingerprint.kt
@@ -0,0 +1,16 @@
+package app.revanced.patches.youtube.layout.miniplayer.fingerprints
+
+import app.revanced.patcher.extensions.or
+import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch
+import app.revanced.util.patch.LiteralValueFingerprint
+import com.android.tools.smali.dexlib2.AccessFlags
+
+/**
+ * Resolves using the class found in [MiniplayerModernViewParentFingerprint].
+ */
+internal object MiniplayerModernRewindButtonFingerprint : LiteralValueFingerprint(
+    accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
+    returnType = "Landroid/widget/ImageView;",
+    parameters = listOf(),
+    literalSupplier = { MiniplayerResourcePatch.modernMiniplayerRewindButton }
+)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerModernViewParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerModernViewParentFingerprint.kt
new file mode 100644
index 00000000..a6baeec7
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerModernViewParentFingerprint.kt
@@ -0,0 +1,12 @@
+package app.revanced.patches.youtube.layout.miniplayer.fingerprints
+
+import app.revanced.patcher.extensions.or
+import app.revanced.patcher.fingerprint.MethodFingerprint
+import com.android.tools.smali.dexlib2.AccessFlags
+
+internal object MiniplayerModernViewParentFingerprint : MethodFingerprint(
+    accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
+    returnType = "Ljava/lang/String;",
+    parameters = listOf(),
+    strings = listOf("player_overlay_modern_mini_player_controls")
+)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/fingerprints/MiniPlayerOverrideFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerOverrideFingerprint.kt
similarity index 68%
rename from src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/fingerprints/MiniPlayerOverrideFingerprint.kt
rename to src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerOverrideFingerprint.kt
index 9e80c81a..9d9bf5e1 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/fingerprints/MiniPlayerOverrideFingerprint.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerOverrideFingerprint.kt
@@ -1,10 +1,10 @@
-package app.revanced.patches.youtube.layout.tabletminiplayer.fingerprints
+package app.revanced.patches.youtube.layout.miniplayer.fingerprints
 
 import app.revanced.patcher.extensions.or
 import app.revanced.patcher.fingerprint.MethodFingerprint
 import com.android.tools.smali.dexlib2.AccessFlags
 
-internal object MiniPlayerOverrideFingerprint : MethodFingerprint(
+internal object MiniplayerOverrideFingerprint : MethodFingerprint(
     returnType = "L",
     accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
     parameters = listOf("L"),
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerOverrideNoContextFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerOverrideNoContextFingerprint.kt
new file mode 100644
index 00000000..53900f99
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerOverrideNoContextFingerprint.kt
@@ -0,0 +1,12 @@
+package app.revanced.patches.youtube.layout.miniplayer.fingerprints
+
+import app.revanced.patcher.extensions.or
+import app.revanced.patcher.fingerprint.MethodFingerprint
+import com.android.tools.smali.dexlib2.AccessFlags
+import com.android.tools.smali.dexlib2.Opcode
+
+internal object MiniplayerOverrideNoContextFingerprint : MethodFingerprint(
+    accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL,
+    returnType = "Z",
+    opcodes = listOf(Opcode.IGET_BOOLEAN), // anchor to insert the instruction
+)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/fingerprints/MiniPlayerResponseModelSizeCheckFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerResponseModelSizeCheckFingerprint.kt
similarity index 56%
rename from src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/fingerprints/MiniPlayerResponseModelSizeCheckFingerprint.kt
rename to src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerResponseModelSizeCheckFingerprint.kt
index 4ac508ed..b25e727c 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/fingerprints/MiniPlayerResponseModelSizeCheckFingerprint.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/MiniplayerResponseModelSizeCheckFingerprint.kt
@@ -1,15 +1,15 @@
-package app.revanced.patches.youtube.layout.tabletminiplayer.fingerprints
+package app.revanced.patches.youtube.layout.miniplayer.fingerprints
 
 import app.revanced.patcher.extensions.or
 import app.revanced.patcher.fingerprint.MethodFingerprint
 import com.android.tools.smali.dexlib2.AccessFlags
 import com.android.tools.smali.dexlib2.Opcode
 
-internal object MiniPlayerResponseModelSizeCheckFingerprint : MethodFingerprint(
-    "L",
-    AccessFlags.PUBLIC or AccessFlags.FINAL,
-    listOf("Ljava/lang/Object;", "Ljava/lang/Object;"),
-    listOf(
+internal object MiniplayerResponseModelSizeCheckFingerprint : MethodFingerprint(
+    accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
+    returnType = "L",
+    parameters = listOf("Ljava/lang/Object;", "Ljava/lang/Object;"),
+    opcodes = listOf(
         Opcode.RETURN_OBJECT,
         Opcode.CHECK_CAST,
         Opcode.CHECK_CAST,
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/YouTubePlayerOverlaysLayoutFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/YouTubePlayerOverlaysLayoutFingerprint.kt
new file mode 100644
index 00000000..c53a208e
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/fingerprints/YouTubePlayerOverlaysLayoutFingerprint.kt
@@ -0,0 +1,13 @@
+package app.revanced.patches.youtube.layout.miniplayer.fingerprints
+
+import app.revanced.patcher.fingerprint.MethodFingerprint
+import app.revanced.patches.youtube.layout.miniplayer.fingerprints.YouTubePlayerOverlaysLayoutFingerprint.YOUTUBE_PLAYER_OVERLAYS_LAYOUT_CLASS_NAME
+
+internal object YouTubePlayerOverlaysLayoutFingerprint : MethodFingerprint(
+    customFingerprint = { _, classDef ->
+        classDef.type == YOUTUBE_PLAYER_OVERLAYS_LAYOUT_CLASS_NAME
+    }
+) {
+    const val YOUTUBE_PLAYER_OVERLAYS_LAYOUT_CLASS_NAME =
+        "Lcom/google/android/apps/youtube/app/common/player/overlay/YouTubePlayerOverlaysLayout;"
+}
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/player/overlay/CustomPlayerOverlayOpacityPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/player/overlay/CustomPlayerOverlayOpacityPatch.kt
index fd00bf39..f64d7d76 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/player/overlay/CustomPlayerOverlayOpacityPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/player/overlay/CustomPlayerOverlayOpacityPatch.kt
@@ -1,7 +1,5 @@
 package app.revanced.patches.youtube.layout.player.overlay
 
-import app.revanced.util.exception
-import app.revanced.util.indexOfFirstWideLiteralInstructionValue
 import app.revanced.patcher.data.BytecodeContext
 import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
 import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
@@ -9,6 +7,8 @@ import app.revanced.patcher.patch.BytecodePatch
 import app.revanced.patcher.patch.annotation.CompatiblePackage
 import app.revanced.patcher.patch.annotation.Patch
 import app.revanced.patches.youtube.layout.player.overlay.fingerprints.CreatePlayerOverviewFingerprint
+import app.revanced.util.exception
+import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow
 import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
 
 @Patch(
@@ -27,7 +27,7 @@ object CustomPlayerOverlayOpacityPatch : BytecodePatch(setOf(CreatePlayerOvervie
         CreatePlayerOverviewFingerprint.result?.let { result ->
             result.mutableMethod.apply {
                 val viewRegisterIndex =
-                    indexOfFirstWideLiteralInstructionValue(CustomPlayerOverlayOpacityResourcePatch.scrimOverlayId) + 3
+                    indexOfFirstWideLiteralInstructionValueOrThrow(CustomPlayerOverlayOpacityResourcePatch.scrimOverlayId) + 3
                 val viewRegister =
                     getInstruction<OneRegisterInstruction>(viewRegisterIndex).registerA
 
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/SeekbarColorBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/SeekbarColorBytecodePatch.kt
index 98acf716..08d3fa02 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/SeekbarColorBytecodePatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/SeekbarColorBytecodePatch.kt
@@ -1,7 +1,5 @@
 package app.revanced.patches.youtube.layout.seekbar
 
-import app.revanced.util.exception
-import app.revanced.util.indexOfFirstWideLiteralInstructionValue
 import app.revanced.patcher.data.BytecodeContext
 import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
 import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
@@ -15,6 +13,8 @@ import app.revanced.patches.youtube.layout.seekbar.fingerprints.ShortsSeekbarCol
 import app.revanced.patches.youtube.layout.theme.LithoColorHookPatch
 import app.revanced.patches.youtube.layout.theme.LithoColorHookPatch.lithoColorOverrideHook
 import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
+import app.revanced.util.exception
+import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow
 import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
 import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
 
@@ -30,7 +30,7 @@ internal object SeekbarColorBytecodePatch : BytecodePatch(
 
     override fun execute(context: BytecodeContext) {
         fun MutableMethod.addColorChangeInstructions(resourceId: Long) {
-            val registerIndex = indexOfFirstWideLiteralInstructionValue(resourceId) + 2
+            val registerIndex = indexOfFirstWideLiteralInstructionValueOrThrow(resourceId) + 2
             val colorRegister = getInstruction<OneRegisterInstruction>(registerIndex).registerA
             addInstructions(
                 registerIndex + 1,
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/tablet/EnableTabletLayoutPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/tablet/EnableTabletLayoutPatch.kt
index f09c7d69..8b41fc5d 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/tablet/EnableTabletLayoutPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/tablet/EnableTabletLayoutPatch.kt
@@ -13,18 +13,51 @@ import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
 import app.revanced.patches.youtube.layout.tablet.fingerprints.GetFormFactorFingerprint
 import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
 import app.revanced.patches.youtube.misc.settings.SettingsPatch
-import app.revanced.util.exception
+import app.revanced.util.resultOrThrow
 
 @Patch(
     name = "Enable tablet layout",
-    description = "Adds an option to spoof the device form factor to a tablet which enables the tablet layout.",
-    dependencies = [IntegrationsPatch::class, SettingsPatch::class, AddResourcesPatch::class],
-    compatiblePackages = [CompatiblePackage("com.google.android.youtube")]
+    description = "Adds an option to enable tablet layout",
+    dependencies = [
+        IntegrationsPatch::class,
+        SettingsPatch::class,
+        AddResourcesPatch::class,
+    ],
+    compatiblePackages = [
+        CompatiblePackage(
+            "com.google.android.youtube", arrayOf(
+                "18.32.39",
+                "18.37.36",
+                "18.38.44",
+                "18.43.45",
+                "18.44.41",
+                "18.45.43",
+                "18.48.39",
+                "18.49.37",
+                "19.01.34",
+                "19.02.39",
+                "19.03.36",
+                "19.04.38",
+                "19.05.36",
+                "19.06.39",
+                "19.07.40",
+                "19.08.36",
+                "19.09.38",
+                "19.10.39",
+                "19.11.43",
+                "19.12.41",
+                "19.13.37",
+                "19.14.43",
+                "19.15.36",
+                "19.16.39"
+            )
+        )
+    ]
 )
 @Suppress("unused")
-object EnableTabletLayoutPatch : BytecodePatch(
-    setOf(GetFormFactorFingerprint)
-) {
+object EnableTabletLayoutPatch : BytecodePatch(setOf(GetFormFactorFingerprint)) {
+    private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/youtube/patches/TabletLayoutPatch;"
+
     override fun execute(context: BytecodeContext) {
         AddResourcesPatch(this::class)
 
@@ -32,7 +65,7 @@ object EnableTabletLayoutPatch : BytecodePatch(
             SwitchPreference("revanced_tablet_layout")
         )
 
-        GetFormFactorFingerprint.result?.let {
+        GetFormFactorFingerprint.resultOrThrow().let {
             it.mutableMethod.apply {
                 val returnIsLargeFormFactorIndex = getInstructions().lastIndex - 4
                 val returnIsLargeFormFactorLabel = getInstruction(returnIsLargeFormFactorIndex)
@@ -40,8 +73,8 @@ object EnableTabletLayoutPatch : BytecodePatch(
                 addInstructionsWithLabels(
                     0,
                     """
-                          invoke-static { }, Lapp/revanced/integrations/youtube/patches/EnableTabletLayoutPatch;->enableTabletLayout()Z
-                          move-result v0 # Free register
+                          invoke-static { }, $INTEGRATIONS_CLASS_DESCRIPTOR->getTabletLayoutEnabled()Z
+                          move-result v0
                           if-nez v0, :is_large_form_factor
                     """,
                     ExternalLabel(
@@ -50,6 +83,6 @@ object EnableTabletLayoutPatch : BytecodePatch(
                     )
                 )
             }
-        } ?: GetFormFactorFingerprint.exception
+        }
     }
 }
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/tablet/fingerprints/GetFormFactorFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/tablet/fingerprints/GetFormFactorFingerprint.kt
index c7cb6d1e..8742fe5b 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/tablet/fingerprints/GetFormFactorFingerprint.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/tablet/fingerprints/GetFormFactorFingerprint.kt
@@ -21,5 +21,6 @@ internal object GetFormFactorFingerprint : MethodFingerprint(
         Opcode.INVOKE_STATIC,
         Opcode.MOVE_RESULT_OBJECT,
         Opcode.RETURN_OBJECT
-    )
+    ),
+    strings = listOf("")
 )
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/TabletMiniPlayerPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/TabletMiniPlayerPatch.kt
index d3b4183a..6b1f154b 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/TabletMiniPlayerPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/TabletMiniPlayerPatch.kt
@@ -1,152 +1,11 @@
 package app.revanced.patches.youtube.layout.tabletminiplayer
 
 import app.revanced.patcher.data.BytecodeContext
-import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
-import app.revanced.patcher.fingerprint.MethodFingerprint
 import app.revanced.patcher.patch.BytecodePatch
-import app.revanced.patcher.patch.PatchException
-import app.revanced.patcher.patch.annotation.CompatiblePackage
-import app.revanced.patcher.patch.annotation.Patch
-import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
-import app.revanced.patches.all.misc.resources.AddResourcesPatch
-import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
-import app.revanced.patches.youtube.layout.tabletminiplayer.fingerprints.MiniPlayerDimensionsCalculatorParentFingerprint
-import app.revanced.patches.youtube.layout.tabletminiplayer.fingerprints.MiniPlayerOverrideFingerprint
-import app.revanced.patches.youtube.layout.tabletminiplayer.fingerprints.MiniPlayerOverrideNoContextFingerprint
-import app.revanced.patches.youtube.layout.tabletminiplayer.fingerprints.MiniPlayerResponseModelSizeCheckFingerprint
-import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
-import app.revanced.patches.youtube.misc.settings.SettingsPatch
-import app.revanced.util.exception
-import com.android.tools.smali.dexlib2.Opcode
-import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
+import app.revanced.patches.youtube.layout.miniplayer.MiniplayerPatch
 
-@Patch(
-    name = "Tablet mini player",
-    description = "Adds an option to enable the tablet mini player layout.",
-    dependencies = [IntegrationsPatch::class, SettingsPatch::class, AddResourcesPatch::class],
-    compatiblePackages = [
-        CompatiblePackage(
-            "com.google.android.youtube", arrayOf(
-                "18.32.39",
-                "18.37.36",
-                "18.38.44",
-                "18.43.45",
-                "18.44.41",
-                "18.45.43",
-                "18.48.39",
-                "18.49.37",
-                "19.01.34",
-                "19.02.39",
-                "19.03.36",
-                "19.04.38",
-                "19.05.36",
-                "19.06.39",
-                "19.07.40",
-                "19.08.36",
-                "19.09.38",
-                "19.10.39",
-                "19.11.43",
-                "19.12.41",
-                "19.13.37",
-                "19.14.43",
-                "19.15.36",
-                "19.16.39",
-            )
-        )
-    ]
-)
-@Suppress("unused")
-object TabletMiniPlayerPatch : BytecodePatch(
-    setOf(
-        MiniPlayerDimensionsCalculatorParentFingerprint,
-        MiniPlayerResponseModelSizeCheckFingerprint,
-        MiniPlayerOverrideFingerprint
-    )
-) {
+@Deprecated("This patch class has been renamed to Miniplayer.")
+object TabletMiniPlayerPatch : BytecodePatch(dependencies = setOf(MiniplayerPatch::class)) {
     override fun execute(context: BytecodeContext) {
-        AddResourcesPatch(this::class)
-
-        SettingsPatch.PreferenceScreen.GENERAL_LAYOUT.addPreferences(
-            SwitchPreference("revanced_tablet_miniplayer")
-        )
-
-        // First resolve the fingerprints via the parent fingerprint.
-        MiniPlayerDimensionsCalculatorParentFingerprint.result
-            ?: throw MiniPlayerDimensionsCalculatorParentFingerprint.exception
-        val miniPlayerClass = MiniPlayerDimensionsCalculatorParentFingerprint.result!!.classDef
-
-        /*
-         * No context parameter method.
-         */
-        MiniPlayerOverrideNoContextFingerprint.resolve(context, miniPlayerClass)
-        val (method, _, parameterRegister) = MiniPlayerOverrideNoContextFingerprint.addProxyCall()
-
-        // Insert right before the return instruction.
-        val secondInsertIndex = method.implementation!!.instructions.size - 1
-        method.insertOverride(
-            secondInsertIndex, parameterRegister
-            /** same register used to return **/
-        )
-
-        /*
-         * Override every return instruction with the proxy call.
-         */
-        MiniPlayerOverrideFingerprint.result?.let { result ->
-            result.mutableMethod.let { method ->
-                val appNameStringIndex = result.scanResult.stringsScanResult!!.matches.first().index + 2
-                context.toMethodWalker(method).nextMethod(appNameStringIndex, true)
-                    .getMethod() as MutableMethod
-            }.apply {
-                implementation!!.let { implementation ->
-                    val returnIndices = implementation.instructions
-                        .withIndex()
-                        .filter { (_, instruction) -> instruction.opcode == Opcode.RETURN }
-                        .map { (index, _) -> index }
-
-                    if (returnIndices.isEmpty()) throw PatchException("No return instructions found.")
-
-                    // This method clobbers register p0 to return the value, calculate to override.
-                    val returnedRegister = implementation.registerCount - parameters.size
-
-                    // Hook the returned register on every return instruction.
-                    returnIndices.forEach { index -> insertOverride(index, returnedRegister) }
-                }
-            }
-
-            return@let
-        } ?: throw MiniPlayerOverrideFingerprint.exception
-
-        /*
-         * Size check return value override.
-         */
-        MiniPlayerResponseModelSizeCheckFingerprint.addProxyCall()
-    }
-
-    // Helper methods.
-    private fun MethodFingerprint.addProxyCall(): Triple<MutableMethod, Int, Int> {
-        val (method, scanIndex, parameterRegister) = this.unwrap()
-        method.insertOverride(scanIndex, parameterRegister)
-
-        return Triple(method, scanIndex, parameterRegister)
-    }
-
-    private fun MutableMethod.insertOverride(index: Int, overrideRegister: Int) {
-        this.addInstructions(
-            index,
-            """
-                    invoke-static {v$overrideRegister}, Lapp/revanced/integrations/youtube/patches/TabletMiniPlayerOverridePatch;->getTabletMiniPlayerOverride(Z)Z
-                    move-result v$overrideRegister
-                """
-        )
-    }
-
-    private fun MethodFingerprint.unwrap(): Triple<MutableMethod, Int, Int> {
-        val result = this.result!!
-        val scanIndex = result.scanResult.patternScanResult!!.endIndex
-        val method = result.mutableMethod
-        val instructions = method.implementation!!.instructions
-        val parameterRegister = (instructions[scanIndex] as OneRegisterInstruction).registerA
-
-        return Triple(method, scanIndex, parameterRegister)
     }
 }
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/fingerprints/MiniPlayerDimensionsCalculatorParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/fingerprints/MiniPlayerDimensionsCalculatorParentFingerprint.kt
deleted file mode 100644
index 2e161237..00000000
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/fingerprints/MiniPlayerDimensionsCalculatorParentFingerprint.kt
+++ /dev/null
@@ -1,23 +0,0 @@
-package app.revanced.patches.youtube.layout.tabletminiplayer.fingerprints
-
-import app.revanced.patcher.extensions.or
-import app.revanced.patcher.fingerprint.MethodFingerprint
-import com.android.tools.smali.dexlib2.AccessFlags
-import com.android.tools.smali.dexlib2.Opcode
-
-internal object MiniPlayerDimensionsCalculatorParentFingerprint : MethodFingerprint(
-    accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
-    returnType = "V",
-    parameters = listOf("F"),
-    opcodes = listOf(
-        Opcode.CONST_HIGH16,
-        Opcode.ADD_FLOAT_2ADDR,
-        null, // Opcode.MUL_FLOAT or Opcode.MUL_FLOAT_2ADDR
-        Opcode.CONST_4,
-        Opcode.INVOKE_STATIC,
-        Opcode.MOVE_RESULT,
-        Opcode.FLOAT_TO_INT,
-        Opcode.INVOKE_INTERFACE,
-        Opcode.RETURN_VOID,
-    )
-)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/fingerprints/MiniPlayerOverrideNoContextFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/fingerprints/MiniPlayerOverrideNoContextFingerprint.kt
deleted file mode 100644
index c6ea61f3..00000000
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/fingerprints/MiniPlayerOverrideNoContextFingerprint.kt
+++ /dev/null
@@ -1,11 +0,0 @@
-package app.revanced.patches.youtube.layout.tabletminiplayer.fingerprints
-
-import app.revanced.patcher.extensions.or
-import app.revanced.patcher.fingerprint.MethodFingerprint
-import com.android.tools.smali.dexlib2.AccessFlags
-import com.android.tools.smali.dexlib2.Opcode
-
-internal object MiniPlayerOverrideNoContextFingerprint : MethodFingerprint(
-    "Z", AccessFlags.FINAL or AccessFlags.PRIVATE,
-    opcodes = listOf(Opcode.RETURN), // anchor to insert the instruction
-)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/theme/ThemeBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/theme/ThemeBytecodePatch.kt
index 3e9bfd60..23d7a62f 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/theme/ThemeBytecodePatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/theme/ThemeBytecodePatch.kt
@@ -16,7 +16,7 @@ import app.revanced.patches.youtube.layout.theme.fingerprints.UseGradientLoading
 import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
 import app.revanced.patches.youtube.misc.settings.SettingsPatch
 import app.revanced.util.exception
-import app.revanced.util.indexOfFirstWideLiteralInstructionValue
+import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow
 import app.revanced.util.resultOrThrow
 import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
 
@@ -123,7 +123,7 @@ object ThemeBytecodePatch : BytecodePatch(
         )
 
         UseGradientLoadingScreenFingerprint.result?.mutableMethod?.apply {
-            val isEnabledIndex = indexOfFirstWideLiteralInstructionValue(GRADIENT_LOADING_SCREEN_AB_CONSTANT) + 3
+            val isEnabledIndex = indexOfFirstWideLiteralInstructionValueOrThrow(GRADIENT_LOADING_SCREEN_AB_CONSTANT) + 3
             val isEnabledRegister = getInstruction<OneRegisterInstruction>(isEnabledIndex - 1).registerA
 
             addInstructions(
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofClientPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofClientPatch.kt
index c008f673..de699484 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofClientPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofClientPatch.kt
@@ -286,9 +286,12 @@ object SpoofClientPatch : BytecodePatch(
         // Fix playback speed menu item if spoofing to iOS.
 
         CreatePlaybackSpeedMenuItemFingerprint.resultOrThrow().let {
-            val shouldCreateMenuIndex = it.scanResult.patternScanResult!!.endIndex
+            val scanResult = it.scanResult.patternScanResult!!
+            if (scanResult.startIndex != 0) throw PatchException("Unexpected start index: ${scanResult.startIndex}")
 
             it.mutableMethod.apply {
+                // Find the conditional check if the playback speed menu item is not created.
+                val shouldCreateMenuIndex = indexOfFirstInstructionOrThrow(scanResult.endIndex) { opcode == Opcode.IF_EQZ }
                 val shouldCreateMenuRegister = getInstruction<OneRegisterInstruction>(shouldCreateMenuIndex).registerA
 
                 addInstructions(
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/CreatePlaybackSpeedMenuItemFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/CreatePlaybackSpeedMenuItemFingerprint.kt
index 389977dd..035771ce 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/CreatePlaybackSpeedMenuItemFingerprint.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/CreatePlaybackSpeedMenuItemFingerprint.kt
@@ -8,15 +8,27 @@ import com.android.tools.smali.dexlib2.Opcode
 internal object CreatePlaybackSpeedMenuItemFingerprint : MethodFingerprint(
     accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
     returnType = "V",
-    parameters = listOf("[L", "F"),
     opcodes = listOf(
-        Opcode.IGET_OBJECT,
+        Opcode.IGET_OBJECT, // First instruction of the method
         Opcode.IGET_OBJECT,
         Opcode.IGET_OBJECT,
         Opcode.CONST_4,
         Opcode.IF_EQZ,
         Opcode.INVOKE_INTERFACE,
-        Opcode.MOVE_RESULT, // Return value controls the creation of the playback speed menu item.
-        Opcode.IF_EQZ, // If the return value is false, the playback speed menu item is not created.
+        null // MOVE_RESULT or MOVE_RESULT_OBJECT, Return value controls the creation of the playback speed menu item.
     ),
+    // 19.01 and earlier is missing the second parameter.
+    // Since this fingerprint is somewhat weak, work around by checking for both method parameter signatures.
+    customFingerprint = custom@{ methodDef, _ ->
+        // 19.01 and earlier parameters are: "[L"
+        // 19.02+ parameters are "[L", "F"
+        val parameterTypes = methodDef.parameterTypes
+        val firstParameter = parameterTypes.firstOrNull()
+
+        if (firstParameter == null || !firstParameter.startsWith("[L")) {
+            return@custom false
+        }
+
+        parameterTypes.size == 1 || (parameterTypes.size == 2 && parameterTypes[1] == "F")
+    }
 )
diff --git a/src/main/kotlin/app/revanced/util/BytecodeUtils.kt b/src/main/kotlin/app/revanced/util/BytecodeUtils.kt
index acc989c3..7e5388d3 100644
--- a/src/main/kotlin/app/revanced/util/BytecodeUtils.kt
+++ b/src/main/kotlin/app/revanced/util/BytecodeUtils.kt
@@ -8,6 +8,7 @@ import app.revanced.patcher.patch.PatchException
 import app.revanced.patcher.util.proxy.mutableTypes.MutableClass
 import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
 import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch
+import com.android.tools.smali.dexlib2.Opcode
 import com.android.tools.smali.dexlib2.iface.Method
 import com.android.tools.smali.dexlib2.iface.instruction.Instruction
 import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
@@ -99,6 +100,7 @@ fun Method.indexOfIdResourceOrThrow(resourceName: String): Int {
  * Find the index of the first wide literal instruction with the given value.
  *
  * @return the first literal instruction with the value, or -1 if not found.
+ * @see indexOfFirstWideLiteralInstructionValueOrThrow
  */
 fun Method.indexOfFirstWideLiteralInstructionValue(literal: Long) = implementation?.let {
     it.instructions.indexOfFirst { instruction ->
@@ -106,6 +108,18 @@ fun Method.indexOfFirstWideLiteralInstructionValue(literal: Long) = implementati
     }
 } ?: -1
 
+/**
+ * Find the index of the first wide literal instruction with the given value,
+ * or throw an exception if not found.
+ *
+ * @return the first literal instruction with the value, or throws [PatchException] if not found.
+ */
+fun Method.indexOfFirstWideLiteralInstructionValueOrThrow(literal: Long) : Int {
+    val index = indexOfFirstWideLiteralInstructionValue(literal)
+    if (index < 0) throw PatchException("Could not find literal value: $literal")
+    return index
+}
+
 /**
  * Check if the method contains a literal with the given value.
  *
@@ -144,7 +158,9 @@ inline fun <reified T : Reference> Instruction.getReference() = (this as? Refere
  * @return The index of the first [Instruction] that matches the predicate.
  */
 // TODO: delete this on next major release, the overloaded method with an optional start index serves the same purposes.
-@Deprecated("Use the overloaded method with an optional start index.", ReplaceWith("indexOfFirstInstruction(predicate)"))
+// Method is deprecated, but annotation is commented out otherwise during compilation usage of the replacement is
+// incorrectly flagged as deprecated.
+//@Deprecated("Use the overloaded method with an optional start index.", ReplaceWith("indexOfFirstInstruction(predicate)"))
 fun Method.indexOfFirstInstruction(predicate: Instruction.() -> Boolean) = indexOfFirstInstruction(0, predicate)
 
 /**
@@ -179,6 +195,21 @@ fun Method.indexOfFirstInstructionOrThrow(startIndex: Int = 0, predicate: Instru
     return index
 }
 
+/**
+ * @return The list of indices of the opcode in reverse order.
+ */
+fun Method.findOpcodeIndicesReversed(opcode: Opcode): List<Int> {
+    val indexes = implementation!!.instructions
+        .withIndex()
+        .filter { (_, instruction) -> instruction.opcode == opcode }
+        .map { (index, _) -> index }
+        .reversed()
+
+    if (indexes.isEmpty()) throw PatchException("No ${opcode.name} instructions found in: $this")
+
+    return indexes
+}
+
 /**
  * Return the resolved methods of [MethodFingerprint]s early.
  */
diff --git a/src/main/resources/addresources/values/arrays.xml b/src/main/resources/addresources/values/arrays.xml
index 5fad2d88..f8f2b421 100644
--- a/src/main/resources/addresources/values/arrays.xml
+++ b/src/main/resources/addresources/values/arrays.xml
@@ -16,6 +16,35 @@
                 <item>17.33.42</item>
             </string-array>
         </patch>
+        <patch id="layout.miniplayer.MiniplayerPatch">
+            <string-array name="revanced_miniplayer_type_19_15_entries">
+                <item>@string/revanced_miniplayer_type_entry_1</item>
+                <item>@string/revanced_miniplayer_type_entry_2</item>
+                <item>@string/revanced_miniplayer_type_entry_3</item>
+                <item>@string/revanced_miniplayer_type_entry_4</item>
+                <item>@string/revanced_miniplayer_type_entry_5</item>
+                <item>@string/revanced_miniplayer_type_entry_6</item>
+            </string-array>
+            <string-array name="revanced_miniplayer_type_19_15_entry_values">
+                <!-- Enum names from Integrations. -->
+                <item>ORIGINAL</item>
+                <item>PHONE</item>
+                <item>TABLET</item>
+                <item>MODERN_1</item>
+                <item>MODERN_2</item>
+                <item>MODERN_3</item>
+            </string-array>
+            <string-array name="revanced_miniplayer_type_legacy_entries">
+                <item>@string/revanced_miniplayer_type_entry_1</item>
+                <item>@string/revanced_miniplayer_type_entry_2</item>
+                <item>@string/revanced_miniplayer_type_entry_3</item>
+            </string-array>
+            <string-array name="revanced_miniplayer_type_legacy_entry_values">
+                <item>ORIGINAL</item>
+                <item>PHONE</item>
+                <item>TABLET</item>
+            </string-array>
+        </patch>
         <patch id="layout.startpage.ChangeStartPagePatch">
             <string-array name="revanced_start_page_entries">
                 <item>@string/revanced_start_page_entry_0</item>
diff --git a/src/main/resources/addresources/values/strings.xml b/src/main/resources/addresources/values/strings.xml
index b4506ea3..774198db 100644
--- a/src/main/resources/addresources/values/strings.xml
+++ b/src/main/resources/addresources/values/strings.xml
@@ -661,6 +661,7 @@
         <patch id="layout.player.overlay.CustomPlayerOverlayOpacityResourcePatch">
             <string name="revanced_player_overlay_opacity_title">Player overlay opacity</string>
             <string name="revanced_player_overlay_opacity_summary">Opacity value between 0-100, where 0 is transparent</string>
+            <string name="revanced_player_overlay_opacity_invalid_toast">Player overlay opacity must be between 0-100</string>
         </patch>
         <patch id="layout.returnyoutubedislike.ReturnYouTubeDislikeResourcePatch">
             <string name="revanced_ryd_settings_title">Return YouTube Dislike</string>
@@ -947,11 +948,29 @@
             <string name="revanced_tablet_layout_summary_on">Tablet layout is enabled</string>
             <string name="revanced_tablet_layout_summary_off">Tablet layout is disabled</string>
             <string name="revanced_tablet_layout_user_dialog_message">Community posts do not show up on tablet layouts</string>
-        </patch>
-        <patch id="layout.tabletminiplayer.TabletMiniPlayerPatch">
-            <string name="revanced_tablet_miniplayer_title">Enable tablet mini player</string>
-            <string name="revanced_tablet_miniplayer_summary_on">Mini player is enabled</string>
-            <string name="revanced_tablet_miniplayer_summary_off">Mini player is disabled</string>
+        </patch>x
+        <patch id="layout.miniplayer.MiniplayerPatch">
+            <string name="revanced_miniplayer_screen_title">Miniplayer</string>
+            <string name="revanced_miniplayer_screen_summary">Change the style of the in app minimized player</string>
+            <string name="revanced_miniplayer_type_title">Miniplayer type</string>
+            <string name="revanced_miniplayer_type_entry_1">Original</string>
+            <string name="revanced_miniplayer_type_entry_2">Phone</string>
+            <string name="revanced_miniplayer_type_entry_3">Tablet</string>
+            <string name="revanced_miniplayer_type_entry_4">Modern 1</string>
+            <string name="revanced_miniplayer_type_entry_5">Modern 2</string>
+            <string name="revanced_miniplayer_type_entry_6">Modern 3</string>
+            <string name="revanced_miniplayer_hide_expand_close_title">Hide expand and close buttons</string>
+            <string name="revanced_miniplayer_hide_expand_close_summary_on">Buttons are hidden\n(swipe miniplayer to expand or close)</string>
+            <string name="revanced_miniplayer_hide_expand_close_summary_off">Expand and close buttons are shown</string>
+            <string name="revanced_miniplayer_hide_subtext_title">Hide subtexts</string>
+            <string name="revanced_miniplayer_hide_subtext_summary_on">Subtexts are hidden</string>
+            <string name="revanced_miniplayer_hide_subtext_summary_off">Subtexts are shown</string>
+            <string name="revanced_miniplayer_hide_rewind_forward_title">Hide skip forward and back buttons</string>
+            <string name="revanced_miniplayer_hide_rewind_forward_summary_on">Skip forward and back are hidden</string>
+            <string name="revanced_miniplayer_hide_rewind_forward_summary_off">Skip forward and back are shown</string>
+            <string name="revanced_miniplayer_opacity_title">Overlay opacity</string>
+            <string name="revanced_miniplayer_opacity_summary">Opacity value between 0-100, where 0 is transparent</string>
+            <string name="revanced_miniplayer_opacity_invalid_toast">Miniplayer overlay opacity must be between 0-100</string>
         </patch>
         <patch id="layout.theme.ThemeBytecodePatch">
             <string name="revanced_gradient_loading_screen_title">Enable gradient loading screen</string>