fix(YouTube): Combine Restore old video quality menu and Remember video quality into Video quality patch (#4552)

This commit is contained in:
LisoUseInAIKyrios 2025-03-06 14:56:32 +02:00 committed by GitHub
parent 49bf811252
commit ee67b763d5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 324 additions and 301 deletions

View File

@ -2,20 +2,20 @@ package app.revanced.extension.youtube.patches.components;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import app.revanced.extension.youtube.patches.playback.quality.RestoreOldVideoQualityMenuPatch; import app.revanced.extension.youtube.patches.playback.quality.AdvancedVideoQualityMenuPatch;
import app.revanced.extension.youtube.settings.Settings; import app.revanced.extension.youtube.settings.Settings;
/** /**
* Abuse LithoFilter for {@link RestoreOldVideoQualityMenuPatch}. * Abuse LithoFilter for {@link AdvancedVideoQualityMenuPatch}.
*/ */
public final class VideoQualityMenuFilterPatch extends Filter { public final class AdvancedVideoQualityMenuFilter extends Filter {
// Must be volatile or synchronized, as litho filtering runs off main thread // Must be volatile or synchronized, as litho filtering runs off main thread
// and this field is then access from the main thread. // and this field is then access from the main thread.
public static volatile boolean isVideoQualityMenuVisible; public static volatile boolean isVideoQualityMenuVisible;
public VideoQualityMenuFilterPatch() { public AdvancedVideoQualityMenuFilter() {
addPathCallbacks(new StringFilterGroup( addPathCallbacks(new StringFilterGroup(
Settings.RESTORE_OLD_VIDEO_QUALITY_MENU, Settings.ADVANCED_VIDEO_QUALITY_MENU,
"quick_quality_sheet_content.eml-js" "quick_quality_sheet_content.eml-js"
)); ));
} }

View File

@ -8,30 +8,30 @@ import android.widget.ListView;
import app.revanced.extension.shared.Logger; import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils; import app.revanced.extension.shared.Utils;
import app.revanced.extension.youtube.patches.components.VideoQualityMenuFilterPatch; import app.revanced.extension.youtube.patches.components.AdvancedVideoQualityMenuFilter;
import app.revanced.extension.youtube.settings.Settings; import app.revanced.extension.youtube.settings.Settings;
/** /**
* This patch contains the logic to show the old video quality menu. * This patch contains the logic to always open the advanced video quality menu.
* Two methods are required, because the quality menu is a RecyclerView in the new YouTube version * Two methods are required, because the quality menu is a RecyclerView in the new YouTube version
* and a ListView in the old one. * and a ListView in the old one.
*/ */
@SuppressWarnings("unused") @SuppressWarnings("unused")
public final class RestoreOldVideoQualityMenuPatch { public final class AdvancedVideoQualityMenuPatch {
/** /**
* Injection point. * Injection point.
*/ */
public static void onFlyoutMenuCreate(RecyclerView recyclerView) { public static void onFlyoutMenuCreate(RecyclerView recyclerView) {
if (!Settings.RESTORE_OLD_VIDEO_QUALITY_MENU.get()) return; if (!Settings.ADVANCED_VIDEO_QUALITY_MENU.get()) return;
recyclerView.getViewTreeObserver().addOnDrawListener(() -> { recyclerView.getViewTreeObserver().addOnDrawListener(() -> {
try { try {
// Check if the current view is the quality menu. // Check if the current view is the quality menu.
if (!VideoQualityMenuFilterPatch.isVideoQualityMenuVisible || recyclerView.getChildCount() == 0) { if (!AdvancedVideoQualityMenuFilter.isVideoQualityMenuVisible || recyclerView.getChildCount() == 0) {
return; return;
} }
VideoQualityMenuFilterPatch.isVideoQualityMenuVisible = false; AdvancedVideoQualityMenuFilter.isVideoQualityMenuVisible = false;
ViewParent quickQualityViewParent = Utils.getParentView(recyclerView, 3); ViewParent quickQualityViewParent = Utils.getParentView(recyclerView, 3);
if (!(quickQualityViewParent instanceof ViewGroup)) { if (!(quickQualityViewParent instanceof ViewGroup)) {
@ -39,16 +39,15 @@ public final class RestoreOldVideoQualityMenuPatch {
} }
View firstChild = recyclerView.getChildAt(0); View firstChild = recyclerView.getChildAt(0);
if (!(firstChild instanceof ViewGroup)) { if (!(firstChild instanceof ViewGroup firstChildGroup)) {
return; return;
} }
ViewGroup advancedQualityParentView = (ViewGroup) firstChild; if (firstChildGroup.getChildCount() < 4) {
if (advancedQualityParentView.getChildCount() < 4) {
return; return;
} }
View advancedQualityView = advancedQualityParentView.getChildAt(3); View advancedQualityView = firstChildGroup.getChildAt(3);
if (advancedQualityView == null) { if (advancedQualityView == null) {
return; return;
} }
@ -71,7 +70,7 @@ public final class RestoreOldVideoQualityMenuPatch {
* Used to force the creation of the advanced menu item for the Shorts quality flyout. * Used to force the creation of the advanced menu item for the Shorts quality flyout.
*/ */
public static boolean forceAdvancedVideoQualityMenuCreation(boolean original) { public static boolean forceAdvancedVideoQualityMenuCreation(boolean original) {
return Settings.RESTORE_OLD_VIDEO_QUALITY_MENU.get() || original; return Settings.ADVANCED_VIDEO_QUALITY_MENU.get() || original;
} }
/** /**
@ -79,8 +78,8 @@ public final class RestoreOldVideoQualityMenuPatch {
* *
* Used if spoofing to an old app version, and also used for the Shorts video quality flyout. * Used if spoofing to an old app version, and also used for the Shorts video quality flyout.
*/ */
public static void showOldVideoQualityMenu(final ListView listView) { public static void showAdvancedVideoQualityMenu(ListView listView) {
if (!Settings.RESTORE_OLD_VIDEO_QUALITY_MENU.get()) return; if (!Settings.ADVANCED_VIDEO_QUALITY_MENU.get()) return;
listView.setOnHierarchyChangeListener(new ViewGroup.OnHierarchyChangeListener() { listView.setOnHierarchyChangeListener(new ViewGroup.OnHierarchyChangeListener() {
@Override @Override

View File

@ -47,14 +47,14 @@ import app.revanced.extension.youtube.sponsorblock.SponsorBlockSettings;
public class Settings extends BaseSettings { public class Settings extends BaseSettings {
// Video // Video
public static final BooleanSetting DISABLE_HDR_VIDEO = new BooleanSetting("revanced_disable_hdr_video", FALSE);
public static final IntegerSetting VIDEO_QUALITY_DEFAULT_WIFI = new IntegerSetting("revanced_video_quality_default_wifi", -2); public static final IntegerSetting VIDEO_QUALITY_DEFAULT_WIFI = new IntegerSetting("revanced_video_quality_default_wifi", -2);
public static final IntegerSetting VIDEO_QUALITY_DEFAULT_MOBILE = new IntegerSetting("revanced_video_quality_default_mobile", -2); public static final IntegerSetting VIDEO_QUALITY_DEFAULT_MOBILE = new IntegerSetting("revanced_video_quality_default_mobile", -2);
public static final BooleanSetting REMEMBER_VIDEO_QUALITY_LAST_SELECTED = new BooleanSetting("revanced_remember_video_quality_last_selected", FALSE); public static final BooleanSetting REMEMBER_VIDEO_QUALITY_LAST_SELECTED = new BooleanSetting("revanced_remember_video_quality_last_selected", FALSE);
public static final IntegerSetting SHORTS_QUALITY_DEFAULT_WIFI = new IntegerSetting("revanced_shorts_quality_default_wifi", -2, true); public static final IntegerSetting SHORTS_QUALITY_DEFAULT_WIFI = new IntegerSetting("revanced_shorts_quality_default_wifi", -2, true);
public static final IntegerSetting SHORTS_QUALITY_DEFAULT_MOBILE = new IntegerSetting("revanced_shorts_quality_default_mobile", -2, true); public static final IntegerSetting SHORTS_QUALITY_DEFAULT_MOBILE = new IntegerSetting("revanced_shorts_quality_default_mobile", -2, true);
public static final BooleanSetting REMEMBER_SHORTS_QUALITY_LAST_SELECTED = new BooleanSetting("revanced_remember_shorts_quality_last_selected", FALSE); public static final BooleanSetting REMEMBER_SHORTS_QUALITY_LAST_SELECTED = new BooleanSetting("revanced_remember_shorts_quality_last_selected", FALSE);
public static final BooleanSetting RESTORE_OLD_VIDEO_QUALITY_MENU = new BooleanSetting("revanced_restore_old_video_quality_menu", TRUE); public static final BooleanSetting ADVANCED_VIDEO_QUALITY_MENU = new BooleanSetting("revanced_advanced_video_quality_menu", TRUE);
public static final BooleanSetting DISABLE_HDR_VIDEO = new BooleanSetting("revanced_disable_hdr_video", FALSE);
// Speed // Speed
public static final FloatSetting SPEED_TAP_AND_HOLD = new FloatSetting("revanced_speed_tap_and_hold", 2.0f, true); public static final FloatSetting SPEED_TAP_AND_HOLD = new FloatSetting("revanced_speed_tap_and_hold", 2.0f, true);
public static final BooleanSetting REMEMBER_PLAYBACK_SPEED_LAST_SELECTED = new BooleanSetting("revanced_remember_playback_speed_last_selected", FALSE); public static final BooleanSetting REMEMBER_PLAYBACK_SPEED_LAST_SELECTED = new BooleanSetting("revanced_remember_playback_speed_last_selected", FALSE);
@ -391,6 +391,7 @@ public class Settings extends BaseSettings {
private static final IntegerSetting DEPRECATED_SWIPE_OVERLAY_BACKGROUND_ALPHA = new IntegerSetting("revanced_swipe_overlay_background_alpha", 127); private static final IntegerSetting DEPRECATED_SWIPE_OVERLAY_BACKGROUND_ALPHA = new IntegerSetting("revanced_swipe_overlay_background_alpha", 127);
private static final StringSetting DEPRECATED_SEEKBAR_CUSTOM_COLOR_PRIMARY = new StringSetting("revanced_seekbar_custom_color_value", "#FF0033"); private static final StringSetting DEPRECATED_SEEKBAR_CUSTOM_COLOR_PRIMARY = new StringSetting("revanced_seekbar_custom_color_value", "#FF0033");
private static final BooleanSetting DEPRECATED_DISABLE_SUGGESTED_VIDEO_END_SCREEN = new BooleanSetting("revanced_disable_suggested_video_end_screen", FALSE); private static final BooleanSetting DEPRECATED_DISABLE_SUGGESTED_VIDEO_END_SCREEN = new BooleanSetting("revanced_disable_suggested_video_end_screen", FALSE);
private static final BooleanSetting DEPRECATED_RESTORE_OLD_VIDEO_QUALITY_MENU = new BooleanSetting("revanced_restore_old_video_quality_menu", TRUE);
static { static {
// region Migration // region Migration
@ -411,6 +412,8 @@ public class Settings extends BaseSettings {
migrateOldSettingToNew(DEPRECATED_DISABLE_SUGGESTED_VIDEO_END_SCREEN, HIDE_END_SCREEN_SUGGESTED_VIDEO); migrateOldSettingToNew(DEPRECATED_DISABLE_SUGGESTED_VIDEO_END_SCREEN, HIDE_END_SCREEN_SUGGESTED_VIDEO);
migrateOldSettingToNew(DEPRECATED_RESTORE_OLD_VIDEO_QUALITY_MENU, ADVANCED_VIDEO_QUALITY_MENU);
// Migrate renamed enum. // Migrate renamed enum.
//noinspection deprecation //noinspection deprecation
if (MINIPLAYER_TYPE.get() == MiniplayerType.PHONE) { if (MINIPLAYER_TYPE.get() == MiniplayerType.PHONE) {

View File

@ -1463,6 +1463,10 @@ public final class app/revanced/patches/youtube/video/quality/RememberVideoQuali
public static final fun getRememberVideoQualityPatch ()Lapp/revanced/patcher/patch/BytecodePatch; public static final fun getRememberVideoQualityPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
} }
public final class app/revanced/patches/youtube/video/quality/VideoQualityPatchKt {
public static final fun getVideoQualityPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
public final class app/revanced/patches/youtube/video/speed/PlaybackSpeedPatchKt { public final class app/revanced/patches/youtube/video/speed/PlaybackSpeedPatchKt {
public static final fun getPlaybackSpeedPatch ()Lapp/revanced/patcher/patch/BytecodePatch; public static final fun getPlaybackSpeedPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
} }

View File

@ -5,10 +5,10 @@ import app.revanced.patches.all.misc.transformation.IMethodCall
import app.revanced.patches.all.misc.transformation.filterMapInstruction35c import app.revanced.patches.all.misc.transformation.filterMapInstruction35c
import app.revanced.patches.all.misc.transformation.transformInstructionsPatch import app.revanced.patches.all.misc.transformation.transformInstructionsPatch
internal const val EXTENSION_CLASS_DESCRIPTOR_PREFIX = private const val EXTENSION_CLASS_DESCRIPTOR_PREFIX =
"Lapp/revanced/extension/all/connectivity/wifi/spoof/SpoofWifiPatch" "Lapp/revanced/extension/all/connectivity/wifi/spoof/SpoofWifiPatch"
internal const val EXTENSION_CLASS_DESCRIPTOR = "$EXTENSION_CLASS_DESCRIPTOR_PREFIX;" private const val EXTENSION_CLASS_DESCRIPTOR = "$EXTENSION_CLASS_DESCRIPTOR_PREFIX;"
@Suppress("unused") @Suppress("unused")
val spoofWifiPatch = bytecodePatch( val spoofWifiPatch = bytecodePatch(

View File

@ -17,7 +17,7 @@ import com.android.tools.smali.dexlib2.iface.reference.TypeReference
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
internal const val EXTENSION_CLASS_DESCRIPTOR = private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/music/spoof/SpoofClientPatch;" "Lapp/revanced/extension/music/spoof/SpoofClientPatch;"
// TODO: Replace this patch with spoofVideoStreamsPatch once possible. // TODO: Replace this patch with spoofVideoStreamsPatch once possible.

View File

@ -11,7 +11,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction22c
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c
import com.android.tools.smali.dexlib2.iface.reference.FieldReference import com.android.tools.smali.dexlib2.iface.reference.FieldReference
internal const val EXTENSION_CLASS_DESCRIPTOR = private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/tiktok/settings/AdPersonalizationActivityHook;" "Lapp/revanced/extension/tiktok/settings/AdPersonalizationActivityHook;"
val settingsPatch = bytecodePatch( val settingsPatch = bytecodePatch(

View File

@ -12,7 +12,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c
import com.android.tools.smali.dexlib2.iface.reference.FieldReference import com.android.tools.smali.dexlib2.iface.reference.FieldReference
import com.android.tools.smali.dexlib2.iface.reference.MethodReference import com.android.tools.smali.dexlib2.iface.reference.MethodReference
internal const val EXTENSION_CLASS_DESCRIPTOR = private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/tudortmund/lockscreen/ShowOnLockscreenPatch;" "Lapp/revanced/extension/tudortmund/lockscreen/ShowOnLockscreenPatch;"
@Suppress("unused") @Suppress("unused")

View File

@ -11,7 +11,7 @@ import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch import app.revanced.patches.youtube.misc.settings.settingsPatch
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
internal const val EXTENSION_CLASS_DESCRIPTOR = private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/patches/HideGetPremiumPatch;" "Lapp/revanced/extension/youtube/patches/HideGetPremiumPatch;"
val hideGetPremiumPatch = bytecodePatch( val hideGetPremiumPatch = bytecodePatch(

View File

@ -50,7 +50,7 @@ private val downloadsResourcePatch = resourcePatch {
} }
} }
internal const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/DownloadsPatch;" private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/DownloadsPatch;"
internal const val BUTTON_DESCRIPTOR = "Lapp/revanced/extension/youtube/videoplayer/ExternalDownloadButton;" internal const val BUTTON_DESCRIPTOR = "Lapp/revanced/extension/youtube/videoplayer/ExternalDownloadButton;"

View File

@ -23,7 +23,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference import com.android.tools.smali.dexlib2.iface.reference.MethodReference
internal const val EXTENSION_CLASS_DESCRIPTOR = private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/patches/NavigationButtonsPatch;" "Lapp/revanced/extension/youtube/patches/NavigationButtonsPatch;"
val navigationButtonsPatch = bytecodePatch( val navigationButtonsPatch = bytecodePatch(

View File

@ -14,7 +14,7 @@ import app.revanced.util.indexOfFirstInstructionReversedOrThrow
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference import com.android.tools.smali.dexlib2.iface.reference.MethodReference
internal const val EXTENSION_CLASS_DESCRIPTOR = private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/patches/DisableFullscreenAmbientModePatch;" "Lapp/revanced/extension/youtube/patches/DisableFullscreenAmbientModePatch;"
val disableFullscreenAmbientModePatch = bytecodePatch( val disableFullscreenAmbientModePatch = bytecodePatch(

View File

@ -8,7 +8,10 @@ import app.revanced.patcher.patch.stringOption
import app.revanced.patches.all.misc.resources.addResources import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.shared.misc.mapping.resourceMappingPatch import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
import app.revanced.patches.shared.misc.settings.preference.BasePreference
import app.revanced.patches.shared.misc.settings.preference.InputType import app.revanced.patches.shared.misc.settings.preference.InputType
import app.revanced.patches.shared.misc.settings.preference.PreferenceCategory
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference.Sorting
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
import app.revanced.patches.shared.misc.settings.preference.TextPreference import app.revanced.patches.shared.misc.settings.preference.TextPreference
import app.revanced.patches.youtube.layout.seekbar.seekbarColorPatch import app.revanced.patches.youtube.layout.seekbar.seekbarColorPatch
@ -71,6 +74,9 @@ val themePatch = bytecodePatch(
) )
dependsOn( dependsOn(
sharedExtensionPatch,
settingsPatch,
addResourcesPatch,
lithoColorHookPatch, lithoColorHookPatch,
seekbarColorPatch, seekbarColorPatch,
versionCheckPatch, versionCheckPatch,
@ -78,23 +84,31 @@ val themePatch = bytecodePatch(
dependsOn( dependsOn(
settingsPatch, settingsPatch,
resourceMappingPatch, resourceMappingPatch,
addResourcesPatch,
) )
execute { execute {
addResources("youtube", "layout.theme.themeResourcePatch") val preferences = mutableSetOf<BasePreference>(
PreferenceScreen.SEEKBAR.addPreferences(
SwitchPreference("revanced_seekbar_custom_color"), SwitchPreference("revanced_seekbar_custom_color"),
TextPreference("revanced_seekbar_custom_color_primary", inputType = InputType.TEXT_CAP_CHARACTERS), TextPreference("revanced_seekbar_custom_color_primary", inputType = InputType.TEXT_CAP_CHARACTERS),
) )
if (is_19_25_or_greater) { if (is_19_25_or_greater) {
PreferenceScreen.SEEKBAR.addPreferences( preferences += TextPreference(
TextPreference("revanced_seekbar_custom_color_accent", inputType = InputType.TEXT_CAP_CHARACTERS), "revanced_seekbar_custom_color_accent",
inputType = InputType.TEXT_CAP_CHARACTERS
) )
} }
PreferenceScreen.SEEKBAR.addPreferences(
PreferenceCategory(
// Title is hidden, but is used for sorting the group.
titleKey = "revanced_seekbar_custom_color_title",
sorting = Sorting.UNSORTED,
tag = "app.revanced.extension.shared.settings.preference.NoTitlePreferenceCategory",
preferences = preferences
)
)
// Edit theme colors via resources. // Edit theme colors via resources.
document("res/values/colors.xml").use { document -> document("res/values/colors.xml").use { document ->
@ -125,7 +139,6 @@ val themePatch = bytecodePatch(
colorValue: String, colorValue: String,
) { ) {
document(resourceFile).use { document -> document(resourceFile).use { document ->
val resourcesNode = document.getElementsByTagName("resources").item(0) as Element val resourcesNode = document.getElementsByTagName("resources").item(0) as Element
resourcesNode.appendChild( resourcesNode.appendChild(
@ -133,7 +146,7 @@ val themePatch = bytecodePatch(
setAttribute("name", colorName) setAttribute("name", colorName)
setAttribute("category", "color") setAttribute("category", "color")
textContent = colorValue textContent = colorValue
}, }
) )
} }
} }
@ -152,11 +165,10 @@ val themePatch = bytecodePatch(
// Edit splash screen files and change the background color, // Edit splash screen files and change the background color,
// if the background colors are set. // if the background colors are set.
if (darkThemeBackgroundColor != null && lightThemeBackgroundColor != null) { if (darkThemeBackgroundColor != null && lightThemeBackgroundColor != null) {
val splashScreenResourceFiles = val splashScreenResourceFiles = listOf(
listOf( "res/drawable/quantum_launchscreen_youtube.xml",
"res/drawable/quantum_launchscreen_youtube.xml", "res/drawable-sw600dp/quantum_launchscreen_youtube.xml",
"res/drawable-sw600dp/quantum_launchscreen_youtube.xml", )
)
splashScreenResourceFiles.forEach editSplashScreen@{ resourceFile -> splashScreenResourceFiles.forEach editSplashScreen@{ resourceFile ->
document(resourceFile).use { document -> document(resourceFile).use { document ->
@ -200,10 +212,7 @@ val themePatch = bytecodePatch(
} }
} }
} }
}, }
sharedExtensionPatch,
settingsPatch,
addResourcesPatch,
) )
compatibleWith( compatibleWith(

View File

@ -27,7 +27,7 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
lateinit var addLithoFilter: (String) -> Unit lateinit var addLithoFilter: (String) -> Unit
private set private set
internal const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/components/LithoFilterPatch;" private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/components/LithoFilterPatch;"
val lithoFilterPatch = bytecodePatch( val lithoFilterPatch = bytecodePatch(
description = "Hooks the method which parses the bytes into a ComponentContext to filter components.", description = "Hooks the method which parses the bytes into a ComponentContext to filter components.",

View File

@ -15,7 +15,7 @@ import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction 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.ReferenceInstruction
internal const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/PlayerTypeHookPatch;" private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/PlayerTypeHookPatch;"
internal var reelWatchPlayerId = -1L internal var reelWatchPlayerId = -1L
private set private set

View File

@ -301,11 +301,9 @@ object PreferenceScreen : BasePreferenceScreen() {
summaryKey = null, summaryKey = null,
) )
// Don't sort, because title sorting scatters the custom color preferences.
val SEEKBAR = Screen( val SEEKBAR = Screen(
key = "revanced_settings_screen_07_seekbar", key = "revanced_settings_screen_07_seekbar",
summaryKey = null, summaryKey = null,
sorting = Sorting.UNSORTED,
) )
val SWIPE_CONTROLS = Screen( val SWIPE_CONTROLS = Screen(
key = "revanced_settings_screen_08_swipe_controls", key = "revanced_settings_screen_08_swipe_controls",

View File

@ -0,0 +1,118 @@
package app.revanced.patches.youtube.video.quality
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.patch.PatchException
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.resourcePatch
import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.shared.misc.mapping.get
import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
import app.revanced.patches.shared.misc.mapping.resourceMappings
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.litho.filter.addLithoFilter
import app.revanced.patches.youtube.misc.litho.filter.lithoFilterPatch
import app.revanced.patches.youtube.misc.recyclerviewtree.hook.addRecyclerViewTreeHook
import app.revanced.patches.youtube.misc.recyclerviewtree.hook.recyclerViewTreeHookPatch
import app.revanced.patches.youtube.misc.settings.settingsPatch
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
internal var videoQualityBottomSheetListFragmentTitle = -1L
private set
internal var videoQualityQuickMenuAdvancedMenuDescription = -1L
private set
private val advancedVideoQualityMenuResourcePatch = resourcePatch {
dependsOn(resourceMappingPatch)
execute {
// Used for the old type of the video quality menu.
videoQualityBottomSheetListFragmentTitle = resourceMappings[
"layout",
"video_quality_bottom_sheet_list_fragment_title",
]
videoQualityQuickMenuAdvancedMenuDescription = resourceMappings[
"string",
"video_quality_quick_menu_advanced_menu_description",
]
}
}
private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/patches/playback/quality/AdvancedVideoQualityMenuPatch;"
private const val FILTER_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/patches/components/AdvancedVideoQualityMenuFilter;"
internal val advancedVideoQualityMenuPatch = bytecodePatch {
dependsOn(
advancedVideoQualityMenuResourcePatch,
sharedExtensionPatch,
settingsPatch,
addResourcesPatch,
lithoFilterPatch,
recyclerViewTreeHookPatch,
)
execute {
addResources("youtube", "video.quality.advancedVideoQualityMenuPatch")
settingsMenuVideoQualityGroup.add(
SwitchPreference("revanced_advanced_video_quality_menu")
)
// region Patch for the old type of the video quality menu.
// Used for regular videos when spoofing to old app version,
// and for the Shorts quality flyout on newer app versions.
videoQualityMenuViewInflateFingerprint.let {
it.method.apply {
val checkCastIndex = it.patternMatch!!.endIndex
val listViewRegister = getInstruction<OneRegisterInstruction>(checkCastIndex).registerA
addInstruction(
checkCastIndex + 1,
"invoke-static { v$listViewRegister }, $EXTENSION_CLASS_DESCRIPTOR->" +
"showAdvancedVideoQualityMenu(Landroid/widget/ListView;)V",
)
}
}
// Force YT to add the 'advanced' quality menu for Shorts.
videoQualityMenuOptionsFingerprint.let {
val patternMatch = it.patternMatch!!
val startIndex = patternMatch.startIndex
val insertIndex = patternMatch.endIndex
if (startIndex != 0) throw PatchException("Unexpected opcode start index: $startIndex")
it.method.apply {
val register = getInstruction<OneRegisterInstruction>(insertIndex).registerA
// A condition controls whether to show the three or four items quality menu.
// Force the four items quality menu to make the "Advanced" item visible, necessary for the patch.
addInstructions(
insertIndex,
"""
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->forceAdvancedVideoQualityMenuCreation(Z)Z
move-result v$register
"""
)
}
}
// endregion
// region Patch for the new type of the video quality menu.
addRecyclerViewTreeHook(EXTENSION_CLASS_DESCRIPTOR)
// Required to check if the video quality menu is currently shown in order to click on the "Advanced" item.
addLithoFilter(FILTER_CLASS_DESCRIPTOR)
// endregion
}
}

View File

@ -1,6 +1,7 @@
package app.revanced.patches.youtube.video.quality package app.revanced.patches.youtube.video.quality
import app.revanced.patcher.fingerprint import app.revanced.patcher.fingerprint
import app.revanced.util.literal
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
@ -35,3 +36,41 @@ internal val videoQualitySetterFingerprint = fingerprint {
) )
strings("menu_item_video_quality") strings("menu_item_video_quality")
} }
internal val videoQualityMenuOptionsFingerprint = fingerprint {
accessFlags(AccessFlags.STATIC)
returns("[L")
parameters("Landroid/content/Context", "L", "L")
opcodes(
Opcode.CONST_4, // First instruction of method.
Opcode.CONST_4,
Opcode.IF_EQZ,
Opcode.IGET_BOOLEAN, // Use the quality menu, that contains the advanced menu.
Opcode.IF_NEZ,
)
literal { videoQualityQuickMenuAdvancedMenuDescription }
}
internal val videoQualityMenuViewInflateFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("L")
parameters("L", "L", "L")
opcodes(
Opcode.INVOKE_SUPER,
Opcode.CONST,
Opcode.CONST_4,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CONST,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CONST_16,
Opcode.INVOKE_VIRTUAL,
Opcode.CONST,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CHECK_CAST,
)
literal { videoQualityBottomSheetListFragmentTitle }
}

View File

@ -8,12 +8,9 @@ import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.all.misc.resources.addResources import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.shared.misc.settings.preference.ListPreference import app.revanced.patches.shared.misc.settings.preference.ListPreference
import app.revanced.patches.shared.misc.settings.preference.PreferenceCategory
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference.Sorting
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.playertype.playerTypeHookPatch import app.revanced.patches.youtube.misc.playertype.playerTypeHookPatch
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.patches.youtube.shared.newVideoQualityChangedFingerprint import app.revanced.patches.youtube.shared.newVideoQualityChangedFingerprint
import app.revanced.patches.youtube.video.information.onCreateHook import app.revanced.patches.youtube.video.information.onCreateHook
@ -25,10 +22,7 @@ import com.android.tools.smali.dexlib2.iface.reference.FieldReference
private const val EXTENSION_CLASS_DESCRIPTOR = private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/patches/playback/quality/RememberVideoQualityPatch;" "Lapp/revanced/extension/youtube/patches/playback/quality/RememberVideoQualityPatch;"
val rememberVideoQualityPatch = bytecodePatch( val rememberVideoQualityPatch = bytecodePatch {
name = "Remember video quality",
description = "Adds an option to remember the last video quality selected.",
) {
dependsOn( dependsOn(
sharedExtensionPatch, sharedExtensionPatch,
videoInformationPatch, videoInformationPatch,
@ -37,59 +31,38 @@ val rememberVideoQualityPatch = bytecodePatch(
addResourcesPatch, addResourcesPatch,
) )
compatibleWith(
"com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
),
)
execute { execute {
addResources("youtube", "video.quality.rememberVideoQualityPatch") addResources("youtube", "video.quality.rememberVideoQualityPatch")
PreferenceScreen.VIDEO.addPreferences( settingsMenuVideoQualityGroup.addAll(listOf(
// Keep the preferences organized together. ListPreference(
PreferenceCategory( key = "revanced_video_quality_default_mobile",
key = "revanced_01_video_key", // Dummy key to force the quality preferences first. summaryKey = null,
titleKey = null, entriesKey = "revanced_video_quality_default_entries",
sorting = Sorting.UNSORTED, entryValuesKey = "revanced_video_quality_default_entry_values",
tag = "app.revanced.extension.shared.settings.preference.NoTitlePreferenceCategory", ),
preferences = setOf( ListPreference(
ListPreference( key = "revanced_video_quality_default_wifi",
key = "revanced_video_quality_default_mobile", summaryKey = null,
summaryKey = null, entriesKey = "revanced_video_quality_default_entries",
entriesKey = "revanced_video_quality_default_entries", entryValuesKey = "revanced_video_quality_default_entry_values",
entryValuesKey = "revanced_video_quality_default_entry_values", ),
), SwitchPreference("revanced_remember_video_quality_last_selected"),
ListPreference(
key = "revanced_video_quality_default_wifi",
summaryKey = null,
entriesKey = "revanced_video_quality_default_entries",
entryValuesKey = "revanced_video_quality_default_entry_values",
),
SwitchPreference("revanced_remember_video_quality_last_selected"),
ListPreference( ListPreference(
key = "revanced_shorts_quality_default_mobile", key = "revanced_shorts_quality_default_mobile",
summaryKey = null, summaryKey = null,
entriesKey = "revanced_video_quality_default_entries", entriesKey = "revanced_video_quality_default_entries",
entryValuesKey = "revanced_video_quality_default_entry_values", entryValuesKey = "revanced_video_quality_default_entry_values",
), ),
ListPreference( ListPreference(
key = "revanced_shorts_quality_default_wifi", key = "revanced_shorts_quality_default_wifi",
summaryKey = null, summaryKey = null,
entriesKey = "revanced_video_quality_default_entries", entriesKey = "revanced_video_quality_default_entries",
entryValuesKey = "revanced_video_quality_default_entry_values", entryValuesKey = "revanced_video_quality_default_entry_values",
), ),
SwitchPreference("revanced_remember_shorts_quality_last_selected") SwitchPreference("revanced_remember_shorts_quality_last_selected")
) ))
)
)
/* /*
* The following code works by hooking the method which is called when the user selects a video quality * The following code works by hooking the method which is called when the user selects a video quality

View File

@ -0,0 +1,48 @@
package app.revanced.patches.youtube.video.quality
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.shared.misc.settings.preference.BasePreference
import app.revanced.patches.shared.misc.settings.preference.PreferenceCategory
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference.Sorting
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
/**
* Video quality settings. Used to organize all speed related settings together.
*/
internal val settingsMenuVideoQualityGroup = mutableSetOf<BasePreference>()
@Suppress("unused")
val videoQualityPatch = bytecodePatch(
name = "Video quality",
description = "Adds options to use the advanced video quality menu and set default video qualities."
) {
dependsOn(
rememberVideoQualityPatch,
advancedVideoQualityMenuPatch,
)
compatibleWith(
"com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
)
)
execute {
PreferenceScreen.VIDEO.addPreferences(
// Keep the preferences organized together.
PreferenceCategory(
key = "revanced_01_video_key", // Dummy key to force the quality preferences first.
titleKey = null,
sorting = Sorting.UNSORTED,
tag = "app.revanced.extension.shared.settings.preference.NoTitlePreferenceCategory",
preferences = settingsMenuVideoQualityGroup
)
)
}
}

View File

@ -17,13 +17,13 @@ internal val settingsMenuVideoSpeedGroup = mutableSetOf<BasePreference>()
@Suppress("unused") @Suppress("unused")
val playbackSpeedPatch = bytecodePatch( val playbackSpeedPatch = bytecodePatch(
name = "Playback speed", name = "Playback speed",
description = "Adds options to customize available playback speeds, remember the last playback speed selected " + description = "Adds options to customize available playback speeds, set default a playback speed, " +
"and show a speed dialog button in the video player.", "and show a speed dialog button in the video player.",
) { ) {
dependsOn( dependsOn(
playbackSpeedButtonPatch,
customPlaybackSpeedPatch, customPlaybackSpeedPatch,
rememberPlaybackSpeedPatch, rememberPlaybackSpeedPatch,
playbackSpeedButtonPatch,
) )
compatibleWith( compatibleWith(
@ -38,10 +38,10 @@ val playbackSpeedPatch = bytecodePatch(
) )
) )
finalize { execute {
PreferenceScreen.VIDEO.addPreferences( PreferenceScreen.VIDEO.addPreferences(
PreferenceCategory( PreferenceCategory(
key = "revanced_zz_key", // Dummy key to force the speed settings last. key = "revanced_zz_video_key", // Dummy key to force the speed settings last.
titleKey = null, titleKey = null,
sorting = Sorting.UNSORTED, sorting = Sorting.UNSORTED,
tag = "app.revanced.extension.shared.settings.preference.NoTitlePreferenceCategory", tag = "app.revanced.extension.shared.settings.preference.NoTitlePreferenceCategory",

View File

@ -5,6 +5,7 @@ import app.revanced.patcher.patch.resourcePatch
import app.revanced.patches.all.misc.resources.addResources import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.playercontrols.* import app.revanced.patches.youtube.misc.playercontrols.*
import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch import app.revanced.patches.youtube.misc.settings.settingsPatch
@ -35,11 +36,12 @@ val playbackSpeedButtonPatch = bytecodePatch(
description = "Adds the option to display playback speed dialog button in the video player.", description = "Adds the option to display playback speed dialog button in the video player.",
) { ) {
dependsOn( dependsOn(
playbackSpeedButtonResourcePatch, sharedExtensionPatch,
customPlaybackSpeedPatch,
playerControlsPatch,
settingsPatch, settingsPatch,
addResourcesPatch, addResourcesPatch,
customPlaybackSpeedPatch,
playbackSpeedButtonResourcePatch,
playerControlsPatch,
) )
execute { execute {

View File

@ -60,12 +60,12 @@ internal val customPlaybackSpeedPatch = bytecodePatch(
) { ) {
dependsOn( dependsOn(
sharedExtensionPatch, sharedExtensionPatch,
lithoFilterPatch,
settingsPatch, settingsPatch,
recyclerViewTreeHookPatch,
customPlaybackSpeedResourcePatch,
addResourcesPatch, addResourcesPatch,
versionCheckPatch lithoFilterPatch,
versionCheckPatch,
recyclerViewTreeHookPatch,
customPlaybackSpeedResourcePatch
) )
execute { execute {

View File

@ -22,9 +22,9 @@ internal val rememberPlaybackSpeedPatch = bytecodePatch {
dependsOn( dependsOn(
sharedExtensionPatch, sharedExtensionPatch,
settingsPatch, settingsPatch,
videoInformationPatch,
customPlaybackSpeedPatch,
addResourcesPatch, addResourcesPatch,
videoInformationPatch,
customPlaybackSpeedPatch
) )
execute { execute {
@ -44,6 +44,7 @@ internal val rememberPlaybackSpeedPatch = bytecodePatch {
) )
onCreateHook(EXTENSION_CLASS_DESCRIPTOR, "newVideoStarted") onCreateHook(EXTENSION_CLASS_DESCRIPTOR, "newVideoStarted")
userSelectedPlaybackSpeedHook( userSelectedPlaybackSpeedHook(
EXTENSION_CLASS_DESCRIPTOR, EXTENSION_CLASS_DESCRIPTOR,
"userSelectedPlaybackSpeed", "userSelectedPlaybackSpeed",

View File

@ -1,43 +0,0 @@
package app.revanced.patches.youtube.video.videoqualitymenu
import app.revanced.patcher.fingerprint
import app.revanced.util.literal
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
internal val videoQualityMenuOptionsFingerprint = fingerprint {
accessFlags(AccessFlags.STATIC)
returns("[L")
parameters("Landroid/content/Context", "L", "L")
opcodes(
Opcode.CONST_4, // First instruction of method.
Opcode.CONST_4,
Opcode.IF_EQZ,
Opcode.IGET_BOOLEAN, // Use the quality menu, that contains the advanced menu.
Opcode.IF_NEZ,
)
literal { videoQualityQuickMenuAdvancedMenuDescription }
}
internal val videoQualityMenuViewInflateFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("L")
parameters("L", "L", "L")
opcodes(
Opcode.INVOKE_SUPER,
Opcode.CONST,
Opcode.CONST_4,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CONST,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CONST_16,
Opcode.INVOKE_VIRTUAL,
Opcode.CONST,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CHECK_CAST,
)
literal { videoQualityBottomSheetListFragmentTitle }
}

View File

@ -1,135 +1,10 @@
package app.revanced.patches.youtube.video.videoqualitymenu package app.revanced.patches.youtube.video.videoqualitymenu
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.patch.PatchException
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.resourcePatch import app.revanced.patches.youtube.video.quality.videoQualityPatch
import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.shared.misc.mapping.get
import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
import app.revanced.patches.shared.misc.mapping.resourceMappings
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.litho.filter.addLithoFilter
import app.revanced.patches.youtube.misc.litho.filter.lithoFilterPatch
import app.revanced.patches.youtube.misc.recyclerviewtree.hook.addRecyclerViewTreeHook
import app.revanced.patches.youtube.misc.recyclerviewtree.hook.recyclerViewTreeHookPatch
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
internal var videoQualityBottomSheetListFragmentTitle = -1L
private set
internal var videoQualityQuickMenuAdvancedMenuDescription = -1L
private set
private val restoreOldVideoQualityMenuResourcePatch = resourcePatch {
dependsOn(
settingsPatch,
resourceMappingPatch,
addResourcesPatch,
)
execute {
addResources("youtube", "video.videoqualitymenu.restoreOldVideoQualityMenuResourcePatch")
PreferenceScreen.VIDEO.addPreferences(
SwitchPreference("revanced_restore_old_video_quality_menu"),
)
// Used for the old type of the video quality menu.
videoQualityBottomSheetListFragmentTitle = resourceMappings[
"layout",
"video_quality_bottom_sheet_list_fragment_title",
]
videoQualityQuickMenuAdvancedMenuDescription = resourceMappings[
"string",
"video_quality_quick_menu_advanced_menu_description",
]
}
}
private const val FILTER_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/patches/components/VideoQualityMenuFilterPatch;"
private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/patches/playback/quality/RestoreOldVideoQualityMenuPatch;"
@Suppress("unused") @Suppress("unused")
val restoreOldVideoQualityMenuPatch = bytecodePatch( @Deprecated("Use 'Video Quality' instead.")
name = "Restore old video quality menu", val restoreOldVideoQualityMenuPatch = bytecodePatch {
description = "Adds an option to restore the old video quality menu with specific video resolution options.", dependsOn(videoQualityPatch)
}
) {
dependsOn(
sharedExtensionPatch,
restoreOldVideoQualityMenuResourcePatch,
lithoFilterPatch,
recyclerViewTreeHookPatch,
)
compatibleWith(
"com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
),
)
execute {
// region Patch for the old type of the video quality menu.
// Used for regular videos when spoofing to old app version,
// and for the Shorts quality flyout on newer app versions.
videoQualityMenuViewInflateFingerprint.method.apply {
val checkCastIndex = videoQualityMenuViewInflateFingerprint.patternMatch!!.endIndex
val listViewRegister = getInstruction<OneRegisterInstruction>(checkCastIndex).registerA
addInstruction(
checkCastIndex + 1,
"invoke-static { v$listViewRegister }, " +
"$EXTENSION_CLASS_DESCRIPTOR->" +
"showOldVideoQualityMenu(Landroid/widget/ListView;)V",
)
}
// Force YT to add the 'advanced' quality menu for Shorts.
val patternMatch = videoQualityMenuOptionsFingerprint.patternMatch!!
val startIndex = patternMatch.startIndex
if (startIndex != 0) throw PatchException("Unexpected opcode start index: $startIndex")
val insertIndex = patternMatch.endIndex
videoQualityMenuOptionsFingerprint.method.apply {
val register = getInstruction<OneRegisterInstruction>(insertIndex).registerA
// A condition controls whether to show the three or four items quality menu.
// Force the four items quality menu to make the "Advanced" item visible, necessary for the patch.
addInstructions(
insertIndex,
"""
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->forceAdvancedVideoQualityMenuCreation(Z)Z
move-result v$register
""",
)
}
// endregion
// region Patch for the new type of the video quality menu.
addRecyclerViewTreeHook(EXTENSION_CLASS_DESCRIPTOR)
// Required to check if the video quality menu is currently shown in order to click on the "Advanced" item.
addLithoFilter(FILTER_CLASS_DESCRIPTOR)
// endregion
}
}

View File

@ -1257,8 +1257,6 @@ Swipe to expand or close"</string>
<string name="revanced_gradient_loading_screen_title">Enable gradient loading screen</string> <string name="revanced_gradient_loading_screen_title">Enable gradient loading screen</string>
<string name="revanced_gradient_loading_screen_summary_on">Loading screen will have a gradient background</string> <string name="revanced_gradient_loading_screen_summary_on">Loading screen will have a gradient background</string>
<string name="revanced_gradient_loading_screen_summary_off">Loading screen will have a solid background</string> <string name="revanced_gradient_loading_screen_summary_off">Loading screen will have a solid background</string>
</patch>
<patch id="layout.theme.themeResourcePatch">
<string name="revanced_seekbar_custom_color_title">Enable custom seekbar color</string> <string name="revanced_seekbar_custom_color_title">Enable custom seekbar color</string>
<string name="revanced_seekbar_custom_color_summary_on">Custom seekbar color is shown</string> <string name="revanced_seekbar_custom_color_summary_on">Custom seekbar color is shown</string>
<string name="revanced_seekbar_custom_color_summary_off">Original seekbar color is shown</string> <string name="revanced_seekbar_custom_color_summary_off">Original seekbar color is shown</string>
@ -1373,7 +1371,6 @@ Enabling this can unlock higher video qualities"</string>
</patch> </patch>
<patch id="video.quality.rememberVideoQualityPatch"> <patch id="video.quality.rememberVideoQualityPatch">
<!-- Translations should use the same text as revanced_custom_playback_speeds_auto --> <!-- Translations should use the same text as revanced_custom_playback_speeds_auto -->
<string name="revanced_video_quality_screen_title">Video quality</string>
<string name="revanced_video_quality_default_entry_1">Auto</string> <string name="revanced_video_quality_default_entry_1">Auto</string>
<string name="revanced_remember_video_quality_last_selected_title">Remember video quality changes</string> <string name="revanced_remember_video_quality_last_selected_title">Remember video quality changes</string>
<string name="revanced_remember_video_quality_last_selected_summary_on">Quality changes apply to all videos</string> <string name="revanced_remember_video_quality_last_selected_summary_on">Quality changes apply to all videos</string>
@ -1381,8 +1378,8 @@ Enabling this can unlock higher video qualities"</string>
<string name="revanced_video_quality_default_wifi_title">Default video quality on Wi-Fi network</string> <string name="revanced_video_quality_default_wifi_title">Default video quality on Wi-Fi network</string>
<string name="revanced_video_quality_default_mobile_title">Default video quality on mobile network</string> <string name="revanced_video_quality_default_mobile_title">Default video quality on mobile network</string>
<string name="revanced_remember_shorts_quality_last_selected_title">Remember Shorts quality changes</string> <string name="revanced_remember_shorts_quality_last_selected_title">Remember Shorts quality changes</string>
<string name="revanced_remember_shorts_quality_last_selected_summary_on">Quality changes apply to all Shorts videos</string> <string name="revanced_remember_shorts_quality_last_selected_summary_on">Quality changes apply to all Shorts</string>
<string name="revanced_remember_shorts_quality_last_selected_summary_off">Quality changes only apply to the current Shorts video</string> <string name="revanced_remember_shorts_quality_last_selected_summary_off">Quality changes only apply to the current Short</string>
<string name="revanced_shorts_quality_default_wifi_title">Default Shorts quality on Wi-Fi network</string> <string name="revanced_shorts_quality_default_wifi_title">Default Shorts quality on Wi-Fi network</string>
<string name="revanced_shorts_quality_default_mobile_title">Default Shorts quality on mobile network</string> <string name="revanced_shorts_quality_default_mobile_title">Default Shorts quality on mobile network</string>
<string name="revanced_remember_video_quality_mobile">mobile</string> <string name="revanced_remember_video_quality_mobile">mobile</string>
@ -1419,10 +1416,10 @@ Enabling this can unlock higher video qualities"</string>
<string name="revanced_disable_hdr_video_summary_on">HDR video is disabled</string> <string name="revanced_disable_hdr_video_summary_on">HDR video is disabled</string>
<string name="revanced_disable_hdr_video_summary_off">HDR video is enabled</string> <string name="revanced_disable_hdr_video_summary_off">HDR video is enabled</string>
</patch> </patch>
<patch id="video.videoqualitymenu.restoreOldVideoQualityMenuResourcePatch"> <patch id="video.quality.advancedVideoQualityMenuPatch">
<string name="revanced_restore_old_video_quality_menu_title">Restore old video quality menu</string> <string name="revanced_advanced_video_quality_menu_title">Show advanced video quality menu</string>
<string name="revanced_restore_old_video_quality_menu_summary_on">Old video quality menu is shown</string> <string name="revanced_advanced_video_quality_menu_summary_on">Advanced video quality menu is shown</string>
<string name="revanced_restore_old_video_quality_menu_summary_off">Old video quality menu is not shown</string> <string name="revanced_advanced_video_quality_menu_summary_off">Advanced video quality menu is not shown</string>
</patch> </patch>
<patch id="interaction.seekbar.enableSlideToSeekPatch"> <patch id="interaction.seekbar.enableSlideToSeekPatch">
<string name="revanced_slide_to_seek_title">Enable slide to seek</string> <string name="revanced_slide_to_seek_title">Enable slide to seek</string>