feat(YouTube): Replace with a fingerprint that supports a wider range of versions (..20.06)

This commit is contained in:
inotia00 2025-02-07 18:18:05 +09:00
parent 08202866e7
commit a9d25bf9c2
16 changed files with 391 additions and 255 deletions

View File

@ -1,15 +1,17 @@
package app.revanced.extension.youtube.patches.general;
import static app.revanced.extension.shared.utils.StringRef.str;
import static app.revanced.extension.youtube.patches.general.MiniplayerPatch.MiniplayerType.DEFAULT;
import static app.revanced.extension.youtube.patches.general.MiniplayerPatch.MiniplayerType.DISABLED;
import static app.revanced.extension.youtube.patches.general.MiniplayerPatch.MiniplayerType.MODERN_1;
import static app.revanced.extension.youtube.patches.general.MiniplayerPatch.MiniplayerType.MODERN_2;
import static app.revanced.extension.youtube.patches.general.MiniplayerPatch.MiniplayerType.MODERN_3;
import static app.revanced.extension.youtube.patches.general.MiniplayerPatch.MiniplayerType.ORIGINAL;
import static app.revanced.extension.youtube.patches.general.MiniplayerPatch.MiniplayerType.MODERN_4;
import static app.revanced.extension.youtube.utils.ExtendedUtils.IS_19_20_OR_GREATER;
import static app.revanced.extension.youtube.utils.ExtendedUtils.IS_19_21_OR_GREATER;
import static app.revanced.extension.youtube.utils.ExtendedUtils.IS_19_26_OR_GREATER;
import static app.revanced.extension.youtube.utils.ExtendedUtils.IS_19_29_OR_GREATER;
import static app.revanced.extension.youtube.utils.ExtendedUtils.IS_19_34_OR_GREATER;
import static app.revanced.extension.youtube.utils.ExtendedUtils.validateValue;
import android.content.Context;
@ -27,7 +29,6 @@ import app.revanced.extension.shared.utils.Logger;
import app.revanced.extension.shared.utils.ResourceUtils;
import app.revanced.extension.shared.utils.Utils;
import app.revanced.extension.youtube.settings.Settings;
import app.revanced.extension.youtube.utils.ExtendedUtils;
@SuppressWarnings({"unused", "SpellCheckingInspection"})
public final class MiniplayerPatch {
@ -44,7 +45,7 @@ public final class MiniplayerPatch {
/**
* Unmodified type, and same as un-patched.
*/
ORIGINAL(null, null),
DEFAULT(null, null),
/**
* Exactly the same as MINIMAL and only here for migration of user settings.
* Eventually this should be deleted.
@ -57,10 +58,13 @@ public final class MiniplayerPatch {
MODERN_2(null, 2),
MODERN_3(null, 3),
/**
* Half broken miniplayer, that might be work in progress or left over abandoned code.
* Can force this type by editing the import/export settings.
* Works and is functional with 20.03+
*/
MODERN_4(null, 4);
MODERN_4(null, 4),
/**
* Half broken miniplayer, and in 20.02 and earlier is declared as type 4.
*/
MODERN_5(null, 5);
/**
* Legacy tablet hook value.
@ -157,20 +161,21 @@ public final class MiniplayerPatch {
private static final boolean DRAG_AND_DROP_ENABLED =
CURRENT_TYPE.isModern() && Settings.MINIPLAYER_DRAG_AND_DROP.get();
private static final boolean HIDE_EXPAND_CLOSE_ENABLED =
Settings.MINIPLAYER_HIDE_EXPAND_CLOSE.get()
&& Settings.MINIPLAYER_HIDE_EXPAND_CLOSE.isAvailable();
private static final boolean HIDE_OVERLAY_BUTTONS_ENABLED =
Settings.MINIPLAYER_HIDE_OVERLAY_BUTTONS.get()
&& Settings.MINIPLAYER_HIDE_OVERLAY_BUTTONS.isAvailable();
private static final boolean HIDE_SUBTEXT_ENABLED =
(CURRENT_TYPE == MODERN_1 || CURRENT_TYPE == MODERN_3) && Settings.MINIPLAYER_HIDE_SUBTEXT.get();
(CURRENT_TYPE == MODERN_1 || CURRENT_TYPE == MODERN_3 || CURRENT_TYPE == MODERN_4)
&& Settings.MINIPLAYER_HIDE_SUBTEXT.get();
// 19.25 is last version that has forward/back buttons for phones,
// but buttons still show for tablets/foldable devices and they don't work well so always hide.
private static final boolean HIDE_REWIND_FORWARD_ENABLED = CURRENT_TYPE == MODERN_1
&& (ExtendedUtils.IS_19_34_OR_GREATER || Settings.MINIPLAYER_HIDE_REWIND_FORWARD.get());
&& (IS_19_34_OR_GREATER || Settings.MINIPLAYER_HIDE_REWIND_FORWARD.get());
private static final boolean MINIPLAYER_ROUNDED_CORNERS_ENABLED =
Settings.MINIPLAYER_ROUNDED_CORNERS.get();
CURRENT_TYPE.isModern() && Settings.MINIPLAYER_ROUNDED_CORNERS.get();
private static final boolean MINIPLAYER_HORIZONTAL_DRAG_ENABLED =
DRAG_AND_DROP_ENABLED && Settings.MINIPLAYER_HORIZONTAL_DRAG.get();
@ -202,11 +207,12 @@ public final class MiniplayerPatch {
}
}
public static final class MiniplayerHideExpandCloseAvailability implements Setting.Availability {
public static final class MiniplayerHideOverlayButtonsAvailability implements Setting.Availability {
@Override
public boolean isAvailable() {
MiniplayerType type = Settings.MINIPLAYER_TYPE.get();
return (!IS_19_20_OR_GREATER && (type == MODERN_1 || type == MODERN_3))
return type == MODERN_4
|| (!IS_19_20_OR_GREATER && (type == MODERN_1 || type == MODERN_3))
|| (!IS_19_26_OR_GREATER && type == MODERN_1
&& !Settings.MINIPLAYER_DOUBLE_TAP_ACTION.get() && !Settings.MINIPLAYER_DRAG_AND_DROP.get())
|| (IS_19_29_OR_GREATER && type == MODERN_3);
@ -220,7 +226,7 @@ public final class MiniplayerPatch {
* effectively disabling the miniplayer.
*/
public static boolean getMiniplayerOnCloseHandler(boolean original) {
return CURRENT_TYPE == ORIGINAL
return CURRENT_TYPE == DEFAULT
? original
: CURRENT_TYPE == DISABLED;
}
@ -239,7 +245,7 @@ public final class MiniplayerPatch {
* Injection point.
*/
public static boolean getModernMiniplayerOverride(boolean original) {
return CURRENT_TYPE == ORIGINAL
return CURRENT_TYPE == DEFAULT
? original
: CURRENT_TYPE.isModern();
}
@ -257,9 +263,13 @@ public final class MiniplayerPatch {
/**
* Injection point.
*/
public static void adjustMiniplayerOpacity(ImageView view) {
public static void adjustMiniplayerOpacity(View view) {
if (CURRENT_TYPE == MODERN_1) {
view.setImageAlpha(OPACITY_LEVEL);
if (view instanceof ImageView imageView) {
imageView.setImageAlpha(OPACITY_LEVEL);
} else {
Logger.printException(() -> "Unknown miniplayer overlay view. viewType: " + view.getClass().getName());
}
}
}
@ -267,7 +277,7 @@ public final class MiniplayerPatch {
* Injection point.
*/
public static boolean getModernFeatureFlagsActiveOverride(boolean original) {
if (CURRENT_TYPE == ORIGINAL) {
if (CURRENT_TYPE == DEFAULT) {
return original;
}
@ -277,8 +287,8 @@ public final class MiniplayerPatch {
/**
* Injection point.
*/
public static boolean enableMiniplayerDoubleTapAction(boolean original) {
if (CURRENT_TYPE == ORIGINAL) {
public static boolean getMiniplayerDoubleTapAction(boolean original) {
if (CURRENT_TYPE == DEFAULT) {
return original;
}
@ -288,8 +298,8 @@ public final class MiniplayerPatch {
/**
* Injection point.
*/
public static boolean enableMiniplayerDragAndDrop(boolean original) {
if (CURRENT_TYPE == ORIGINAL) {
public static boolean getMiniplayerDragAndDrop(boolean original) {
if (CURRENT_TYPE == DEFAULT) {
return original;
}
@ -300,18 +310,42 @@ public final class MiniplayerPatch {
/**
* Injection point.
*/
public static boolean setRoundedCorners(boolean original) {
if (CURRENT_TYPE.isModern()) {
public static boolean getRoundedCorners(boolean original) {
if (CURRENT_TYPE == DEFAULT) {
return original;
}
return MINIPLAYER_ROUNDED_CORNERS_ENABLED;
}
/**
* Injection point.
*/
public static boolean getHorizontalDrag(boolean original) {
if (CURRENT_TYPE == DEFAULT) {
return original;
}
return MINIPLAYER_HORIZONTAL_DRAG_ENABLED;
}
/**
* Injection point.
*/
public static boolean getMaximizeAnimation(boolean original) {
// This must be forced on if horizontal drag is enabled,
// otherwise the UI has visual glitches when maximizing the miniplayer.
if (MINIPLAYER_HORIZONTAL_DRAG_ENABLED) {
return true;
}
return original;
}
/**
* Injection point.
*/
public static int setMiniplayerDefaultSize(int original) {
public static int getMiniplayerDefaultSize(int original) {
if (CURRENT_TYPE.isModern()) {
if (MINIPLAYER_SIZE == 0) {
setMiniPlayerSize();
@ -324,29 +358,26 @@ public final class MiniplayerPatch {
return original;
}
/**
* Injection point.
*/
public static boolean setHorizontalDrag(boolean original) {
if (CURRENT_TYPE.isModern()) {
return MINIPLAYER_HORIZONTAL_DRAG_ENABLED;
}
return original;
public static void hideMiniplayerExpandClose(View view) {
Utils.hideViewByRemovingFromParentUnderCondition(HIDE_OVERLAY_BUTTONS_ENABLED, view);
}
/**
* Injection point.
*/
public static void hideMiniplayerExpandClose(ImageView view) {
Utils.hideViewByRemovingFromParentUnderCondition(HIDE_EXPAND_CLOSE_ENABLED, view);
public static void hideMiniplayerActionButton(View view) {
if (CURRENT_TYPE == MODERN_4) {
Utils.hideViewByRemovingFromParentUnderCondition(HIDE_OVERLAY_BUTTONS_ENABLED, view);
}
}
/**
* Injection point.
*/
public static void hideMiniplayerRewindForward(ImageView view) {
public static void hideMiniplayerRewindForward(View view) {
Utils.hideViewByRemovingFromParentUnderCondition(HIDE_REWIND_FORWARD_ENABLED, view);
}

View File

@ -170,13 +170,13 @@ public class Settings extends BaseSettings {
public static final StringSetting CUSTOM_FILTER_STRINGS = new StringSetting("revanced_custom_filter_strings", "", true, parent(CUSTOM_FILTER));
// PreferenceScreen: General - Miniplayer
public static final EnumSetting<MiniplayerType> MINIPLAYER_TYPE = new EnumSetting<>("revanced_miniplayer_type", MiniplayerType.ORIGINAL, true);
public static final EnumSetting<MiniplayerType> MINIPLAYER_TYPE = new EnumSetting<>("revanced_miniplayer_type", MiniplayerType.DEFAULT, true);
private static final Setting.Availability MINIPLAYER_ANY_MODERN = MINIPLAYER_TYPE.availability(MODERN_1, MODERN_2, MODERN_3, MODERN_4);
public static final BooleanSetting MINIPLAYER_DOUBLE_TAP_ACTION = new BooleanSetting("revanced_miniplayer_double_tap_action", TRUE, true, MINIPLAYER_ANY_MODERN);
public static final BooleanSetting MINIPLAYER_DRAG_AND_DROP = new BooleanSetting("revanced_miniplayer_drag_and_drop", TRUE, true, MINIPLAYER_ANY_MODERN);
public static final BooleanSetting MINIPLAYER_HORIZONTAL_DRAG = new BooleanSetting("revanced_miniplayer_horizontal_drag", FALSE, true, new MiniplayerPatch.MiniplayerHorizontalDragAvailability());
public static final BooleanSetting MINIPLAYER_HIDE_EXPAND_CLOSE = new BooleanSetting("revanced_miniplayer_hide_expand_close", FALSE, true, new MiniplayerPatch.MiniplayerHideExpandCloseAvailability());
public static final BooleanSetting MINIPLAYER_HIDE_SUBTEXT = new BooleanSetting("revanced_miniplayer_hide_subtext", FALSE, true, MINIPLAYER_TYPE.availability(MODERN_1, MODERN_3));
public static final BooleanSetting MINIPLAYER_HIDE_OVERLAY_BUTTONS = new BooleanSetting("revanced_miniplayer_hide_overlay_buttons", FALSE, true, new MiniplayerPatch.MiniplayerHideOverlayButtonsAvailability());
public static final BooleanSetting MINIPLAYER_HIDE_SUBTEXT = new BooleanSetting("revanced_miniplayer_hide_subtext", FALSE, true, MINIPLAYER_TYPE.availability(MODERN_1, MODERN_3, MODERN_4));
public static final BooleanSetting MINIPLAYER_HIDE_REWIND_FORWARD = new BooleanSetting("revanced_miniplayer_hide_rewind_forward", TRUE, true, MINIPLAYER_TYPE.availability(MODERN_1));
public static final BooleanSetting MINIPLAYER_ROUNDED_CORNERS = new BooleanSetting("revanced_miniplayer_rounded_corners", TRUE, true, MINIPLAYER_ANY_MODERN);
public static final IntegerSetting MINIPLAYER_WIDTH_DIP = new IntegerSetting("revanced_miniplayer_width_dip", 192, true, MINIPLAYER_ANY_MODERN);

View File

@ -2,8 +2,6 @@ package app.revanced.extension.youtube.settings.preference;
import static app.revanced.extension.shared.utils.StringRef.str;
import static app.revanced.extension.shared.utils.Utils.isSDKAbove;
import static app.revanced.extension.youtube.patches.general.MiniplayerPatch.MiniplayerType.MODERN_1;
import static app.revanced.extension.youtube.patches.general.MiniplayerPatch.MiniplayerType.MODERN_3;
import static app.revanced.extension.youtube.utils.ExtendedUtils.isSpoofingToLessThan;
import android.preference.Preference;
@ -11,7 +9,6 @@ import android.preference.SwitchPreference;
import app.revanced.extension.shared.settings.Setting;
import app.revanced.extension.youtube.patches.general.LayoutSwitchPatch;
import app.revanced.extension.youtube.patches.general.MiniplayerPatch;
import app.revanced.extension.youtube.patches.utils.PatchStatus;
import app.revanced.extension.youtube.patches.utils.ReturnYouTubeDislikePatch;
import app.revanced.extension.youtube.returnyoutubedislike.ReturnYouTubeDislike;
@ -48,7 +45,6 @@ public class ReVancedSettingsPreference extends ReVancedPreferenceFragment {
AmbientModePreferenceLinks();
ExternalDownloaderPreferenceLinks();
FullScreenPanelPreferenceLinks();
MiniPlayerPreferenceLinks();
NavigationPreferenceLinks();
RYDPreferenceLinks();
SeekBarPreferenceLinks();
@ -140,22 +136,6 @@ public class ReVancedSettingsPreference extends ReVancedPreferenceFragment {
);
}
/**
* Enable/Disable Preference related to Miniplayer settings
*/
private static void MiniPlayerPreferenceLinks() {
final MiniplayerPatch.MiniplayerType CURRENT_TYPE = Settings.MINIPLAYER_TYPE.get();
final boolean available =
(CURRENT_TYPE == MODERN_1 || CURRENT_TYPE == MODERN_3) &&
!Settings.MINIPLAYER_DOUBLE_TAP_ACTION.get() &&
!Settings.MINIPLAYER_DRAG_AND_DROP.get();
enableDisablePreferences(
!available,
Settings.MINIPLAYER_HIDE_EXPAND_CLOSE
);
}
/**
* Enable/Disable Preference related to Navigation settings
*/

View File

@ -7,6 +7,7 @@ import app.revanced.patches.youtube.utils.resourceid.miniplayerMaxSize
import app.revanced.patches.youtube.utils.resourceid.modernMiniPlayerClose
import app.revanced.patches.youtube.utils.resourceid.modernMiniPlayerExpand
import app.revanced.patches.youtube.utils.resourceid.modernMiniPlayerForwardButton
import app.revanced.patches.youtube.utils.resourceid.modernMiniPlayerOverlayActionButton
import app.revanced.patches.youtube.utils.resourceid.modernMiniPlayerRewindButton
import app.revanced.patches.youtube.utils.resourceid.scrimOverlay
import app.revanced.patches.youtube.utils.resourceid.ytOutlinePictureInPictureWhite
@ -15,6 +16,8 @@ import app.revanced.util.or
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
// region legacy miniplayer
internal val miniplayerDimensionsCalculatorParentFingerprint = legacyFingerprint(
name = "miniplayerDimensionsCalculatorParentFingerprint",
returnType = "V",
@ -23,6 +26,68 @@ internal val miniplayerDimensionsCalculatorParentFingerprint = legacyFingerprint
literals = listOf(floatyBarTopMargin),
)
/**
* Matches using the class found in [miniplayerDimensionsCalculatorParentFingerprint].
*/
internal val miniplayerOverrideNoContextFingerprint = legacyFingerprint(
name = "miniplayerOverrideNoContextFingerprint",
accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL,
returnType = "Z",
opcodes = listOf(Opcode.IGET_BOOLEAN), // anchor to insert the instruction
)
internal val miniplayerOverrideFingerprint = legacyFingerprint(
name = "miniplayerOverrideFingerprint",
returnType = "L",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
strings = listOf("appName")
)
internal val miniplayerResponseModelSizeCheckFingerprint = legacyFingerprint(
name = "miniplayerResponseModelSizeCheckFingerprint",
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,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT,
Opcode.IF_NEZ,
)
)
// endregion
// region modern miniplayer
internal const val MINIPLAYER_MODERN_FEATURE_KEY = 45622882L
// In later targets this feature flag does nothing and is dead code.
internal const val MINIPLAYER_MODERN_FEATURE_LEGACY_KEY = 45630429L
internal const val MINIPLAYER_DOUBLE_TAP_FEATURE_KEY = 45628823L
internal const val MINIPLAYER_DRAG_DROP_FEATURE_KEY = 45628752L
internal const val MINIPLAYER_HORIZONTAL_DRAG_FEATURE_KEY = 45658112L
internal const val MINIPLAYER_ROUNDED_CORNERS_FEATURE_KEY = 45652224L
internal const val MINIPLAYER_INITIAL_SIZE_FEATURE_KEY = 45640023L
internal const val MINIPLAYER_DISABLED_FEATURE_KEY = 45657015L
internal const val MINIPLAYER_ANIMATED_EXPAND_FEATURE_KEY = 45644360L
internal val miniplayerModernConstructorFingerprint = legacyFingerprint(
name = "miniplayerModernConstructorFingerprint",
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
parameters = listOf("L"),
literals = listOf(45623000L),
)
internal val miniplayerModernViewParentFingerprint = legacyFingerprint(
name = "miniplayerModernViewParentFingerprint",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
returnType = "Ljava/lang/String;",
parameters = listOf(),
strings = listOf("player_overlay_modern_mini_player_controls")
)
/**
* Matches using the class found in [miniplayerModernViewParentFingerprint].
*/
@ -38,43 +103,18 @@ internal val miniplayerModernAddViewListenerFingerprint = legacyFingerprint(
*/
internal val miniplayerModernCloseButtonFingerprint = legacyFingerprint(
name = "miniplayerModernCloseButtonFingerprint",
returnType = "Landroid/widget/ImageView;",
returnType = "L",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = emptyList(),
literals = listOf(modernMiniPlayerClose),
)
internal const val MINIPLAYER_MODERN_FEATURE_KEY = 45622882L
// In later targets this feature flag does nothing and is dead code.
internal const val MINIPLAYER_MODERN_FEATURE_LEGACY_KEY = 45630429L
internal const val MINIPLAYER_DOUBLE_TAP_FEATURE_KEY = 45628823L
internal const val MINIPLAYER_DRAG_DROP_FEATURE_KEY = 45628752L
internal const val MINIPLAYER_HORIZONTAL_DRAG_FEATURE_KEY = 45658112L
internal const val MINIPLAYER_ROUNDED_CORNERS_FEATURE_KEY = 45652224L
internal const val MINIPLAYER_INITIAL_SIZE_FEATURE_KEY = 45640023L
internal const val MINIPLAYER_DISABLED_FEATURE_KEY = 45657015L
internal val miniplayerModernConstructorFingerprint = legacyFingerprint(
name = "miniplayerModernConstructorFingerprint",
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
parameters = listOf("L"),
literals = listOf(45623000L),
)
internal val miniplayerOnCloseHandlerFingerprint = legacyFingerprint(
name = "miniplayerOnCloseHandlerFingerprint",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
returnType = "Z",
literals = listOf(MINIPLAYER_DISABLED_FEATURE_KEY),
)
/**
* Matches using the class found in [miniplayerModernViewParentFingerprint].
*/
internal val miniplayerModernExpandButtonFingerprint = legacyFingerprint(
name = "miniplayerModernExpandButtonFingerprint",
returnType = "Landroid/widget/ImageView;",
returnType = "L",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = emptyList(),
literals = listOf(modernMiniPlayerExpand),
@ -96,7 +136,7 @@ internal val miniplayerModernExpandCloseDrawablesFingerprint = legacyFingerprint
*/
internal val miniplayerModernForwardButtonFingerprint = legacyFingerprint(
name = "miniplayerModernForwardButtonFingerprint",
returnType = "Landroid/widget/ImageView;",
returnType = "L",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = emptyList(),
literals = listOf(modernMiniPlayerForwardButton),
@ -107,7 +147,6 @@ internal val miniplayerModernForwardButtonFingerprint = legacyFingerprint(
*/
internal val miniplayerModernOverlayViewFingerprint = legacyFingerprint(
name = "miniplayerModernOverlayViewFingerprint",
returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = emptyList(),
literals = listOf(scrimOverlay),
@ -118,18 +157,21 @@ internal val miniplayerModernOverlayViewFingerprint = legacyFingerprint(
*/
internal val miniplayerModernRewindButtonFingerprint = legacyFingerprint(
name = "miniplayerModernRewindButtonFingerprint",
returnType = "Landroid/widget/ImageView;",
returnType = "L",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = emptyList(),
literals = listOf(modernMiniPlayerRewindButton),
)
internal val miniplayerModernViewParentFingerprint = legacyFingerprint(
name = "miniplayerModernViewParentFingerprint",
/**
* Matches using the class found in [miniplayerModernViewParentFingerprint].
*/
internal val miniplayerModernActionButtonFingerprint = legacyFingerprint(
name = "miniplayerModernActionButtonFingerprint",
returnType = "L",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
returnType = "Ljava/lang/String;",
parameters = listOf(),
strings = listOf("player_overlay_modern_mini_player_controls")
parameters = emptyList(),
literals = listOf(modernMiniPlayerOverlayActionButton),
)
internal val miniplayerMinimumSizeFingerprint = legacyFingerprint(
@ -138,33 +180,11 @@ internal val miniplayerMinimumSizeFingerprint = legacyFingerprint(
literals = listOf(192L, 128L, miniplayerMaxSize),
)
internal val miniplayerOverrideFingerprint = legacyFingerprint(
name = "miniplayerOverrideFingerprint",
returnType = "L",
internal val miniplayerOnCloseHandlerFingerprint = legacyFingerprint(
name = "miniplayerOnCloseHandlerFingerprint",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
strings = listOf("appName")
)
internal val miniplayerOverrideNoContextFingerprint = legacyFingerprint(
name = "miniplayerOverrideNoContextFingerprint",
accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL,
returnType = "Z",
opcodes = listOf(Opcode.IGET_BOOLEAN), // anchor to insert the instruction
)
internal val miniplayerResponseModelSizeCheckFingerprint = legacyFingerprint(
name = "miniplayerResponseModelSizeCheckFingerprint",
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,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT,
Opcode.IF_NEZ,
)
literals = listOf(MINIPLAYER_DISABLED_FEATURE_KEY),
)
internal const val YOUTUBE_PLAYER_OVERLAYS_LAYOUT_CLASS_NAME =

View File

@ -11,16 +11,19 @@ import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PAC
import app.revanced.patches.youtube.utils.extension.Constants.GENERAL_PATH
import app.revanced.patches.youtube.utils.patch.PatchList.MINIPLAYER
import app.revanced.patches.youtube.utils.playservice.is_19_15_or_greater
import app.revanced.patches.youtube.utils.playservice.is_19_17_or_greater
import app.revanced.patches.youtube.utils.playservice.is_19_23_or_greater
import app.revanced.patches.youtube.utils.playservice.is_19_25_or_greater
import app.revanced.patches.youtube.utils.playservice.is_19_26_or_greater
import app.revanced.patches.youtube.utils.playservice.is_19_29_or_greater
import app.revanced.patches.youtube.utils.playservice.is_19_36_or_greater
import app.revanced.patches.youtube.utils.playservice.is_19_43_or_greater
import app.revanced.patches.youtube.utils.playservice.is_20_03_or_greater
import app.revanced.patches.youtube.utils.playservice.versionCheckPatch
import app.revanced.patches.youtube.utils.resourceid.modernMiniPlayerClose
import app.revanced.patches.youtube.utils.resourceid.modernMiniPlayerExpand
import app.revanced.patches.youtube.utils.resourceid.modernMiniPlayerForwardButton
import app.revanced.patches.youtube.utils.resourceid.modernMiniPlayerOverlayActionButton
import app.revanced.patches.youtube.utils.resourceid.modernMiniPlayerRewindButton
import app.revanced.patches.youtube.utils.resourceid.scrimOverlay
import app.revanced.patches.youtube.utils.resourceid.sharedResourceIdPatch
@ -36,6 +39,7 @@ import app.revanced.util.fingerprint.methodOrThrow
import app.revanced.util.fingerprint.mutableClassOrThrow
import app.revanced.util.getReference
import app.revanced.util.getWalkerMethod
import app.revanced.util.indexOfFirstInstruction
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstLiteralInstructionOrThrow
import com.android.tools.smali.dexlib2.AccessFlags
@ -116,25 +120,6 @@ val miniplayerPatch = bytecodePatch(
)
}
fun MutableMethod.hookInflatedView(
literalValue: Long,
hookedClassType: String,
extensionMethodName: String,
) {
val imageViewIndex = indexOfFirstInstructionOrThrow(
indexOfFirstLiteralInstructionOrThrow(literalValue)
) {
opcode == Opcode.CHECK_CAST &&
getReference<TypeReference>()?.type == hookedClassType
}
val register = getInstruction<OneRegisterInstruction>(imageViewIndex).registerA
addInstruction(
imageViewIndex + 1,
"invoke-static { v$register }, $extensionMethodName"
)
}
// 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 = !is_19_15_or_greater
@ -212,7 +197,7 @@ val miniplayerPatch = bytecodePatch(
if (is_19_23_or_greater) {
miniplayerModernConstructorFingerprint.injectLiteralInstructionBooleanCall(
MINIPLAYER_DRAG_DROP_FEATURE_KEY,
"$EXTENSION_CLASS_DESCRIPTOR->enableMiniplayerDragAndDrop(Z)Z"
"$EXTENSION_CLASS_DESCRIPTOR->getMiniplayerDragAndDrop(Z)Z"
)
settingArray += "SETTINGS: MINIPLAYER_DRAG_AND_DROP"
}
@ -230,7 +215,7 @@ val miniplayerPatch = bytecodePatch(
miniplayerModernConstructorFingerprint.injectLiteralInstructionBooleanCall(
MINIPLAYER_DOUBLE_TAP_FEATURE_KEY,
"$EXTENSION_CLASS_DESCRIPTOR->enableMiniplayerDoubleTapAction(Z)Z"
"$EXTENSION_CLASS_DESCRIPTOR->getMiniplayerDoubleTapAction(Z)Z"
)
if (!is_19_29_or_greater) {
@ -244,13 +229,11 @@ val miniplayerPatch = bytecodePatch(
MINIPLAYER_INITIAL_SIZE_FEATURE_KEY,
)
val targetIndex = indexOfFirstInstructionOrThrow(literalIndex, Opcode.LONG_TO_INT)
val register = getInstruction<OneRegisterInstruction>(targetIndex).registerA
addInstructions(
targetIndex + 1,
"""
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->setMiniplayerDefaultSize(I)I
targetIndex + 1, """
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->getMiniplayerDefaultSize(I)I
move-result v$register
""",
)
@ -270,15 +253,17 @@ val miniplayerPatch = bytecodePatch(
replaceInstruction(index, "const/16 v$register, 170")
}
settingArray += "SETTINGS: MINIPLAYER_OVERLAY_BUTTONS_19_26"
settingArray += "SETTINGS: MINIPLAYER_WIDTH_DIP"
} else {
settingArray += "SETTINGS: MINIPLAYER_OVERLAY_BUTTONS_19_25"
settingArray += "SETTINGS: MINIPLAYER_REWIND_FORWARD"
}
if (is_19_36_or_greater) {
miniplayerModernConstructorFingerprint.injectLiteralInstructionBooleanCall(
MINIPLAYER_ROUNDED_CORNERS_FEATURE_KEY,
"$EXTENSION_CLASS_DESCRIPTOR->setRoundedCorners(Z)Z"
"$EXTENSION_CLASS_DESCRIPTOR->getRoundedCorners(Z)Z"
)
settingArray += "SETTINGS: MINIPLAYER_ROUNDED_CORNERS"
@ -292,13 +277,23 @@ val miniplayerPatch = bytecodePatch(
miniplayerModernConstructorFingerprint.injectLiteralInstructionBooleanCall(
MINIPLAYER_HORIZONTAL_DRAG_FEATURE_KEY,
"$EXTENSION_CLASS_DESCRIPTOR->setHorizontalDrag(Z)Z"
"$EXTENSION_CLASS_DESCRIPTOR->getHorizontalDrag(Z)Z"
)
miniplayerModernConstructorFingerprint.injectLiteralInstructionBooleanCall(
MINIPLAYER_ANIMATED_EXPAND_FEATURE_KEY,
"$EXTENSION_CLASS_DESCRIPTOR->getMaximizeAnimation(Z)Z"
)
settingArray += "SETTINGS: MINIPLAYER_HORIZONTAL_DRAG"
settingArray += "SETTINGS: MINIPLAYER_TYPE_19_43"
}
settingArray += if (is_20_03_or_greater) {
"SETTINGS: MINIPLAYER_TYPE_20_03"
} else if (is_19_43_or_greater) {
"SETTINGS: MINIPLAYER_TYPE_19_43"
} else {
settingArray += "SETTINGS: MINIPLAYER_TYPE_19_16"
"SETTINGS: MINIPLAYER_TYPE_19_16"
}
// endregion
@ -339,6 +334,11 @@ val miniplayerPatch = bytecodePatch(
modernMiniPlayerClose,
"hideMiniplayerExpandClose"
),
Triple(
miniplayerModernActionButtonFingerprint,
modernMiniPlayerOverlayActionButton,
"hideMiniplayerActionButton"
),
Triple(
miniplayerModernRewindButtonFingerprint,
modernMiniPlayerRewindButton,
@ -355,12 +355,25 @@ val miniplayerPatch = bytecodePatch(
"adjustMiniplayerOpacity"
)
).forEach { (fingerprint, literalValue, methodName) ->
fingerprint.methodOrThrow(miniplayerModernViewParentFingerprint).hookInflatedView(
literalValue,
"Landroid/widget/ImageView;",
"$EXTENSION_CLASS_DESCRIPTOR->$methodName(Landroid/widget/ImageView;)V"
fingerprint.methodOrThrow(miniplayerModernViewParentFingerprint).apply {
val literalIndex = indexOfFirstLiteralInstructionOrThrow(literalValue)
val checkCastIndex = indexOfFirstInstruction(literalIndex) {
opcode == Opcode.CHECK_CAST &&
getReference<TypeReference>()?.type == "Landroid/widget/ImageView;"
}
val viewIndex = if (checkCastIndex >= 0) {
checkCastIndex
} else {
indexOfFirstInstructionOrThrow(literalIndex, Opcode.MOVE_RESULT_OBJECT)
}
val viewRegister = getInstruction<OneRegisterInstruction>(viewIndex).registerA
addInstruction(
viewIndex + 1,
"invoke-static { v$viewRegister }, $EXTENSION_CLASS_DESCRIPTOR->$methodName(Landroid/view/View;)V"
)
}
}
miniplayerModernAddViewListenerFingerprint.methodOrThrow(
miniplayerModernViewParentFingerprint
@ -374,9 +387,11 @@ val miniplayerPatch = bytecodePatch(
// 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 extension.
// Problem is fixed in 19.21+
//
// NOTE: Modern 2 uses the same video UI as the regular player except resized to smaller.
// This patch code could be used to hide other player overlays that do not use Litho.
if (!is_19_17_or_greater) {
youTubePlayerOverlaysLayoutFingerprint.matchOrThrow().let {
it.method.apply {
it.classDef.methods.add(
@ -409,6 +424,7 @@ val miniplayerPatch = bytecodePatch(
)
}
}
}
// endregion

View File

@ -45,6 +45,8 @@ internal val nextGenWatchLayoutFingerprint = legacyFingerprint(
}
)
internal const val RESTORE_SLIDE_TO_SEEK_FEATURE_FLAG = 45411329L
/**
* This value restores the 'Slide to seek' behavior.
* Deprecated in YouTube v19.18.41+.
@ -54,7 +56,7 @@ internal val restoreSlideToSeekBehaviorFingerprint = legacyFingerprint(
returnType = "Z",
parameters = emptyList(),
opcodes = listOf(Opcode.MOVE_RESULT),
literals = listOf(45411329L),
literals = listOf(RESTORE_SLIDE_TO_SEEK_FEATURE_FLAG),
)
internal val slideToSeekMotionEventFingerprint = legacyFingerprint(
@ -72,6 +74,8 @@ internal val slideToSeekMotionEventFingerprint = legacyFingerprint(
)
)
internal const val SPEED_OVERLAY_FEATURE_FLAG = 45411330L
/**
* This value disables 'Playing at 2x speed' while holding down.
* Deprecated in YouTube v19.18.41+.
@ -81,7 +85,7 @@ internal val speedOverlayFingerprint = legacyFingerprint(
returnType = "Z",
parameters = emptyList(),
opcodes = listOf(Opcode.MOVE_RESULT),
literals = listOf(45411330L),
literals = listOf(SPEED_OVERLAY_FEATURE_FLAG),
)
/**
@ -152,6 +156,13 @@ internal val filmStripOverlayPreviewFingerprint = legacyFingerprint(
)
)
internal const val FILM_STRIP_OVERLAY_V2_FEATURE_FLAG = 45420198L
internal val filmStripOverlayConfigV2Fingerprint = legacyFingerprint(
name = "filmStripOverlayConfigV2Fingerprint",
literals = listOf(FILM_STRIP_OVERLAY_V2_FEATURE_FLAG),
)
internal val infoCardsIncognitoFingerprint = legacyFingerprint(
name = "infoCardsIncognitoFingerprint",
returnType = "Ljava/lang/Boolean;",

View File

@ -24,6 +24,8 @@ import app.revanced.patches.youtube.utils.fix.suggestedvideoendscreen.suggestedV
import app.revanced.patches.youtube.utils.patch.PatchList.PLAYER_COMPONENTS
import app.revanced.patches.youtube.utils.playertype.playerTypeHookPatch
import app.revanced.patches.youtube.utils.playservice.is_20_02_or_greater
import app.revanced.patches.youtube.utils.playservice.is_20_03_or_greater
import app.revanced.patches.youtube.utils.playservice.is_20_05_or_greater
import app.revanced.patches.youtube.utils.playservice.versionCheckPatch
import app.revanced.patches.youtube.utils.resourceid.darkBackground
import app.revanced.patches.youtube.utils.resourceid.fadeDurationFast
@ -91,8 +93,8 @@ private val speedOverlayPatch = bytecodePatch(
// region patch for Disable speed overlay (Enable slide to seek)
mapOf(
restoreSlideToSeekBehaviorFingerprint to 45411329L,
speedOverlayFingerprint to 45411330L
restoreSlideToSeekBehaviorFingerprint to RESTORE_SLIDE_TO_SEEK_FEATURE_FLAG,
speedOverlayFingerprint to SPEED_OVERLAY_FEATURE_FLAG
).forEach { (fingerprint, literal) ->
fingerprint.injectLiteralInstructionBooleanCall(
literal,
@ -237,6 +239,8 @@ private val speedOverlayPatch = bytecodePatch(
)
}
// Removed in YouTube 20.03+
if (!is_20_03_or_greater) {
speedOverlayTextValueFingerprint.matchOrThrow().let {
it.method.apply {
val targetIndex = it.patternMatch!!.startIndex
@ -251,6 +255,7 @@ private val speedOverlayPatch = bytecodePatch(
)
}
}
}
// endregion
@ -509,6 +514,8 @@ val playerComponentsPatch = bytecodePatch(
fingerprint.methodOrThrow(filmStripOverlayParentFingerprint).hookFilmstripOverlay()
}
// Removed in YouTube 20.05+
if (!is_20_05_or_greater) {
youtubeControlsOverlayFingerprint.methodOrThrow().apply {
val constIndex = indexOfFirstLiteralInstructionOrThrow(fadeDurationFast)
val constRegister = getInstruction<OneRegisterInstruction>(constIndex).registerA
@ -536,6 +543,14 @@ val playerComponentsPatch = bytecodePatch(
)
removeInstruction(insertIndex)
}
} else {
// This is a new film strip overlay added to YouTube 20.05+
// Disabling this flag is not related to the operation of the patch.
filmStripOverlayConfigV2Fingerprint.injectLiteralInstructionBooleanCall(
FILM_STRIP_OVERLAY_V2_FEATURE_FLAG,
"0x0"
)
}
// endregion
@ -571,6 +586,7 @@ val playerComponentsPatch = bytecodePatch(
)
}
// Removed in YouTube 20.02+
if (!is_20_02_or_greater) {
youtubeControlsOverlayFingerprint.methodOrThrow().apply {
val insertIndex =

View File

@ -1,7 +1,9 @@
package app.revanced.patches.youtube.player.seekbar
import app.revanced.patches.youtube.utils.resourceid.inlineTimeBarLiveSeekAbleRange
import app.revanced.patches.youtube.utils.resourceid.reelTimeBarPlayedColor
import app.revanced.patches.youtube.utils.resourceid.ytStaticBrandRed
import app.revanced.patches.youtube.utils.resourceid.ytTextSecondary
import app.revanced.patches.youtube.utils.resourceid.ytYoutubeMagenta
import app.revanced.util.containsLiteralInstruction
import app.revanced.util.fingerprint.legacyFingerprint
@ -35,11 +37,18 @@ internal val playerSeekbarGradientConfigFingerprint = legacyFingerprint(
literals = listOf(PLAYER_SEEKBAR_GRADIENT_FEATURE_FLAG),
)
internal val playerSeekbarHandleColorFingerprint = legacyFingerprint(
name = "playerSeekbarHandleColorFingerprint",
internal val playerSeekbarHandleColorPrimaryFingerprint = legacyFingerprint(
name = "playerSeekbarHandleColorPrimaryFingerprint",
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
parameters = listOf("Landroid/content/Context;"),
literals = listOf(ytStaticBrandRed),
literals = listOf(ytTextSecondary, ytStaticBrandRed),
)
internal val playerSeekbarHandleColorSecondaryFingerprint = legacyFingerprint(
name = "playerSeekbarHandleColorSecondaryFingerprint",
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
parameters = listOf("Landroid/content/Context;"),
literals = listOf(inlineTimeBarLiveSeekAbleRange, ytStaticBrandRed),
)
internal val watchHistoryMenuUseProgressDrawableFingerprint = legacyFingerprint(

View File

@ -265,8 +265,11 @@ val seekbarComponentsPatch = bytecodePatch(
"$EXTENSION_SEEKBAR_COLOR_CLASS_DESCRIPTOR->playerSeekbarGradientEnabled(Z)Z"
)
playerSeekbarHandleColorFingerprint.methodOrThrow().apply {
addColorChangeInstructions(ytStaticBrandRed, "getVideoPlayerSeekbarColorAccent")
arrayOf(
playerSeekbarHandleColorPrimaryFingerprint,
playerSeekbarHandleColorSecondaryFingerprint
).forEach {
it.methodOrThrow().addColorChangeInstructions(ytStaticBrandRed, "getVideoPlayerSeekbarColorAccent")
}
// If hiding feed seekbar thumbnails, then turn off the cairo gradient
// of the watch history menu items as they use the same gradient as the

View File

@ -95,7 +95,6 @@ internal val playerButtonsResourcesFingerprint = legacyFingerprint(
internal val playerButtonsVisibilityFingerprint = legacyFingerprint(
name = "playerButtonsVisibilityFingerprint",
returnType = "V",
accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL,
opcodes = listOf(
Opcode.IGET_OBJECT,
Opcode.IGET_OBJECT,

View File

@ -16,6 +16,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
import com.android.tools.smali.dexlib2.util.MethodUtil
private lateinit var engagementPanelBuilderMethod: MutableMethod
private lateinit var hideEngagementPanelMethod: MutableMethod
private var showEngagementPanelMethods = mutableListOf<MutableMethod>()
@ -26,8 +27,10 @@ val engagementPanelHookPatch = bytecodePatch(
execute {
engagementPanelBuilderFingerprint.matchOrThrow().let {
engagementPanelBuilderMethod = it.method
it.classDef.methods.filter { method ->
method.indexOfEngagementPanelBuilderInstruction(it.method) >= 0
method.indexOfEngagementPanelBuilderInstruction() >= 0
}.forEach { method ->
showEngagementPanelMethods.add(method)
}
@ -38,11 +41,11 @@ val engagementPanelHookPatch = bytecodePatch(
}
}
private fun Method.indexOfEngagementPanelBuilderInstruction(targetMethod: MutableMethod) =
private fun Method.indexOfEngagementPanelBuilderInstruction() =
indexOfFirstInstructionReversed {
opcode == Opcode.INVOKE_DIRECT &&
MethodUtil.methodSignaturesMatch(
targetMethod,
engagementPanelBuilderMethod,
getReference<MethodReference>()!!
)
}
@ -50,7 +53,7 @@ private fun Method.indexOfEngagementPanelBuilderInstruction(targetMethod: Mutabl
internal fun hookEngagementPanelState(classDescriptor: String) {
showEngagementPanelMethods.forEach { method ->
method.apply {
val index = indexOfEngagementPanelBuilderInstruction(this)
val index = indexOfEngagementPanelBuilderInstruction()
val register = getInstruction<OneRegisterInstruction>(index + 1).registerA
addInstruction(

View File

@ -55,6 +55,10 @@ var is_19_49_or_greater = false
private set
var is_20_02_or_greater = false
private set
var is_20_03_or_greater = false
private set
var is_20_05_or_greater = false
private set
val versionCheckPatch = resourcePatch(
description = "versionCheckPatch",
@ -95,5 +99,7 @@ val versionCheckPatch = resourcePatch(
is_19_46_or_greater = 244705000 <= playStoreServicesVersion
is_19_49_or_greater = 245005000 <= playStoreServicesVersion
is_20_02_or_greater = 250299000 <= playStoreServicesVersion
is_20_03_or_greater = 250405000 <= playStoreServicesVersion
is_20_05_or_greater = 250605000 <= playStoreServicesVersion
}
}

View File

@ -115,6 +115,8 @@ var imageOnlyTab = -1L
private set
var inlineTimeBarColorizedBarPlayedColorDark = -1L
private set
var inlineTimeBarLiveSeekAbleRange = -1L
private set
var inlineTimeBarPlayedNotHighlightedColor = -1L
private set
var insetOverlayViewLayout = -1L
@ -135,6 +137,8 @@ var modernMiniPlayerExpand = -1L
private set
var modernMiniPlayerForwardButton = -1L
private set
var modernMiniPlayerOverlayActionButton = -1L
private set
var modernMiniPlayerRewindButton = -1L
private set
var musicAppDeeplinkButtonView = -1L
@ -241,6 +245,8 @@ var ytOutlineXWhite = -1L
private set
var ytPremiumWordMarkHeader = -1L
private set
var ytTextSecondary = -1L
private set
var ytStaticBrandRed = -1L
private set
var ytWordMarkHeader = -1L
@ -454,6 +460,10 @@ internal val sharedResourceIdPatch = resourcePatch(
COLOR,
"inline_time_bar_colorized_bar_played_color_dark"
]
inlineTimeBarLiveSeekAbleRange = resourceMappings[
COLOR,
"inline_time_bar_live_seekable_range"
]
inlineTimeBarPlayedNotHighlightedColor = resourceMappings[
COLOR,
"inline_time_bar_played_not_highlighted_color"
@ -494,6 +504,10 @@ internal val sharedResourceIdPatch = resourcePatch(
ID,
"modern_miniplayer_forward_button"
]
modernMiniPlayerOverlayActionButton = resourceMappings[
ID,
"modern_miniplayer_overlay_action_button"
]
modernMiniPlayerRewindButton = resourceMappings[
ID,
"modern_miniplayer_rewind_button"
@ -706,6 +720,10 @@ internal val sharedResourceIdPatch = resourcePatch(
ATTR,
"ytPremiumWordmarkHeader"
]
ytTextSecondary = resourceMappings[
ATTR,
"ytTextSecondary",
]
ytStaticBrandRed = resourceMappings[
ATTR,
"ytStaticBrandRed",

View File

@ -303,6 +303,26 @@
<item>VI</item>
<item>ZH</item>
</string-array>
<string-array name="revanced_miniplayer_type_20_03_entries">
<item>@string/revanced_miniplayer_type_entry_0</item>
<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>
<item>@string/revanced_miniplayer_type_entry_7</item>
</string-array>
<string-array name="revanced_miniplayer_type_20_03_entry_values">
<item>DISABLED</item>
<item>DEFAULT</item>
<item>MINIMAL</item>
<item>TABLET</item>
<item>MODERN_1</item>
<item>MODERN_2</item>
<item>MODERN_3</item>
<item>MODERN_4</item>
</string-array>
<string-array name="revanced_miniplayer_type_19_43_entries">
<item>@string/revanced_miniplayer_type_entry_0</item>
<item>@string/revanced_miniplayer_type_entry_1</item>
@ -314,7 +334,7 @@
</string-array>
<string-array name="revanced_miniplayer_type_19_43_entry_values">
<item>DISABLED</item>
<item>ORIGINAL</item>
<item>DEFAULT</item>
<item>MINIMAL</item>
<item>TABLET</item>
<item>MODERN_1</item>
@ -330,7 +350,7 @@
<item>@string/revanced_miniplayer_type_entry_6</item>
</string-array>
<string-array name="revanced_miniplayer_type_19_16_entry_values">
<item>ORIGINAL</item>
<item>DEFAULT</item>
<item>MINIMAL</item>
<item>TABLET</item>
<item>MODERN_1</item>
@ -343,7 +363,7 @@
<item>@string/revanced_miniplayer_type_entry_3</item>
</string-array>
<string-array name="revanced_miniplayer_type_19_14_entry_values">
<item>ORIGINAL</item>
<item>DEFAULT</item>
<item>MINIMAL</item>
<item>TABLET</item>
</string-array>

View File

@ -539,12 +539,13 @@ To hide the <b>Get YouTube Premium</b> menu, you can only use <b>Get YouTube Pre
<string name="revanced_miniplayer_type_title">Miniplayer type</string>
<string name="revanced_miniplayer_type_entry_0">Disabled</string>
<string name="revanced_miniplayer_type_entry_1">Original</string>
<string name="revanced_miniplayer_type_entry_1">Default</string>
<string name="revanced_miniplayer_type_entry_2">Minimal</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_type_entry_7">Modern 4</string>
<string name="revanced_miniplayer_rounded_corners_title">Enable rounded corners</string>
<string name="revanced_miniplayer_rounded_corners_summary_on">Corners are rounded.</string>
<string name="revanced_miniplayer_rounded_corners_summary_off">Corners are square.</string>
@ -564,20 +565,20 @@ Miniplayer can be dragged to any corner of the screen."</string>
Miniplayer can be dragged off-screen to the left or right."</string>
<string name="revanced_miniplayer_horizontal_drag_summary_off">Horizontal drag gesture disabled.</string>
<string name="revanced_miniplayer_hide_expand_close_title">Hide close button</string>
<string name="revanced_miniplayer_hide_expand_close_summary_on">Close button is hidden.</string>
<string name="revanced_miniplayer_hide_expand_close_summary_off">Close button is shown.</string>
<string name="revanced_miniplayer_hide_expand_close_legacy_title">Hide expand and close buttons</string>
<string name="revanced_miniplayer_hide_expand_close_legacy_summary_on">"Buttons are hidden.
<string name="revanced_miniplayer_hide_overlay_buttons_title">Hide overlay buttons</string>
<string name="revanced_miniplayer_hide_overlay_buttons_summary_on">Overlay buttons are hidden.</string>
<string name="revanced_miniplayer_hide_overlay_buttons_summary_off">Overlay buttons are shown.</string>
<string name="revanced_miniplayer_hide_overlay_buttons_legacy_title">Hide expand and close buttons</string>
<string name="revanced_miniplayer_hide_overlay_buttons_legacy_summary_on">"Buttons are hidden.
Swipe to expand or close."</string>
<string name="revanced_miniplayer_hide_expand_close_legacy_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_overlay_buttons_legacy_summary_off">Expand and close buttons 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_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_width_dip_title">Initial size</string>
<string name="revanced_miniplayer_width_dip_summary">Initial on screen size, in pixels.</string>
<string name="revanced_miniplayer_width_dip_invalid_toast">Pixel size must be between %1$s and %2$s.</string>

View File

@ -171,6 +171,9 @@
<!-- SETTINGS: MINIPLAYER_TYPE_19_43
<ListPreference android:entries="@array/revanced_miniplayer_type_19_43_entries" android:title="@string/revanced_miniplayer_type_title" android:key="revanced_miniplayer_type" android:entryValues="@array/revanced_miniplayer_type_19_43_entry_values" />SETTINGS: MINIPLAYER_TYPE_19_43 -->
<!-- SETTINGS: MINIPLAYER_TYPE_20_03
<ListPreference android:entries="@array/revanced_miniplayer_type_20_03_entries" android:title="@string/revanced_miniplayer_type_title" android:key="revanced_miniplayer_type" android:entryValues="@array/revanced_miniplayer_type_20_03_entry_values" />SETTINGS: MINIPLAYER_TYPE_20_03 -->
<!-- SETTINGS: MINIPLAYER_DOUBLE_TAP_ACTION
<SwitchPreference android:title="@string/revanced_miniplayer_double_tap_action_title" android:key="revanced_miniplayer_double_tap_action" android:summaryOn="@string/revanced_miniplayer_double_tap_action_summary_on" android:summaryOff="@string/revanced_miniplayer_double_tap_action_summary_off" />SETTINGS: MINIPLAYER_DOUBLE_TAP_ACTION -->
@ -183,18 +186,18 @@
<!-- SETTINGS: MINIPLAYER_ROUNDED_CORNERS
<SwitchPreference android:title="@string/revanced_miniplayer_rounded_corners_title" android:key="revanced_miniplayer_rounded_corners" android:summaryOn="@string/revanced_miniplayer_rounded_corners_summary_on" android:summaryOff="@string/revanced_miniplayer_rounded_corners_summary_off" />SETTINGS: MINIPLAYER_ROUNDED_CORNERS -->
<!-- SETTINGS: MINIPLAYER_TYPE_MODERN
<SwitchPreference android:title="@string/revanced_miniplayer_hide_subtext_title" android:key="revanced_miniplayer_hide_subtext" android:summaryOn="@string/revanced_miniplayer_hide_subtext_summary_on" android:summaryOff="@string/revanced_miniplayer_hide_subtext_summary_off" />SETTINGS: MINIPLAYER_TYPE_MODERN -->
<!-- SETTINGS: MINIPLAYER_OVERLAY_BUTTONS_19_25
<SwitchPreference android:title="@string/revanced_miniplayer_hide_overlay_buttons_title" android:key="revanced_miniplayer_hide_overlay_buttons" android:summaryOn="@string/revanced_miniplayer_hide_overlay_buttons_legacy_summary_on" android:summaryOff="@string/revanced_miniplayer_hide_overlay_buttons_legacy_summary_off" />SETTINGS: MINIPLAYER_OVERLAY_BUTTONS_19_25 -->
<!-- SETTINGS: MINIPLAYER_EXPAND_CLOSE_19_25
<SwitchPreference android:title="@string/revanced_miniplayer_hide_expand_close_title" android:key="revanced_miniplayer_hide_expand_close" android:summaryOn="@string/revanced_miniplayer_hide_expand_close_legacy_summary_on" android:summaryOff="@string/revanced_miniplayer_hide_expand_close_legacy_summary_off" />SETTINGS: MINIPLAYER_EXPAND_CLOSE_19_25 -->
<!-- SETTINGS: MINIPLAYER_EXPAND_CLOSE_19_26
<SwitchPreference android:title="@string/revanced_miniplayer_hide_expand_close_title" android:key="revanced_miniplayer_hide_expand_close" android:summaryOn="@string/revanced_miniplayer_hide_expand_close_summary_on" android:summaryOff="@string/revanced_miniplayer_hide_expand_close_summary_off" />SETTINGS: MINIPLAYER_EXPAND_CLOSE_19_26 -->
<!-- SETTINGS: MINIPLAYER_OVERLAY_BUTTONS_19_26
<SwitchPreference android:title="@string/revanced_miniplayer_hide_overlay_buttons_title" android:key="revanced_miniplayer_hide_overlay_buttons" android:summaryOn="@string/revanced_miniplayer_hide_overlay_buttons_summary_on" android:summaryOff="@string/revanced_miniplayer_hide_overlay_buttons_summary_off" />SETTINGS: MINIPLAYER_OVERLAY_BUTTONS_19_26 -->
<!-- SETTINGS: MINIPLAYER_REWIND_FORWARD
<SwitchPreference android:title="@string/revanced_miniplayer_hide_rewind_forward_title" android:key="revanced_miniplayer_hide_rewind_forward" android:summaryOn="@string/revanced_miniplayer_hide_rewind_forward_summary_on" android:summaryOff="@string/revanced_miniplayer_hide_rewind_forward_summary_off" />SETTINGS: MINIPLAYER_REWIND_FORWARD -->
<!-- SETTINGS: MINIPLAYER_TYPE_MODERN
<SwitchPreference android:title="@string/revanced_miniplayer_hide_subtext_title" android:key="revanced_miniplayer_hide_subtext" android:summaryOn="@string/revanced_miniplayer_hide_subtext_summary_on" android:summaryOff="@string/revanced_miniplayer_hide_subtext_summary_off" />SETTINGS: MINIPLAYER_TYPE_MODERN -->
<!-- SETTINGS: MINIPLAYER_WIDTH_DIP
<app.revanced.extension.shared.settings.preference.ResettableEditTextPreference android:title="@string/revanced_miniplayer_width_dip_title" android:key="revanced_miniplayer_width_dip" android:summary="@string/revanced_miniplayer_width_dip_summary" android:inputType="number" />SETTINGS: MINIPLAYER_WIDTH_DIP -->