From cf3116a7583d09c25c798a85687a056f143656f0 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Sun, 8 Dec 2024 16:19:29 +0100 Subject: [PATCH] feat(YouTube Music): Add `Spoof video streams` patch to fix playback (#4065) Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> --- .../shared/settings/BaseSettings.java | 11 +- .../extension/shared}/spoof/ClientType.java | 6 +- .../shared}/spoof/DeviceHardwareSupport.java | 6 +- .../shared}/spoof/SpoofVideoStreamsPatch.java | 23 +- .../shared}/spoof/requests/PlayerRoutes.java | 4 +- .../spoof/requests/StreamingDataRequest.java | 9 +- .../patches/FullscreenPanelsRemoverPatch.java | 12 - .../extension/youtube/settings/Settings.java | 256 +++++++++--------- .../ForceAVCSpoofingPreference.java | 5 +- patches/api/patches.api | 17 ++ .../music/misc/gms/GmsCoreSupportPatch.kt | 3 + .../misc/spoof/SpoofVideoStreamsPatch.kt | 7 + .../misc/spoof}/Fingerprints.kt | 3 +- .../misc/spoof/SpoofVideoStreamsPatch.kt | 206 ++++++++++++++ .../fix/playback/SpoofVideoStreamsPatch.kt | 242 +---------------- .../fix/playback/UserAgentClientSpoofPatch.kt | 81 +----- .../youtube/misc/gms/GmsCoreSupportPatch.kt | 2 +- .../misc/spoof/SpoofVideoStreamsPatch.kt | 52 ++++ .../misc/spoof/UserAgentClientSpoofPatch.kt | 82 ++++++ 19 files changed, 543 insertions(+), 484 deletions(-) rename extensions/{youtube/src/main/java/app/revanced/extension/youtube/patches => shared/library/src/main/java/app/revanced/extension/shared}/spoof/ClientType.java (92%) rename extensions/{youtube/src/main/java/app/revanced/extension/youtube/patches => shared/library/src/main/java/app/revanced/extension/shared}/spoof/DeviceHardwareSupport.java (90%) rename extensions/{youtube/src/main/java/app/revanced/extension/youtube/patches => shared/library/src/main/java/app/revanced/extension/shared}/spoof/SpoofVideoStreamsPatch.java (93%) rename extensions/{youtube/src/main/java/app/revanced/extension/youtube/patches => shared/library/src/main/java/app/revanced/extension/shared}/spoof/requests/PlayerRoutes.java (95%) rename extensions/{youtube/src/main/java/app/revanced/extension/youtube/patches => shared/library/src/main/java/app/revanced/extension/shared}/spoof/requests/StreamingDataRequest.java (96%) delete mode 100644 extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/FullscreenPanelsRemoverPatch.java create mode 100644 patches/src/main/kotlin/app/revanced/patches/music/misc/spoof/SpoofVideoStreamsPatch.kt rename patches/src/main/kotlin/app/revanced/patches/{youtube/misc/fix/playback => shared/misc/spoof}/Fingerprints.kt (97%) create mode 100644 patches/src/main/kotlin/app/revanced/patches/shared/misc/spoof/SpoofVideoStreamsPatch.kt create mode 100644 patches/src/main/kotlin/app/revanced/patches/youtube/misc/spoof/SpoofVideoStreamsPatch.kt create mode 100644 patches/src/main/kotlin/app/revanced/patches/youtube/misc/spoof/UserAgentClientSpoofPatch.kt diff --git a/extensions/shared/library/src/main/java/app/revanced/extension/shared/settings/BaseSettings.java b/extensions/shared/library/src/main/java/app/revanced/extension/shared/settings/BaseSettings.java index 13be9547ca..a5b558acde 100644 --- a/extensions/shared/library/src/main/java/app/revanced/extension/shared/settings/BaseSettings.java +++ b/extensions/shared/library/src/main/java/app/revanced/extension/shared/settings/BaseSettings.java @@ -1,12 +1,15 @@ package app.revanced.extension.shared.settings; +import app.revanced.extension.shared.spoof.ClientType; +import app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch; + import static java.lang.Boolean.FALSE; import static java.lang.Boolean.TRUE; import static app.revanced.extension.shared.settings.Setting.parent; /** * Settings shared across multiple apps. - * + *

* To ensure this class is loaded when the UI is created, app specific setting bundles should extend * or reference this class. */ @@ -16,4 +19,10 @@ public class BaseSettings { public static final BooleanSetting DEBUG_TOAST_ON_ERROR = new BooleanSetting("revanced_debug_toast_on_error", TRUE, "revanced_debug_toast_on_error_user_dialog_message"); public static final IntegerSetting CHECK_ENVIRONMENT_WARNINGS_ISSUED = new IntegerSetting("revanced_check_environment_warnings_issued", 0, true, false); + + public static final BooleanSetting SPOOF_VIDEO_STREAMS = new BooleanSetting("revanced_spoof_video_streams", TRUE, true, "revanced_spoof_video_streams_user_dialog_message"); + public static final BooleanSetting SPOOF_VIDEO_STREAMS_IOS_FORCE_AVC = new BooleanSetting("revanced_spoof_video_streams_ios_force_avc", FALSE, true, + "revanced_spoof_video_streams_ios_force_avc_user_dialog_message", new SpoofVideoStreamsPatch.ForceiOSAVCAvailability()); + public static final EnumSetting SPOOF_VIDEO_STREAMS_CLIENT_TYPE = new EnumSetting<>("revanced_spoof_video_streams_client", ClientType.ANDROID_VR, true, parent(SPOOF_VIDEO_STREAMS)); + } diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/spoof/ClientType.java b/extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/ClientType.java similarity index 92% rename from extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/spoof/ClientType.java rename to extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/ClientType.java index b29d665b48..93a7815024 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/spoof/ClientType.java +++ b/extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/ClientType.java @@ -1,7 +1,7 @@ -package app.revanced.extension.youtube.patches.spoof; +package app.revanced.extension.shared.spoof; -import static app.revanced.extension.youtube.patches.spoof.DeviceHardwareSupport.allowAV1; -import static app.revanced.extension.youtube.patches.spoof.DeviceHardwareSupport.allowVP9; +import static app.revanced.extension.shared.spoof.DeviceHardwareSupport.allowAV1; +import static app.revanced.extension.shared.spoof.DeviceHardwareSupport.allowVP9; import android.os.Build; diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/spoof/DeviceHardwareSupport.java b/extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/DeviceHardwareSupport.java similarity index 90% rename from extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/spoof/DeviceHardwareSupport.java rename to extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/DeviceHardwareSupport.java index 3adc6befb3..019a13eeb7 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/spoof/DeviceHardwareSupport.java +++ b/extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/DeviceHardwareSupport.java @@ -1,11 +1,11 @@ -package app.revanced.extension.youtube.patches.spoof; +package app.revanced.extension.shared.spoof; import android.media.MediaCodecInfo; import android.media.MediaCodecList; import android.os.Build; import app.revanced.extension.shared.Logger; -import app.revanced.extension.youtube.settings.Settings; +import app.revanced.extension.shared.settings.BaseSettings; public class DeviceHardwareSupport { public static final boolean DEVICE_HAS_HARDWARE_DECODING_VP9; @@ -44,7 +44,7 @@ public class DeviceHardwareSupport { } public static boolean allowVP9() { - return DEVICE_HAS_HARDWARE_DECODING_VP9 && !Settings.SPOOF_VIDEO_STREAMS_IOS_FORCE_AVC.get(); + return DEVICE_HAS_HARDWARE_DECODING_VP9 && !BaseSettings.SPOOF_VIDEO_STREAMS_IOS_FORCE_AVC.get(); } public static boolean allowAV1() { diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/spoof/SpoofVideoStreamsPatch.java b/extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/SpoofVideoStreamsPatch.java similarity index 93% rename from extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/spoof/SpoofVideoStreamsPatch.java rename to extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/SpoofVideoStreamsPatch.java index b50e3f4ffa..1381a9ba51 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/spoof/SpoofVideoStreamsPatch.java +++ b/extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/SpoofVideoStreamsPatch.java @@ -1,4 +1,4 @@ -package app.revanced.extension.youtube.patches.spoof; +package app.revanced.extension.shared.spoof; import android.net.Uri; @@ -12,20 +12,12 @@ import app.revanced.extension.shared.Utils; import app.revanced.extension.shared.settings.BaseSettings; import app.revanced.extension.shared.settings.Setting; -import app.revanced.extension.youtube.patches.spoof.requests.StreamingDataRequest; -import app.revanced.extension.youtube.settings.Settings; +import app.revanced.extension.shared.spoof.requests.StreamingDataRequest; +import app.revanced.extension.shared.settings.BaseSettings; @SuppressWarnings("unused") public class SpoofVideoStreamsPatch { - public static final class ForceiOSAVCAvailability implements Setting.Availability { - @Override - public boolean isAvailable() { - return Settings.SPOOF_VIDEO_STREAMS.get() && Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get() == ClientType.IOS; - } - } - - private static final boolean SPOOF_STREAMING_DATA = Settings.SPOOF_VIDEO_STREAMS.get(); - + private static final boolean SPOOF_STREAMING_DATA = BaseSettings.SPOOF_VIDEO_STREAMS.get(); /** * Any unreachable ip address. Used to intentionally fail requests. */ @@ -165,4 +157,11 @@ public static byte[] removeVideoPlaybackPostBody(Uri uri, int method, byte[] pos return postData; } + + public static final class ForceiOSAVCAvailability implements Setting.Availability { + @Override + public boolean isAvailable() { + return BaseSettings.SPOOF_VIDEO_STREAMS.get() && BaseSettings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get() == ClientType.IOS; + } + } } diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/spoof/requests/PlayerRoutes.java b/extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/requests/PlayerRoutes.java similarity index 95% rename from extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/spoof/requests/PlayerRoutes.java rename to extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/requests/PlayerRoutes.java index f77288ccc3..fa5cc18558 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/spoof/requests/PlayerRoutes.java +++ b/extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/requests/PlayerRoutes.java @@ -1,4 +1,4 @@ -package app.revanced.extension.youtube.patches.spoof.requests; +package app.revanced.extension.shared.spoof.requests; import org.json.JSONException; import org.json.JSONObject; @@ -10,7 +10,7 @@ import app.revanced.extension.shared.Utils; import app.revanced.extension.shared.requests.Requester; import app.revanced.extension.shared.requests.Route; -import app.revanced.extension.youtube.patches.spoof.ClientType; +import app.revanced.extension.shared.spoof.ClientType; final class PlayerRoutes { static final Route.CompiledRoute GET_STREAMING_DATA = new Route( diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/spoof/requests/StreamingDataRequest.java b/extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/requests/StreamingDataRequest.java similarity index 96% rename from extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/spoof/requests/StreamingDataRequest.java rename to extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/requests/StreamingDataRequest.java index 0c09e0fa76..8853722303 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/spoof/requests/StreamingDataRequest.java +++ b/extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/requests/StreamingDataRequest.java @@ -1,6 +1,6 @@ -package app.revanced.extension.youtube.patches.spoof.requests; +package app.revanced.extension.shared.spoof.requests; -import static app.revanced.extension.youtube.patches.spoof.requests.PlayerRoutes.GET_STREAMING_DATA; +import static app.revanced.extension.shared.spoof.requests.PlayerRoutes.GET_STREAMING_DATA; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -22,8 +22,7 @@ import app.revanced.extension.shared.Logger; import app.revanced.extension.shared.Utils; import app.revanced.extension.shared.settings.BaseSettings; -import app.revanced.extension.youtube.patches.spoof.ClientType; -import app.revanced.extension.youtube.settings.Settings; +import app.revanced.extension.shared.spoof.ClientType; /** * Video streaming data. Fetching is tied to the behavior YT uses, @@ -70,7 +69,7 @@ protected boolean removeEldestEntry(Entry eldest) { static { ClientType[] allClientTypes = ClientType.values(); - ClientType preferredClient = Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get(); + ClientType preferredClient = BaseSettings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get(); CLIENT_ORDER_TO_USE = new ClientType[allClientTypes.length]; CLIENT_ORDER_TO_USE[0] = preferredClient; diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/FullscreenPanelsRemoverPatch.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/FullscreenPanelsRemoverPatch.java deleted file mode 100644 index f454b361c0..0000000000 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/FullscreenPanelsRemoverPatch.java +++ /dev/null @@ -1,12 +0,0 @@ -package app.revanced.extension.youtube.patches; - -import android.view.View; - -import app.revanced.extension.youtube.settings.Settings; - -@SuppressWarnings("unused") -public class FullscreenPanelsRemoverPatch { - public static int getFullscreenPanelsVisibility() { - return Settings.HIDE_FULLSCREEN_PANELS.get() ? View.GONE : View.VISIBLE; - } -} diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/Settings.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/Settings.java index 4f11de9284..fb3c199c98 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/Settings.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/Settings.java @@ -2,25 +2,42 @@ import static java.lang.Boolean.FALSE; import static java.lang.Boolean.TRUE; -import static app.revanced.extension.shared.settings.Setting.*; +import static app.revanced.extension.shared.settings.Setting.Availability; +import static app.revanced.extension.shared.settings.Setting.migrateFromOldPreferences; +import static app.revanced.extension.shared.settings.Setting.migrateOldSettingToNew; +import static app.revanced.extension.shared.settings.Setting.parent; +import static app.revanced.extension.shared.settings.Setting.parentsAny; import static app.revanced.extension.youtube.patches.ChangeStartPagePatch.StartPage; import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerHideExpandCloseAvailability; import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerHorizontalDragAvailability; import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerType; -import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerType.*; +import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerType.MINIMAL; +import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerType.MODERN_1; +import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerType.MODERN_2; +import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerType.MODERN_3; +import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerType.MODERN_4; +import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerType.PHONE; import static app.revanced.extension.youtube.patches.SeekbarThumbnailsPatch.SeekbarThumbnailsHighQualityAvailability; import static app.revanced.extension.youtube.patches.VersionCheckPatch.IS_19_17_OR_GREATER; -import static app.revanced.extension.youtube.sponsorblock.objects.CategoryBehaviour.*; +import static app.revanced.extension.youtube.sponsorblock.objects.CategoryBehaviour.IGNORE; +import static app.revanced.extension.youtube.sponsorblock.objects.CategoryBehaviour.MANUAL_SKIP; +import static app.revanced.extension.youtube.sponsorblock.objects.CategoryBehaviour.SKIP_AUTOMATICALLY; +import static app.revanced.extension.youtube.sponsorblock.objects.CategoryBehaviour.SKIP_AUTOMATICALLY_ONCE; import app.revanced.extension.shared.Logger; -import app.revanced.extension.shared.settings.*; +import app.revanced.extension.shared.settings.BaseSettings; +import app.revanced.extension.shared.settings.BooleanSetting; +import app.revanced.extension.shared.settings.EnumSetting; +import app.revanced.extension.shared.settings.FloatSetting; +import app.revanced.extension.shared.settings.IntegerSetting; +import app.revanced.extension.shared.settings.LongSetting; +import app.revanced.extension.shared.settings.Setting; +import app.revanced.extension.shared.settings.StringSetting; import app.revanced.extension.shared.settings.preference.SharedPrefCategory; import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.DeArrowAvailability; import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.StillImagesAvailability; import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.ThumbnailOption; import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.ThumbnailStillTime; -import app.revanced.extension.youtube.patches.spoof.ClientType; -import app.revanced.extension.youtube.patches.spoof.SpoofVideoStreamsPatch; import app.revanced.extension.youtube.sponsorblock.SponsorBlockSettings; public class Settings extends BaseSettings { @@ -37,17 +54,17 @@ public class Settings extends BaseSettings { "0.25\n0.5\n0.75\n0.9\n0.95\n1.0\n1.05\n1.1\n1.25\n1.5\n1.75\n2.0\n3.0\n4.0\n5.0", true); // Ads - public static final BooleanSetting HIDE_FULLSCREEN_ADS = new BooleanSetting("revanced_hide_fullscreen_ads", TRUE); public static final BooleanSetting HIDE_BUTTONED_ADS = new BooleanSetting("revanced_hide_buttoned_ads", TRUE); + public static final BooleanSetting HIDE_FULLSCREEN_ADS = new BooleanSetting("revanced_hide_fullscreen_ads", TRUE); public static final BooleanSetting HIDE_GENERAL_ADS = new BooleanSetting("revanced_hide_general_ads", TRUE); public static final BooleanSetting HIDE_GET_PREMIUM = new BooleanSetting("revanced_hide_get_premium", TRUE); public static final BooleanSetting HIDE_HIDE_LATEST_POSTS = new BooleanSetting("revanced_hide_latest_posts_ads", TRUE); public static final BooleanSetting HIDE_MERCHANDISE_BANNERS = new BooleanSetting("revanced_hide_merchandise_banners", TRUE); public static final BooleanSetting HIDE_PAID_PROMOTION_LABEL = new BooleanSetting("revanced_hide_paid_promotion_label", TRUE); - public static final BooleanSetting HIDE_PRODUCTS_BANNER = new BooleanSetting("revanced_hide_products_banner", TRUE); public static final BooleanSetting HIDE_PLAYER_STORE_SHELF = new BooleanSetting("revanced_hide_player_store_shelf", TRUE); - public static final BooleanSetting HIDE_SHOPPING_LINKS = new BooleanSetting("revanced_hide_shopping_links", TRUE); + public static final BooleanSetting HIDE_PRODUCTS_BANNER = new BooleanSetting("revanced_hide_products_banner", TRUE); public static final BooleanSetting HIDE_SELF_SPONSOR = new BooleanSetting("revanced_hide_self_sponsor_ads", TRUE); + public static final BooleanSetting HIDE_SHOPPING_LINKS = new BooleanSetting("revanced_hide_shopping_links", TRUE); public static final BooleanSetting HIDE_VIDEO_ADS = new BooleanSetting("revanced_hide_video_ads", TRUE, true); public static final BooleanSetting HIDE_VISIT_STORE_BUTTON = new BooleanSetting("revanced_hide_visit_store_button", TRUE); public static final BooleanSetting HIDE_WEB_SEARCH_RESULTS = new BooleanSetting("revanced_hide_web_search_results", TRUE); @@ -55,9 +72,27 @@ public class Settings extends BaseSettings { // Feed public static final BooleanSetting HIDE_ALBUM_CARDS = new BooleanSetting("revanced_hide_album_cards", FALSE, true); public static final BooleanSetting HIDE_ARTIST_CARDS = new BooleanSetting("revanced_hide_artist_cards", FALSE); - public static final BooleanSetting HIDE_EXPANDABLE_CHIP = new BooleanSetting("revanced_hide_expandable_chip", TRUE); + public static final BooleanSetting HIDE_CHIPS_SHELF = new BooleanSetting("revanced_hide_chips_shelf", TRUE); + public static final BooleanSetting HIDE_COMMUNITY_POSTS = new BooleanSetting("revanced_hide_community_posts", FALSE); + public static final BooleanSetting HIDE_COMPACT_BANNER = new BooleanSetting("revanced_hide_compact_banner", TRUE); + public static final BooleanSetting HIDE_CROWDFUNDING_BOX = new BooleanSetting("revanced_hide_crowdfunding_box", FALSE, true); public static final BooleanSetting HIDE_DOODLES = new BooleanSetting("revanced_hide_doodles", FALSE, true, "revanced_hide_doodles_user_dialog_message"); - + public static final BooleanSetting HIDE_EXPANDABLE_CHIP = new BooleanSetting("revanced_hide_expandable_chip", TRUE); + public static final BooleanSetting HIDE_FEED_SURVEY = new BooleanSetting("revanced_hide_feed_survey", TRUE); + public static final BooleanSetting HIDE_FILTER_BAR_FEED_IN_FEED = new BooleanSetting("revanced_hide_filter_bar_feed_in_feed", FALSE, true); + public static final BooleanSetting HIDE_FILTER_BAR_FEED_IN_RELATED_VIDEOS = new BooleanSetting("revanced_hide_filter_bar_feed_in_related_videos", FALSE, true); + public static final BooleanSetting HIDE_FILTER_BAR_FEED_IN_SEARCH = new BooleanSetting("revanced_hide_filter_bar_feed_in_search", FALSE, true); + public static final BooleanSetting HIDE_FLOATING_MICROPHONE_BUTTON = new BooleanSetting("revanced_hide_floating_microphone_button", TRUE, true); + public static final BooleanSetting HIDE_FOR_YOU_SHELF = new BooleanSetting("revanced_hide_for_you_shelf", TRUE); + public static final BooleanSetting HIDE_HORIZONTAL_SHELVES = new BooleanSetting("revanced_hide_horizontal_shelves", TRUE); + public static final BooleanSetting HIDE_IMAGE_SHELF = new BooleanSetting("revanced_hide_image_shelf", TRUE); + public static final BooleanSetting HIDE_MIX_PLAYLISTS = new BooleanSetting("revanced_hide_mix_playlists", TRUE); + public static final BooleanSetting HIDE_MOVIES_SECTION = new BooleanSetting("revanced_hide_movies_section", TRUE); + public static final BooleanSetting HIDE_NOTIFY_ME_BUTTON = new BooleanSetting("revanced_hide_notify_me_button", TRUE); + public static final BooleanSetting HIDE_PLAYABLES = new BooleanSetting("revanced_hide_playables", TRUE); + public static final BooleanSetting HIDE_SEARCH_RESULT_RECOMMENDATIONS = new BooleanSetting("revanced_hide_search_result_recommendations", TRUE); + public static final BooleanSetting HIDE_SEARCH_RESULT_SHELF_HEADER = new BooleanSetting("revanced_hide_search_result_shelf_header", FALSE); + public static final BooleanSetting HIDE_SHOW_MORE_BUTTON = new BooleanSetting("revanced_hide_show_more_button", TRUE, true); // Alternative thumbnails public static final EnumSetting ALT_THUMBNAIL_HOME = new EnumSetting<>("revanced_alt_thumbnail_home", ThumbnailOption.ORIGINAL); public static final EnumSetting ALT_THUMBNAIL_SUBSCRIPTIONS = new EnumSetting<>("revanced_alt_thumbnail_subscription", ThumbnailOption.ORIGINAL); @@ -69,7 +104,6 @@ public class Settings extends BaseSettings { public static final BooleanSetting ALT_THUMBNAIL_DEARROW_CONNECTION_TOAST = new BooleanSetting("revanced_alt_thumbnail_dearrow_connection_toast", TRUE, new DeArrowAvailability()); public static final EnumSetting ALT_THUMBNAIL_STILLS_TIME = new EnumSetting<>("revanced_alt_thumbnail_stills_time", ThumbnailStillTime.MIDDLE, new StillImagesAvailability()); public static final BooleanSetting ALT_THUMBNAIL_STILLS_FAST = new BooleanSetting("revanced_alt_thumbnail_stills_fast", FALSE, new StillImagesAvailability()); - // Hide keyword content public static final BooleanSetting HIDE_KEYWORD_CONTENT_HOME = new BooleanSetting("revanced_hide_keyword_content_home", FALSE); public static final BooleanSetting HIDE_KEYWORD_CONTENT_SUBSCRIPTIONS = new BooleanSetting("revanced_hide_keyword_content_subscriptions", FALSE); @@ -77,61 +111,35 @@ public class Settings extends BaseSettings { public static final StringSetting HIDE_KEYWORD_CONTENT_PHRASES = new StringSetting("revanced_hide_keyword_content_phrases", "", parentsAny(HIDE_KEYWORD_CONTENT_HOME, HIDE_KEYWORD_CONTENT_SUBSCRIPTIONS, HIDE_KEYWORD_CONTENT_SEARCH)); - // Uncategorized layout related settings. Do not add to this section, and instead move these out and categorize them. + // Player + public static final BooleanSetting COPY_VIDEO_URL = new BooleanSetting("revanced_copy_video_url", FALSE); + public static final BooleanSetting COPY_VIDEO_URL_TIMESTAMP = new BooleanSetting("revanced_copy_video_url_timestamp", TRUE); + public static final BooleanSetting DISABLE_FULLSCREEN_AMBIENT_MODE = new BooleanSetting("revanced_disable_fullscreen_ambient_mode", TRUE, true); + public static final BooleanSetting DISABLE_LIKE_SUBSCRIBE_GLOW = new BooleanSetting("revanced_disable_like_subscribe_glow", FALSE); + public static final BooleanSetting DISABLE_ROLLING_NUMBER_ANIMATIONS = new BooleanSetting("revanced_disable_rolling_number_animations", FALSE); public static final BooleanSetting DISABLE_SUGGESTED_VIDEO_END_SCREEN = new BooleanSetting("revanced_disable_suggested_video_end_screen", FALSE, true); - public static final BooleanSetting GRADIENT_LOADING_SCREEN = new BooleanSetting("revanced_gradient_loading_screen", FALSE, true); - public static final BooleanSetting HIDE_HORIZONTAL_SHELVES = new BooleanSetting("revanced_hide_horizontal_shelves", TRUE); + public static final BooleanSetting HIDE_AUTOPLAY_BUTTON = new BooleanSetting("revanced_hide_autoplay_button", TRUE, true); public static final BooleanSetting HIDE_CAPTIONS_BUTTON = new BooleanSetting("revanced_hide_captions_button", FALSE); + public static final BooleanSetting HIDE_CAST_BUTTON = new BooleanSetting("revanced_hide_cast_button", TRUE, true); public static final BooleanSetting HIDE_CHANNEL_BAR = new BooleanSetting("revanced_hide_channel_bar", FALSE); public static final BooleanSetting HIDE_CHANNEL_MEMBER_SHELF = new BooleanSetting("revanced_hide_channel_member_shelf", TRUE); - public static final BooleanSetting HIDE_CHIPS_SHELF = new BooleanSetting("revanced_hide_chips_shelf", TRUE); public static final BooleanSetting HIDE_COMMUNITY_GUIDELINES = new BooleanSetting("revanced_hide_community_guidelines", TRUE); - public static final BooleanSetting HIDE_COMMUNITY_POSTS = new BooleanSetting("revanced_hide_community_posts", FALSE); - public static final BooleanSetting HIDE_COMPACT_BANNER = new BooleanSetting("revanced_hide_compact_banner", TRUE); - public static final BooleanSetting HIDE_CROWDFUNDING_BOX = new BooleanSetting("revanced_hide_crowdfunding_box", FALSE, true); public static final BooleanSetting HIDE_EMERGENCY_BOX = new BooleanSetting("revanced_hide_emergency_box", TRUE); public static final BooleanSetting HIDE_ENDSCREEN_CARDS = new BooleanSetting("revanced_hide_endscreen_cards", FALSE); - public static final BooleanSetting HIDE_FEED_SURVEY = new BooleanSetting("revanced_hide_feed_survey", TRUE); - public static final BooleanSetting HIDE_FILTER_BAR_FEED_IN_FEED = new BooleanSetting("revanced_hide_filter_bar_feed_in_feed", FALSE, true); - public static final BooleanSetting HIDE_FILTER_BAR_FEED_IN_RELATED_VIDEOS = new BooleanSetting("revanced_hide_filter_bar_feed_in_related_videos", FALSE, true); - public static final BooleanSetting HIDE_FILTER_BAR_FEED_IN_SEARCH = new BooleanSetting("revanced_hide_filter_bar_feed_in_search", FALSE, true); - public static final BooleanSetting HIDE_FLOATING_MICROPHONE_BUTTON = new BooleanSetting("revanced_hide_floating_microphone_button", TRUE, true); - public static final BooleanSetting HIDE_FULLSCREEN_PANELS = new BooleanSetting("revanced_hide_fullscreen_panels", TRUE, true); public static final BooleanSetting HIDE_HIDE_CHANNEL_GUIDELINES = new BooleanSetting("revanced_hide_channel_guidelines", TRUE); public static final BooleanSetting HIDE_HIDE_INFO_PANELS = new BooleanSetting("revanced_hide_info_panels", TRUE); - public static final BooleanSetting HIDE_IMAGE_SHELF = new BooleanSetting("revanced_hide_image_shelf", TRUE); public static final BooleanSetting HIDE_INFO_CARDS = new BooleanSetting("revanced_hide_info_cards", FALSE); public static final BooleanSetting HIDE_JOIN_MEMBERSHIP_BUTTON = new BooleanSetting("revanced_hide_join_membership_button", TRUE); - public static final BooleanSetting HIDE_SHOW_MORE_BUTTON = new BooleanSetting("revanced_hide_show_more_button", TRUE, true); public static final BooleanSetting HIDE_MEDICAL_PANELS = new BooleanSetting("revanced_hide_medical_panels", TRUE); - public static final BooleanSetting HIDE_MIX_PLAYLISTS = new BooleanSetting("revanced_hide_mix_playlists", TRUE); - public static final BooleanSetting HIDE_MOVIES_SECTION = new BooleanSetting("revanced_hide_movies_section", TRUE); - public static final BooleanSetting HIDE_NOTIFY_ME_BUTTON = new BooleanSetting("revanced_hide_notify_me_button", TRUE); - public static final BooleanSetting HIDE_PLAYABLES = new BooleanSetting("revanced_hide_playables", TRUE); + public static final BooleanSetting HIDE_PLAYER_PREVIOUS_NEXT_BUTTONS = new BooleanSetting("revanced_hide_player_previous_next_buttons", FALSE, true); public static final BooleanSetting HIDE_QUICK_ACTIONS = new BooleanSetting("revanced_hide_quick_actions", FALSE); public static final BooleanSetting HIDE_RELATED_VIDEOS = new BooleanSetting("revanced_hide_related_videos", FALSE); - public static final BooleanSetting HIDE_SEARCH_RESULT_SHELF_HEADER = new BooleanSetting("revanced_hide_search_result_shelf_header", FALSE); public static final BooleanSetting HIDE_SUBSCRIBERS_COMMUNITY_GUIDELINES = new BooleanSetting("revanced_hide_subscribers_community_guidelines", TRUE); public static final BooleanSetting HIDE_TIMED_REACTIONS = new BooleanSetting("revanced_hide_timed_reactions", TRUE); - public static final BooleanSetting HIDE_TIMESTAMP = new BooleanSetting("revanced_hide_timestamp", FALSE); public static final BooleanSetting HIDE_VIDEO_CHANNEL_WATERMARK = new BooleanSetting("revanced_hide_channel_watermark", TRUE); - public static final BooleanSetting HIDE_FOR_YOU_SHELF = new BooleanSetting("revanced_hide_for_you_shelf", TRUE); - public static final BooleanSetting HIDE_SEARCH_RESULT_RECOMMENDATIONS = new BooleanSetting("revanced_hide_search_result_recommendations", TRUE); - public static final IntegerSetting PLAYER_OVERLAY_OPACITY = new IntegerSetting("revanced_player_overlay_opacity",100, true); - public static final BooleanSetting PLAYER_POPUP_PANELS = new BooleanSetting("revanced_hide_player_popup_panels", FALSE); - - // Player - public static final BooleanSetting DISABLE_FULLSCREEN_AMBIENT_MODE = new BooleanSetting("revanced_disable_fullscreen_ambient_mode", TRUE, true); - public static final BooleanSetting DISABLE_ROLLING_NUMBER_ANIMATIONS = new BooleanSetting("revanced_disable_rolling_number_animations", FALSE); - public static final BooleanSetting DISABLE_LIKE_SUBSCRIBE_GLOW = new BooleanSetting("revanced_disable_like_subscribe_glow", FALSE); - public static final BooleanSetting HIDE_AUTOPLAY_BUTTON = new BooleanSetting("revanced_hide_autoplay_button", TRUE, true); - public static final BooleanSetting HIDE_CAST_BUTTON = new BooleanSetting("revanced_hide_cast_button", TRUE, true); - public static final BooleanSetting HIDE_PLAYER_PREVIOUS_NEXT_BUTTONS = new BooleanSetting("revanced_hide_player_previous_next_buttons", FALSE, true); - private static final BooleanSetting DEPRECATED_HIDE_PLAYER_BUTTONS = new BooleanSetting("revanced_hide_player_buttons", FALSE, true); - public static final BooleanSetting COPY_VIDEO_URL = new BooleanSetting("revanced_copy_video_url", FALSE); - public static final BooleanSetting COPY_VIDEO_URL_TIMESTAMP = new BooleanSetting("revanced_copy_video_url_timestamp", TRUE); public static final BooleanSetting PLAYBACK_SPEED_DIALOG_BUTTON = new BooleanSetting("revanced_playback_speed_dialog_button", FALSE); - + public static final BooleanSetting PLAYER_POPUP_PANELS = new BooleanSetting("revanced_hide_player_popup_panels", FALSE); + public static final IntegerSetting PLAYER_OVERLAY_OPACITY = new IntegerSetting("revanced_player_overlay_opacity", 100, true); // Miniplayer public static final EnumSetting MINIPLAYER_TYPE = new EnumSetting<>("revanced_miniplayer_type", MiniplayerType.ORIGINAL, true); private static final Availability MINIPLAYER_ANY_MODERN = MINIPLAYER_TYPE.availability(MODERN_1, MODERN_2, MODERN_3, MODERN_4); @@ -144,21 +152,18 @@ public class Settings extends BaseSettings { 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); public static final IntegerSetting MINIPLAYER_OPACITY = new IntegerSetting("revanced_miniplayer_opacity", 100, true, MINIPLAYER_TYPE.availability(MODERN_1)); - // External downloader public static final BooleanSetting EXTERNAL_DOWNLOADER = new BooleanSetting("revanced_external_downloader", FALSE); public static final BooleanSetting EXTERNAL_DOWNLOADER_ACTION_BUTTON = new BooleanSetting("revanced_external_downloader_action_button", FALSE); public static final StringSetting EXTERNAL_DOWNLOADER_PACKAGE_NAME = new StringSetting("revanced_external_downloader_name", "org.schabi.newpipe" /* NewPipe */, parentsAny(EXTERNAL_DOWNLOADER, EXTERNAL_DOWNLOADER_ACTION_BUTTON)); - // Comments public static final BooleanSetting HIDE_COMMENTS_BY_MEMBERS_HEADER = new BooleanSetting("revanced_hide_comments_by_members_header", FALSE); - public static final BooleanSetting HIDE_COMMENTS_SECTION = new BooleanSetting("revanced_hide_comments_section", FALSE); public static final BooleanSetting HIDE_COMMENTS_CREATE_A_SHORT_BUTTON = new BooleanSetting("revanced_hide_comments_create_a_short_button", TRUE); public static final BooleanSetting HIDE_COMMENTS_PREVIEW_COMMENT = new BooleanSetting("revanced_hide_comments_preview_comment", FALSE); + public static final BooleanSetting HIDE_COMMENTS_SECTION = new BooleanSetting("revanced_hide_comments_section", FALSE); public static final BooleanSetting HIDE_COMMENTS_THANKS_BUTTON = new BooleanSetting("revanced_hide_comments_thanks_button", TRUE); public static final BooleanSetting HIDE_COMMENTS_TIMESTAMP_AND_EMOJI_BUTTONS = new BooleanSetting("revanced_hide_comments_timestamp_and_emoji_buttons", TRUE); - // Description public static final BooleanSetting HIDE_ATTRIBUTES_SECTION = new BooleanSetting("revanced_hide_attributes_section", FALSE); public static final BooleanSetting HIDE_CHAPTERS_SECTION = new BooleanSetting("revanced_hide_chapters_section", TRUE); @@ -166,47 +171,43 @@ public class Settings extends BaseSettings { public static final BooleanSetting HIDE_KEY_CONCEPTS_SECTION = new BooleanSetting("revanced_hide_key_concepts_section", FALSE); public static final BooleanSetting HIDE_PODCAST_SECTION = new BooleanSetting("revanced_hide_podcast_section", TRUE); public static final BooleanSetting HIDE_TRANSCRIPT_SECTION = new BooleanSetting("revanced_hide_transcript_section", TRUE); - // Action buttons + public static final BooleanSetting HIDE_CLIP_BUTTON = new BooleanSetting("revanced_hide_clip_button", TRUE); + public static final BooleanSetting HIDE_DOWNLOAD_BUTTON = new BooleanSetting("revanced_hide_download_button", FALSE); public static final BooleanSetting HIDE_LIKE_DISLIKE_BUTTON = new BooleanSetting("revanced_hide_like_dislike_button", FALSE); - public static final BooleanSetting HIDE_SHARE_BUTTON = new BooleanSetting("revanced_hide_share_button", FALSE); - public static final BooleanSetting HIDE_REPORT_BUTTON = new BooleanSetting("revanced_hide_report_button", FALSE); + public static final BooleanSetting HIDE_PLAYLIST_BUTTON = new BooleanSetting("revanced_hide_playlist_button", FALSE); public static final BooleanSetting HIDE_REMIX_BUTTON = new BooleanSetting("revanced_hide_remix_button", TRUE); - public static final BooleanSetting HIDE_DOWNLOAD_BUTTON = new BooleanSetting("revanced_hide_download_button", FALSE); + public static final BooleanSetting HIDE_REPORT_BUTTON = new BooleanSetting("revanced_hide_report_button", FALSE); + public static final BooleanSetting HIDE_SHARE_BUTTON = new BooleanSetting("revanced_hide_share_button", FALSE); public static final BooleanSetting HIDE_THANKS_BUTTON = new BooleanSetting("revanced_hide_thanks_button", TRUE); - public static final BooleanSetting HIDE_CLIP_BUTTON = new BooleanSetting("revanced_hide_clip_button", TRUE); - public static final BooleanSetting HIDE_PLAYLIST_BUTTON = new BooleanSetting("revanced_hide_playlist_button", FALSE); - // Player flyout menu items - public static final BooleanSetting HIDE_PLAYER_FLYOUT_CAPTIONS = new BooleanSetting("revanced_hide_player_flyout_captions", FALSE); public static final BooleanSetting HIDE_PLAYER_FLYOUT_ADDITIONAL_SETTINGS = new BooleanSetting("revanced_hide_player_flyout_additional_settings", FALSE); - public static final BooleanSetting HIDE_PLAYER_FLYOUT_LOOP_VIDEO = new BooleanSetting("revanced_hide_player_flyout_loop_video", FALSE); public static final BooleanSetting HIDE_PLAYER_FLYOUT_AMBIENT_MODE = new BooleanSetting("revanced_hide_player_flyout_ambient_mode", FALSE); + public static final BooleanSetting HIDE_PLAYER_FLYOUT_AUDIO_TRACK = new BooleanSetting("revanced_hide_player_flyout_audio_track", FALSE); + public static final BooleanSetting HIDE_PLAYER_FLYOUT_CAPTIONS = new BooleanSetting("revanced_hide_player_flyout_captions", FALSE); public static final BooleanSetting HIDE_PLAYER_FLYOUT_HELP = new BooleanSetting("revanced_hide_player_flyout_help", TRUE); - public static final BooleanSetting HIDE_PLAYER_FLYOUT_SPEED = new BooleanSetting("revanced_hide_player_flyout_speed", FALSE); - public static final BooleanSetting HIDE_PLAYER_FLYOUT_MORE_INFO = new BooleanSetting("revanced_hide_player_flyout_more_info", TRUE); public static final BooleanSetting HIDE_PLAYER_FLYOUT_LOCK_SCREEN = new BooleanSetting("revanced_hide_player_flyout_lock_screen", FALSE); - public static final BooleanSetting HIDE_PLAYER_FLYOUT_AUDIO_TRACK = new BooleanSetting("revanced_hide_player_flyout_audio_track", FALSE); + public static final BooleanSetting HIDE_PLAYER_FLYOUT_LOOP_VIDEO = new BooleanSetting("revanced_hide_player_flyout_loop_video", FALSE); + public static final BooleanSetting HIDE_PLAYER_FLYOUT_MORE_INFO = new BooleanSetting("revanced_hide_player_flyout_more_info", TRUE); public static final BooleanSetting HIDE_PLAYER_FLYOUT_SLEEP_TIMER = new BooleanSetting("revanced_hide_player_flyout_sleep_timer", FALSE); + public static final BooleanSetting HIDE_PLAYER_FLYOUT_SPEED = new BooleanSetting("revanced_hide_player_flyout_speed", FALSE); public static final BooleanSetting HIDE_PLAYER_FLYOUT_STABLE_VOLUME = new BooleanSetting("revanced_hide_player_flyout_stable_volume", FALSE); - public static final BooleanSetting HIDE_PLAYER_FLYOUT_WATCH_IN_VR = new BooleanSetting("revanced_hide_player_flyout_watch_in_vr", TRUE); - private static final BooleanSetting DEPRECATED_HIDE_PLAYER_FLYOUT_VIDEO_QUALITY_FOOTER = new BooleanSetting("revanced_hide_video_quality_menu_footer", FALSE); public static final BooleanSetting HIDE_PLAYER_FLYOUT_VIDEO_QUALITY_FOOTER = new BooleanSetting("revanced_hide_player_flyout_video_quality_footer", FALSE); + public static final BooleanSetting HIDE_PLAYER_FLYOUT_WATCH_IN_VR = new BooleanSetting("revanced_hide_player_flyout_watch_in_vr", TRUE); // General layout - public static final EnumSetting CHANGE_START_PAGE = new EnumSetting<>("revanced_change_start_page", StartPage.ORIGINAL, true); - public static final BooleanSetting SPOOF_APP_VERSION = new BooleanSetting("revanced_spoof_app_version", FALSE, true, "revanced_spoof_app_version_user_dialog_message"); - public static final StringSetting SPOOF_APP_VERSION_TARGET = new StringSetting("revanced_spoof_app_version_target", IS_19_17_OR_GREATER ? "19.35.36" : "17.33.42", true, parent(SPOOF_APP_VERSION)); - public static final BooleanSetting TABLET_LAYOUT = new BooleanSetting("revanced_tablet_layout", FALSE, true, "revanced_tablet_layout_user_dialog_message"); - public static final BooleanSetting WIDE_SEARCHBAR = new BooleanSetting("revanced_wide_searchbar", FALSE, true); public static final BooleanSetting BYPASS_IMAGE_REGION_RESTRICTIONS = new BooleanSetting("revanced_bypass_image_region_restrictions", FALSE, true); + public static final BooleanSetting GRADIENT_LOADING_SCREEN = new BooleanSetting("revanced_gradient_loading_screen", FALSE, true); public static final BooleanSetting REMOVE_VIEWER_DISCRETION_DIALOG = new BooleanSetting("revanced_remove_viewer_discretion_dialog", FALSE, "revanced_remove_viewer_discretion_dialog_user_dialog_message"); - + public static final BooleanSetting SPOOF_APP_VERSION = new BooleanSetting("revanced_spoof_app_version", FALSE, true, "revanced_spoof_app_version_user_dialog_message"); + public static final BooleanSetting TABLET_LAYOUT = new BooleanSetting("revanced_tablet_layout", FALSE, true, "revanced_tablet_layout_user_dialog_message"); + public static final BooleanSetting WIDE_SEARCHBAR = new BooleanSetting("revanced_wide_searchbar", FALSE, true); + public static final EnumSetting CHANGE_START_PAGE = new EnumSetting<>("revanced_change_start_page", StartPage.ORIGINAL, true); + public static final StringSetting SPOOF_APP_VERSION_TARGET = new StringSetting("revanced_spoof_app_version_target", IS_19_17_OR_GREATER ? "19.35.36" : "17.33.42", true, parent(SPOOF_APP_VERSION)); // Custom filter public static final BooleanSetting CUSTOM_FILTER = new BooleanSetting("revanced_custom_filter", FALSE); public static final StringSetting CUSTOM_FILTER_STRINGS = new StringSetting("revanced_custom_filter_strings", "", true, parent(CUSTOM_FILTER)); - // Navigation buttons public static final BooleanSetting HIDE_HOME_BUTTON = new BooleanSetting("revanced_hide_home_button", FALSE, true); public static final BooleanSetting HIDE_CREATE_BUTTON = new BooleanSetting("revanced_hide_create_button", TRUE, true); @@ -216,71 +217,67 @@ public class Settings extends BaseSettings { public static final BooleanSetting SWITCH_CREATE_WITH_NOTIFICATIONS_BUTTON = new BooleanSetting("revanced_switch_create_with_notifications_button", TRUE, true); // Shorts - public static final BooleanSetting DISABLE_SHORTS_BACKGROUND_PLAYBACK = new BooleanSetting("revanced_shorts_disable_background_playback", FALSE); public static final BooleanSetting DISABLE_RESUMING_SHORTS_PLAYER = new BooleanSetting("revanced_disable_resuming_shorts_player", FALSE); + public static final BooleanSetting DISABLE_SHORTS_BACKGROUND_PLAYBACK = new BooleanSetting("revanced_shorts_disable_background_playback", FALSE); + public static final BooleanSetting HIDE_SHORTS_CHANNEL_BAR = new BooleanSetting("revanced_hide_shorts_channel_bar", FALSE); + public static final BooleanSetting HIDE_SHORTS_COMMENTS_BUTTON = new BooleanSetting("revanced_hide_shorts_comments_button", FALSE); + public static final BooleanSetting HIDE_SHORTS_DISLIKE_BUTTON = new BooleanSetting("revanced_hide_shorts_dislike_button", FALSE); + public static final BooleanSetting HIDE_SHORTS_FULL_VIDEO_LINK_LABEL = new BooleanSetting("revanced_hide_shorts_full_video_link_label", FALSE); + public static final BooleanSetting HIDE_SHORTS_GREEN_SCREEN_BUTTON = new BooleanSetting("revanced_hide_shorts_green_screen_button", TRUE); + public static final BooleanSetting HIDE_SHORTS_HASHTAG_BUTTON = new BooleanSetting("revanced_hide_shorts_hashtag_button", TRUE); public static final BooleanSetting HIDE_SHORTS_HOME = new BooleanSetting("revanced_hide_shorts_home", FALSE); - public static final BooleanSetting HIDE_SHORTS_SUBSCRIPTIONS = new BooleanSetting("revanced_hide_shorts_subscriptions", FALSE); - public static final BooleanSetting HIDE_SHORTS_SEARCH = new BooleanSetting("revanced_hide_shorts_search", FALSE); + public static final BooleanSetting HIDE_SHORTS_INFO_PANEL = new BooleanSetting("revanced_hide_shorts_info_panel", TRUE); public static final BooleanSetting HIDE_SHORTS_JOIN_BUTTON = new BooleanSetting("revanced_hide_shorts_join_button", TRUE); - public static final BooleanSetting HIDE_SHORTS_SUBSCRIBE_BUTTON = new BooleanSetting("revanced_hide_shorts_subscribe_button", TRUE); - public static final BooleanSetting HIDE_SHORTS_PAUSED_OVERLAY_BUTTONS = new BooleanSetting("revanced_hide_shorts_paused_overlay_buttons", FALSE); - public static final BooleanSetting HIDE_SHORTS_SHOP_BUTTON = new BooleanSetting("revanced_hide_shorts_shop_button", TRUE); - public static final BooleanSetting HIDE_SHORTS_TAGGED_PRODUCTS = new BooleanSetting("revanced_hide_shorts_tagged_products", TRUE); + public static final BooleanSetting HIDE_SHORTS_LIKE_BUTTON = new BooleanSetting("revanced_hide_shorts_like_button", FALSE); + public static final BooleanSetting HIDE_SHORTS_LIKE_FOUNTAIN = new BooleanSetting("revanced_hide_shorts_like_fountain", TRUE); public static final BooleanSetting HIDE_SHORTS_LOCATION_LABEL = new BooleanSetting("revanced_hide_shorts_location_label", FALSE); + public static final BooleanSetting HIDE_SHORTS_NAVIGATION_BAR = new BooleanSetting("revanced_hide_shorts_navigation_bar", FALSE, true); + public static final BooleanSetting HIDE_SHORTS_PAUSED_OVERLAY_BUTTONS = new BooleanSetting("revanced_hide_shorts_paused_overlay_buttons", FALSE); + public static final BooleanSetting HIDE_SHORTS_REMIX_BUTTON = new BooleanSetting("revanced_hide_shorts_remix_button", TRUE); public static final BooleanSetting HIDE_SHORTS_SAVE_SOUND_BUTTON = new BooleanSetting("revanced_hide_shorts_save_sound_button", TRUE); - public static final BooleanSetting HIDE_SHORTS_USE_TEMPLATE_BUTTON = new BooleanSetting("revanced_hide_shorts_use_template_button", TRUE); - public static final BooleanSetting HIDE_SHORTS_UPCOMING_BUTTON = new BooleanSetting("revanced_hide_shorts_upcoming_button", TRUE); - public static final BooleanSetting HIDE_SHORTS_GREEN_SCREEN_BUTTON = new BooleanSetting("revanced_hide_shorts_green_screen_button", TRUE); - public static final BooleanSetting HIDE_SHORTS_HASHTAG_BUTTON = new BooleanSetting("revanced_hide_shorts_hashtag_button", TRUE); + public static final BooleanSetting HIDE_SHORTS_SEARCH = new BooleanSetting("revanced_hide_shorts_search", FALSE); public static final BooleanSetting HIDE_SHORTS_SEARCH_SUGGESTIONS = new BooleanSetting("revanced_hide_shorts_search_suggestions", TRUE); - public static final BooleanSetting HIDE_SHORTS_STICKERS = new BooleanSetting("revanced_hide_shorts_stickers", TRUE); - public static final BooleanSetting HIDE_SHORTS_SUPER_THANKS_BUTTON = new BooleanSetting("revanced_hide_shorts_super_thanks_button", TRUE); - public static final BooleanSetting HIDE_SHORTS_LIKE_FOUNTAIN = new BooleanSetting("revanced_hide_shorts_like_fountain", TRUE); - public static final BooleanSetting HIDE_SHORTS_LIKE_BUTTON = new BooleanSetting("revanced_hide_shorts_like_button", FALSE); - public static final BooleanSetting HIDE_SHORTS_DISLIKE_BUTTON = new BooleanSetting("revanced_hide_shorts_dislike_button", FALSE); - public static final BooleanSetting HIDE_SHORTS_COMMENTS_BUTTON = new BooleanSetting("revanced_hide_shorts_comments_button", FALSE); - public static final BooleanSetting HIDE_SHORTS_REMIX_BUTTON = new BooleanSetting("revanced_hide_shorts_remix_button", TRUE); public static final BooleanSetting HIDE_SHORTS_SHARE_BUTTON = new BooleanSetting("revanced_hide_shorts_share_button", FALSE); - public static final BooleanSetting HIDE_SHORTS_INFO_PANEL = new BooleanSetting("revanced_hide_shorts_info_panel", TRUE); + public static final BooleanSetting HIDE_SHORTS_SHOP_BUTTON = new BooleanSetting("revanced_hide_shorts_shop_button", TRUE); public static final BooleanSetting HIDE_SHORTS_SOUND_BUTTON = new BooleanSetting("revanced_hide_shorts_sound_button", FALSE); - public static final BooleanSetting HIDE_SHORTS_CHANNEL_BAR = new BooleanSetting("revanced_hide_shorts_channel_bar", FALSE); - public static final BooleanSetting HIDE_SHORTS_VIDEO_TITLE = new BooleanSetting("revanced_hide_shorts_video_title", FALSE); public static final BooleanSetting HIDE_SHORTS_SOUND_METADATA_LABEL = new BooleanSetting("revanced_hide_shorts_sound_metadata_label", FALSE); - public static final BooleanSetting HIDE_SHORTS_FULL_VIDEO_LINK_LABEL = new BooleanSetting("revanced_hide_shorts_full_video_link_label", FALSE); - public static final BooleanSetting HIDE_SHORTS_NAVIGATION_BAR = new BooleanSetting("revanced_hide_shorts_navigation_bar", FALSE, true); + public static final BooleanSetting HIDE_SHORTS_STICKERS = new BooleanSetting("revanced_hide_shorts_stickers", TRUE); + public static final BooleanSetting HIDE_SHORTS_SUBSCRIBE_BUTTON = new BooleanSetting("revanced_hide_shorts_subscribe_button", TRUE); + public static final BooleanSetting HIDE_SHORTS_SUBSCRIPTIONS = new BooleanSetting("revanced_hide_shorts_subscriptions", FALSE); + public static final BooleanSetting HIDE_SHORTS_SUPER_THANKS_BUTTON = new BooleanSetting("revanced_hide_shorts_super_thanks_button", TRUE); + public static final BooleanSetting HIDE_SHORTS_TAGGED_PRODUCTS = new BooleanSetting("revanced_hide_shorts_tagged_products", TRUE); + public static final BooleanSetting HIDE_SHORTS_UPCOMING_BUTTON = new BooleanSetting("revanced_hide_shorts_upcoming_button", TRUE); + public static final BooleanSetting HIDE_SHORTS_USE_TEMPLATE_BUTTON = new BooleanSetting("revanced_hide_shorts_use_template_button", TRUE); + public static final BooleanSetting HIDE_SHORTS_VIDEO_TITLE = new BooleanSetting("revanced_hide_shorts_video_title", FALSE); public static final BooleanSetting SHORTS_AUTOPLAY = new BooleanSetting("revanced_shorts_autoplay", FALSE); public static final BooleanSetting SHORTS_AUTOPLAY_BACKGROUND = new BooleanSetting("revanced_shorts_autoplay_background", TRUE); // Seekbar + public static final BooleanSetting DISABLE_PRECISE_SEEKING_GESTURE = new BooleanSetting("revanced_disable_precise_seeking_gesture", TRUE); - public static final BooleanSetting SEEKBAR_TAPPING = new BooleanSetting("revanced_seekbar_tapping", TRUE); - public static final BooleanSetting SLIDE_TO_SEEK = new BooleanSetting("revanced_slide_to_seek", FALSE, true); - public static final BooleanSetting RESTORE_OLD_SEEKBAR_THUMBNAILS = new BooleanSetting("revanced_restore_old_seekbar_thumbnails", TRUE); - public static final BooleanSetting SEEKBAR_THUMBNAILS_HIGH_QUALITY = new BooleanSetting("revanced_seekbar_thumbnails_high_quality", FALSE, true, - "revanced_seekbar_thumbnails_high_quality_dialog_message", new SeekbarThumbnailsHighQualityAvailability()); public static final BooleanSetting HIDE_SEEKBAR = new BooleanSetting("revanced_hide_seekbar", FALSE, true); public static final BooleanSetting HIDE_SEEKBAR_THUMBNAIL = new BooleanSetting("revanced_hide_seekbar_thumbnail", FALSE); + public static final BooleanSetting HIDE_TIMESTAMP = new BooleanSetting("revanced_hide_timestamp", FALSE); + public static final BooleanSetting RESTORE_OLD_SEEKBAR_THUMBNAILS = new BooleanSetting("revanced_restore_old_seekbar_thumbnails", TRUE); public static final BooleanSetting SEEKBAR_CUSTOM_COLOR = new BooleanSetting("revanced_seekbar_custom_color", FALSE, true); + public static final BooleanSetting SEEKBAR_TAPPING = new BooleanSetting("revanced_seekbar_tapping", TRUE); + public static final BooleanSetting SEEKBAR_THUMBNAILS_HIGH_QUALITY = new BooleanSetting("revanced_seekbar_thumbnails_high_quality", FALSE, true, + "revanced_seekbar_thumbnails_high_quality_dialog_message", new SeekbarThumbnailsHighQualityAvailability()); + public static final BooleanSetting SLIDE_TO_SEEK = new BooleanSetting("revanced_slide_to_seek", FALSE, true); public static final StringSetting SEEKBAR_CUSTOM_COLOR_VALUE = new StringSetting("revanced_seekbar_custom_color_value", "#FF0033", true, parent(SEEKBAR_CUSTOM_COLOR)); // Misc + public static final BooleanSetting ANNOUNCEMENTS = new BooleanSetting("revanced_announcements", TRUE); + public static final IntegerSetting ANNOUNCEMENT_LAST_ID = new IntegerSetting("revanced_announcement_last_id", -1, false, false); public static final BooleanSetting AUTO_CAPTIONS = new BooleanSetting("revanced_auto_captions", FALSE); - public static final BooleanSetting DISABLE_ZOOM_HAPTICS = new BooleanSetting("revanced_disable_zoom_haptics", TRUE); - public static final BooleanSetting EXTERNAL_BROWSER = new BooleanSetting("revanced_external_browser", TRUE, true); public static final BooleanSetting AUTO_REPEAT = new BooleanSetting("revanced_auto_repeat", FALSE); - public static final BooleanSetting SPOOF_DEVICE_DIMENSIONS = new BooleanSetting("revanced_spoof_device_dimensions", FALSE, true, - "revanced_spoof_device_dimensions_user_dialog_message"); public static final BooleanSetting BYPASS_URL_REDIRECTS = new BooleanSetting("revanced_bypass_url_redirects", TRUE); - public static final BooleanSetting ANNOUNCEMENTS = new BooleanSetting("revanced_announcements", TRUE); - public static final BooleanSetting SPOOF_VIDEO_STREAMS = new BooleanSetting("revanced_spoof_video_streams", TRUE, true,"revanced_spoof_video_streams_user_dialog_message"); - public static final BooleanSetting SPOOF_VIDEO_STREAMS_IOS_FORCE_AVC = new BooleanSetting("revanced_spoof_video_streams_ios_force_avc", FALSE, true, - "revanced_spoof_video_streams_ios_force_avc_user_dialog_message", new SpoofVideoStreamsPatch.ForceiOSAVCAvailability()); - public static final EnumSetting SPOOF_VIDEO_STREAMS_CLIENT_TYPE = new EnumSetting<>("revanced_spoof_video_streams_client", ClientType.ANDROID_VR, true, parent(SPOOF_VIDEO_STREAMS)); - public static final IntegerSetting ANNOUNCEMENT_LAST_ID = new IntegerSetting("revanced_announcement_last_id", -1, false, false); public static final BooleanSetting CHECK_WATCH_HISTORY_DOMAIN_NAME = new BooleanSetting("revanced_check_watch_history_domain_name", TRUE, false, false); + public static final BooleanSetting DISABLE_ZOOM_HAPTICS = new BooleanSetting("revanced_disable_zoom_haptics", TRUE); + public static final BooleanSetting EXTERNAL_BROWSER = new BooleanSetting("revanced_external_browser", TRUE, true); public static final BooleanSetting REMOVE_TRACKING_QUERY_PARAMETER = new BooleanSetting("revanced_remove_tracking_query_parameter", TRUE); - - // Debugging + public static final BooleanSetting SPOOF_DEVICE_DIMENSIONS = new BooleanSetting("revanced_spoof_device_dimensions", FALSE, true, + "revanced_spoof_device_dimensions_user_dialog_message"); /** * When enabled, share the debug logs with care. * The buffer contains select user data, including the client ip address and information that could identify the end user. @@ -298,6 +295,8 @@ public class Settings extends BaseSettings { parentsAny(SWIPE_BRIGHTNESS, SWIPE_VOLUME)); public static final IntegerSetting SWIPE_OVERLAY_BACKGROUND_ALPHA = new IntegerSetting("revanced_swipe_overlay_background_alpha", 127, true, parentsAny(SWIPE_BRIGHTNESS, SWIPE_VOLUME)); + + // Debugging public static final IntegerSetting SWIPE_OVERLAY_TEXT_SIZE = new IntegerSetting("revanced_swipe_text_overlay_size", 22, true, parentsAny(SWIPE_BRIGHTNESS, SWIPE_VOLUME)); public static final LongSetting SWIPE_OVERLAY_TIMEOUT = new LongSetting("revanced_swipe_overlay_timeout", 500L, true, @@ -320,7 +319,6 @@ public class Settings extends BaseSettings { * Do not use directly, instead use {@link SponsorBlockSettings} */ public static final StringSetting SB_PRIVATE_USER_ID = new StringSetting("sb_private_user_id_Do_Not_Share", ""); - public static final StringSetting DEPRECATED_SB_UUID_OLD_MIGRATION_SETTING = new StringSetting("uuid", ""); // Delete sometime in 2024 public static final IntegerSetting SB_CREATE_NEW_SEGMENT_STEP = new IntegerSetting("sb_create_new_segment_step", 150, parent(SB_ENABLED)); public static final BooleanSetting SB_VOTING_BUTTON = new BooleanSetting("sb_voting_button", FALSE, parent(SB_ENABLED)); public static final BooleanSetting SB_CREATE_NEW_SEGMENT = new BooleanSetting("sb_create_new_segment", FALSE, parent(SB_ENABLED)); @@ -331,34 +329,38 @@ public class Settings extends BaseSettings { public static final BooleanSetting SB_TRACK_SKIP_COUNT = new BooleanSetting("sb_track_skip_count", TRUE, parent(SB_ENABLED)); public static final FloatSetting SB_SEGMENT_MIN_DURATION = new FloatSetting("sb_min_segment_duration", 0F, parent(SB_ENABLED)); public static final BooleanSetting SB_VIDEO_LENGTH_WITHOUT_SEGMENTS = new BooleanSetting("sb_video_length_without_segments", TRUE, parent(SB_ENABLED)); - public static final StringSetting SB_API_URL = new StringSetting("sb_api_url","https://sponsor.ajay.app"); + public static final StringSetting SB_API_URL = new StringSetting("sb_api_url", "https://sponsor.ajay.app"); public static final BooleanSetting SB_USER_IS_VIP = new BooleanSetting("sb_user_is_vip", FALSE); public static final IntegerSetting SB_LOCAL_TIME_SAVED_NUMBER_SEGMENTS = new IntegerSetting("sb_local_time_saved_number_segments", 0); public static final LongSetting SB_LOCAL_TIME_SAVED_MILLISECONDS = new LongSetting("sb_local_time_saved_milliseconds", 0L); public static final LongSetting SB_LAST_VIP_CHECK = new LongSetting("sb_last_vip_check", 0L, false, false); public static final BooleanSetting SB_HIDE_EXPORT_WARNING = new BooleanSetting("sb_hide_export_warning", FALSE, false, false); public static final BooleanSetting SB_SEEN_GUIDELINES = new BooleanSetting("sb_seen_guidelines", FALSE, false, false); - public static final StringSetting SB_CATEGORY_SPONSOR = new StringSetting("sb_sponsor", SKIP_AUTOMATICALLY_ONCE.reVancedKeyValue); - public static final StringSetting SB_CATEGORY_SPONSOR_COLOR = new StringSetting("sb_sponsor_color","#00D400"); + public static final StringSetting SB_CATEGORY_SPONSOR_COLOR = new StringSetting("sb_sponsor_color", "#00D400"); public static final StringSetting SB_CATEGORY_SELF_PROMO = new StringSetting("sb_selfpromo", MANUAL_SKIP.reVancedKeyValue); - public static final StringSetting SB_CATEGORY_SELF_PROMO_COLOR = new StringSetting("sb_selfpromo_color","#FFFF00"); + public static final StringSetting SB_CATEGORY_SELF_PROMO_COLOR = new StringSetting("sb_selfpromo_color", "#FFFF00"); public static final StringSetting SB_CATEGORY_INTERACTION = new StringSetting("sb_interaction", MANUAL_SKIP.reVancedKeyValue); - public static final StringSetting SB_CATEGORY_INTERACTION_COLOR = new StringSetting("sb_interaction_color","#CC00FF"); + public static final StringSetting SB_CATEGORY_INTERACTION_COLOR = new StringSetting("sb_interaction_color", "#CC00FF"); public static final StringSetting SB_CATEGORY_HIGHLIGHT = new StringSetting("sb_highlight", MANUAL_SKIP.reVancedKeyValue); - public static final StringSetting SB_CATEGORY_HIGHLIGHT_COLOR = new StringSetting("sb_highlight_color","#FF1684"); + public static final StringSetting SB_CATEGORY_HIGHLIGHT_COLOR = new StringSetting("sb_highlight_color", "#FF1684"); public static final StringSetting SB_CATEGORY_INTRO = new StringSetting("sb_intro", MANUAL_SKIP.reVancedKeyValue); - public static final StringSetting SB_CATEGORY_INTRO_COLOR = new StringSetting("sb_intro_color","#00FFFF"); + public static final StringSetting SB_CATEGORY_INTRO_COLOR = new StringSetting("sb_intro_color", "#00FFFF"); public static final StringSetting SB_CATEGORY_OUTRO = new StringSetting("sb_outro", MANUAL_SKIP.reVancedKeyValue); - public static final StringSetting SB_CATEGORY_OUTRO_COLOR = new StringSetting("sb_outro_color","#0202ED"); + public static final StringSetting SB_CATEGORY_OUTRO_COLOR = new StringSetting("sb_outro_color", "#0202ED"); public static final StringSetting SB_CATEGORY_PREVIEW = new StringSetting("sb_preview", IGNORE.reVancedKeyValue); - public static final StringSetting SB_CATEGORY_PREVIEW_COLOR = new StringSetting("sb_preview_color","#008FD6"); + public static final StringSetting SB_CATEGORY_PREVIEW_COLOR = new StringSetting("sb_preview_color", "#008FD6"); public static final StringSetting SB_CATEGORY_FILLER = new StringSetting("sb_filler", IGNORE.reVancedKeyValue); - public static final StringSetting SB_CATEGORY_FILLER_COLOR = new StringSetting("sb_filler_color","#7300FF"); + public static final StringSetting SB_CATEGORY_FILLER_COLOR = new StringSetting("sb_filler_color", "#7300FF"); public static final StringSetting SB_CATEGORY_MUSIC_OFFTOPIC = new StringSetting("sb_music_offtopic", MANUAL_SKIP.reVancedKeyValue); - public static final StringSetting SB_CATEGORY_MUSIC_OFFTOPIC_COLOR = new StringSetting("sb_music_offtopic_color","#FF9900"); + public static final StringSetting SB_CATEGORY_MUSIC_OFFTOPIC_COLOR = new StringSetting("sb_music_offtopic_color", "#FF9900"); public static final StringSetting SB_CATEGORY_UNSUBMITTED = new StringSetting("sb_unsubmitted", SKIP_AUTOMATICALLY.reVancedKeyValue); - public static final StringSetting SB_CATEGORY_UNSUBMITTED_COLOR = new StringSetting("sb_unsubmitted_color","#FFFFFF"); + public static final StringSetting SB_CATEGORY_UNSUBMITTED_COLOR = new StringSetting("sb_unsubmitted_color", "#FFFFFF"); + + // Deprecated migrations + public static final StringSetting DEPRECATED_SB_UUID_OLD_MIGRATION_SETTING = new StringSetting("uuid", ""); // Delete sometime in 2024 + private static final BooleanSetting DEPRECATED_HIDE_PLAYER_BUTTONS = new BooleanSetting("revanced_hide_player_buttons", FALSE, true); + private static final BooleanSetting DEPRECATED_HIDE_PLAYER_FLYOUT_VIDEO_QUALITY_FOOTER = new BooleanSetting("revanced_hide_video_quality_menu_footer", FALSE); static { // region Migration diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/preference/ForceAVCSpoofingPreference.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/preference/ForceAVCSpoofingPreference.java index 5581756758..b3faebf8f9 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/preference/ForceAVCSpoofingPreference.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/preference/ForceAVCSpoofingPreference.java @@ -1,7 +1,7 @@ package app.revanced.extension.youtube.settings.preference; import static app.revanced.extension.shared.StringRef.str; -import static app.revanced.extension.youtube.patches.spoof.DeviceHardwareSupport.DEVICE_HAS_HARDWARE_DECODING_VP9; +import static app.revanced.extension.shared.spoof.DeviceHardwareSupport.DEVICE_HAS_HARDWARE_DECODING_VP9; import android.content.Context; import android.preference.SwitchPreference; @@ -18,12 +18,15 @@ public class ForceAVCSpoofingPreference extends SwitchPreference { public ForceAVCSpoofingPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } + public ForceAVCSpoofingPreference(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } + public ForceAVCSpoofingPreference(Context context, AttributeSet attrs) { super(context, attrs); } + public ForceAVCSpoofingPreference(Context context) { super(context); } diff --git a/patches/api/patches.api b/patches/api/patches.api index 1c601b5515..5e6a8c8fe4 100644 --- a/patches/api/patches.api +++ b/patches/api/patches.api @@ -320,6 +320,10 @@ public final class app/revanced/patches/music/misc/gms/GmsCoreSupportPatchKt { public static final fun getGmsCoreSupportPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } +public final class app/revanced/patches/music/misc/spoof/SpoofVideoStreamsPatchKt { + public static final fun getSpoofVideoStreamsPatch ()Lapp/revanced/patcher/patch/BytecodePatch; +} + public final class app/revanced/patches/myexpenses/misc/pro/UnlockProPatchKt { public static final fun getUnlockProPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } @@ -753,6 +757,11 @@ public final class app/revanced/patches/shared/misc/settings/preference/TextPref public fun serialize (Lorg/w3c/dom/Document;Lkotlin/jvm/functions/Function1;)Lorg/w3c/dom/Element; } +public final class app/revanced/patches/shared/misc/spoof/SpoofVideoStreamsPatchKt { + public static final fun spoofVideoStreamsPatch (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Lapp/revanced/patcher/patch/BytecodePatch; + public static synthetic fun spoofVideoStreamsPatch$default (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lapp/revanced/patcher/patch/BytecodePatch; +} + public final class app/revanced/patches/solidexplorer2/functionality/filesize/RemoveFileSizeLimitPatchKt { public static final fun getRemoveFileSizeLimitPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } @@ -1359,6 +1368,14 @@ public final class app/revanced/patches/youtube/misc/settings/SettingsPatchKt { public static final fun newIntent (Ljava/lang/String;)Lapp/revanced/patches/shared/misc/settings/preference/IntentPreference$Intent; } +public final class app/revanced/patches/youtube/misc/spoof/SpoofVideoStreamsPatchKt { + public static final fun getSpoofVideoStreamsPatch ()Lapp/revanced/patcher/patch/BytecodePatch; +} + +public final class app/revanced/patches/youtube/misc/spoof/UserAgentClientSpoofPatchKt { + public static final fun getUserAgentClientSpoofPatch ()Lapp/revanced/patcher/patch/BytecodePatch; +} + public final class app/revanced/patches/youtube/misc/zoomhaptics/ZoomHapticsPatchKt { public static final fun getZoomHapticsPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } diff --git a/patches/src/main/kotlin/app/revanced/patches/music/misc/gms/GmsCoreSupportPatch.kt b/patches/src/main/kotlin/app/revanced/patches/music/misc/gms/GmsCoreSupportPatch.kt index e38ca6015c..0fa223b235 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/misc/gms/GmsCoreSupportPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/misc/gms/GmsCoreSupportPatch.kt @@ -4,6 +4,7 @@ import app.revanced.patcher.patch.Option import app.revanced.patches.music.misc.extension.sharedExtensionPatch import app.revanced.patches.music.misc.gms.Constants.MUSIC_PACKAGE_NAME import app.revanced.patches.music.misc.gms.Constants.REVANCED_MUSIC_PACKAGE_NAME +import app.revanced.patches.music.misc.spoof.spoofVideoStreamsPatch import app.revanced.patches.shared.castContextFetchFingerprint import app.revanced.patches.shared.misc.gms.gmsCoreSupportPatch import app.revanced.patches.shared.primeMethodFingerprint @@ -20,6 +21,8 @@ val gmsCoreSupportPatch = gmsCoreSupportPatch( extensionPatch = sharedExtensionPatch, gmsCoreSupportResourcePatchFactory = ::gmsCoreSupportResourcePatch, ) { + dependsOn(spoofVideoStreamsPatch) + compatibleWith(MUSIC_PACKAGE_NAME) } diff --git a/patches/src/main/kotlin/app/revanced/patches/music/misc/spoof/SpoofVideoStreamsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/music/misc/spoof/SpoofVideoStreamsPatch.kt new file mode 100644 index 0000000000..862bc3f227 --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/music/misc/spoof/SpoofVideoStreamsPatch.kt @@ -0,0 +1,7 @@ +package app.revanced.patches.music.misc.spoof + +import app.revanced.patches.shared.misc.spoof.spoofVideoStreamsPatch + +val spoofVideoStreamsPatch = spoofVideoStreamsPatch({ + compatibleWith("com.google.android.apps.youtube.music") +}) diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/shared/misc/spoof/Fingerprints.kt similarity index 97% rename from patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/Fingerprints.kt rename to patches/src/main/kotlin/app/revanced/patches/shared/misc/spoof/Fingerprints.kt index 1862a79aa8..3976d03e7e 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/misc/spoof/Fingerprints.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.misc.fix.playback +package app.revanced.patches.shared.misc.spoof import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.AccessFlags @@ -27,7 +27,6 @@ internal val buildPlayerRequestURIFingerprint = fingerprint { Opcode.RETURN_OBJECT, ) strings( - "youtubei/v1", "key", "asig", ) diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/misc/spoof/SpoofVideoStreamsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/shared/misc/spoof/SpoofVideoStreamsPatch.kt new file mode 100644 index 0000000000..0e9e831261 --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/shared/misc/spoof/SpoofVideoStreamsPatch.kt @@ -0,0 +1,206 @@ +package app.revanced.patches.shared.misc.spoof + +import app.revanced.patcher.extensions.InstructionExtensions.addInstruction +import app.revanced.patcher.extensions.InstructionExtensions.addInstructions +import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels +import app.revanced.patcher.extensions.InstructionExtensions.getInstruction +import app.revanced.patcher.extensions.InstructionExtensions.instructions +import app.revanced.patcher.patch.BytecodePatchBuilder +import app.revanced.patcher.patch.BytecodePatchContext +import app.revanced.patcher.patch.bytecodePatch +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable +import app.revanced.patches.all.misc.resources.addResourcesPatch +import app.revanced.util.getReference +import app.revanced.util.indexOfFirstInstructionOrThrow +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation +import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction +import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction +import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction +import com.android.tools.smali.dexlib2.iface.reference.FieldReference +import com.android.tools.smali.dexlib2.iface.reference.MethodReference +import com.android.tools.smali.dexlib2.immutable.ImmutableMethod +import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter + +private const val EXTENSION_CLASS_DESCRIPTOR = + "Lapp/revanced/extension/shared/spoof/SpoofVideoStreamsPatch;" + +fun spoofVideoStreamsPatch( + block: BytecodePatchBuilder.() -> Unit = {}, + executeBlock: BytecodePatchContext.() -> Unit = {}, +) = bytecodePatch( + name = "Spoof video streams", + description = "Spoofs the client video streams to fix playback.", +) { + block() + + dependsOn(addResourcesPatch) + + execute { + // region Block /initplayback requests to fall back to /get_watch requests. + + val moveUriStringIndex = buildInitPlaybackRequestFingerprint.patternMatch!!.startIndex + + buildInitPlaybackRequestFingerprint.method.apply { + val targetRegister = getInstruction(moveUriStringIndex).registerA + + addInstructions( + moveUriStringIndex + 1, + """ + invoke-static { v$targetRegister }, $EXTENSION_CLASS_DESCRIPTOR->blockInitPlaybackRequest(Ljava/lang/String;)Ljava/lang/String; + move-result-object v$targetRegister + """, + ) + } + + // endregion + + // region Block /get_watch requests to fall back to /player requests. + + val invokeToStringIndex = buildPlayerRequestURIFingerprint.patternMatch!!.startIndex + + buildPlayerRequestURIFingerprint.method.apply { + val uriRegister = getInstruction(invokeToStringIndex).registerC + + addInstructions( + invokeToStringIndex, + """ + invoke-static { v$uriRegister }, $EXTENSION_CLASS_DESCRIPTOR->blockGetWatchRequest(Landroid/net/Uri;)Landroid/net/Uri; + move-result-object v$uriRegister + """, + ) + } + + // endregion + + // region Get replacement streams at player requests. + + buildRequestFingerprint.method.apply { + val newRequestBuilderIndex = indexOfFirstInstructionOrThrow { + opcode == Opcode.INVOKE_VIRTUAL && + getReference()?.name == "newUrlRequestBuilder" + } + val urlRegister = getInstruction(newRequestBuilderIndex).registerD + val freeRegister = getInstruction(newRequestBuilderIndex + 1).registerA + + addInstructions( + newRequestBuilderIndex, + """ + move-object v$freeRegister, p1 + invoke-static { v$urlRegister, v$freeRegister }, $EXTENSION_CLASS_DESCRIPTOR->fetchStreams(Ljava/lang/String;Ljava/util/Map;)V + """, + ) + } + + // endregion + + // region Replace the streaming data with the replacement streams. + + createStreamingDataFingerprint.method.apply { + val setStreamDataMethodName = "patch_setStreamingData" + val resultMethodType = createStreamingDataFingerprint.classDef.type + val videoDetailsIndex = createStreamingDataFingerprint.patternMatch!!.endIndex + val videoDetailsRegister = getInstruction(videoDetailsIndex).registerA + val videoDetailsClass = getInstruction(videoDetailsIndex).getReference()!!.type + + addInstruction( + videoDetailsIndex + 1, + "invoke-direct { p0, v$videoDetailsRegister }, " + + "$resultMethodType->$setStreamDataMethodName($videoDetailsClass)V", + ) + + val protobufClass = protobufClassParseByteBufferFingerprint.method.definingClass + val setStreamingDataIndex = createStreamingDataFingerprint.patternMatch!!.startIndex + + val playerProtoClass = getInstruction(setStreamingDataIndex + 1) + .getReference()!!.definingClass + + val setStreamingDataField = getInstruction(setStreamingDataIndex).getReference() + + val getStreamingDataField = getInstruction( + indexOfFirstInstructionOrThrow { + opcode == Opcode.IGET_OBJECT && getReference()?.definingClass == playerProtoClass + }, + ).getReference() + + // Use a helper method to avoid the need of picking out multiple free registers from the hooked code. + createStreamingDataFingerprint.classDef.methods.add( + ImmutableMethod( + resultMethodType, + setStreamDataMethodName, + listOf(ImmutableMethodParameter(videoDetailsClass, null, "videoDetails")), + "V", + AccessFlags.PRIVATE.value or AccessFlags.FINAL.value, + null, + null, + MutableMethodImplementation(9), + ).toMutable().apply { + addInstructionsWithLabels( + 0, + """ + invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->isSpoofingEnabled()Z + move-result v0 + if-eqz v0, :disabled + + # Get video id. + iget-object v2, p1, $videoDetailsClass->c:Ljava/lang/String; + if-eqz v2, :disabled + + # Get streaming data. + invoke-static { v2 }, $EXTENSION_CLASS_DESCRIPTOR->getStreamingData(Ljava/lang/String;)Ljava/nio/ByteBuffer; + move-result-object v3 + if-eqz v3, :disabled + + # Parse streaming data. + sget-object v4, $playerProtoClass->a:$playerProtoClass + invoke-static { v4, v3 }, $protobufClass->parseFrom(${protobufClass}Ljava/nio/ByteBuffer;)$protobufClass + move-result-object v5 + check-cast v5, $playerProtoClass + + # Set streaming data. + iget-object v6, v5, $getStreamingDataField + if-eqz v6, :disabled + iput-object v6, p0, $setStreamingDataField + + :disabled + return-void + """, + ) + }, + ) + } + + // endregion + + // region Remove /videoplayback request body to fix playback. + // It is assumed, YouTube makes a request with a body tuned for Android. + // Requesting streams intended for other platforms with a body tuned for Android could be the cause of 400 errors. + // A proper fix may include modifying the request body to match the platforms expected body. + + buildMediaDataSourceFingerprint.method.apply { + val targetIndex = instructions.lastIndex + + // Instructions are added just before the method returns, + // so there's no concern of clobbering in-use registers. + addInstructions( + targetIndex, + """ + # Field a: Stream uri. + # Field c: Http method. + # Field d: Post data. + move-object v0, p0 # method has over 15 registers and must copy p0 to a lower register. + iget-object v1, v0, $definingClass->a:Landroid/net/Uri; + iget v2, v0, $definingClass->c:I + iget-object v3, v0, $definingClass->d:[B + invoke-static { v1, v2, v3 }, $EXTENSION_CLASS_DESCRIPTOR->removeVideoPlaybackPostBody(Landroid/net/Uri;I[B)[B + move-result-object v1 + iput-object v1, v0, $definingClass->d:[B + """, + ) + } + // endregion + + executeBlock() + } +} diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofVideoStreamsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofVideoStreamsPatch.kt index 515536b8f5..89e7cc08f8 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofVideoStreamsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofVideoStreamsPatch.kt @@ -1,243 +1,9 @@ package app.revanced.patches.youtube.misc.fix.playback -import app.revanced.patcher.extensions.InstructionExtensions.addInstruction -import app.revanced.patcher.extensions.InstructionExtensions.addInstructions -import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels -import app.revanced.patcher.extensions.InstructionExtensions.getInstruction -import app.revanced.patcher.extensions.InstructionExtensions.instructions import app.revanced.patcher.patch.bytecodePatch -import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable -import app.revanced.patches.all.misc.resources.addResources -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.NonInteractivePreference -import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference -import app.revanced.patches.shared.misc.settings.preference.SwitchPreference -import app.revanced.patches.youtube.misc.settings.PreferenceScreen -import app.revanced.patches.youtube.misc.settings.settingsPatch -import app.revanced.util.getReference -import app.revanced.util.indexOfFirstInstructionOrThrow -import com.android.tools.smali.dexlib2.AccessFlags -import com.android.tools.smali.dexlib2.Opcode -import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation -import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction -import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction -import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction -import com.android.tools.smali.dexlib2.iface.reference.FieldReference -import com.android.tools.smali.dexlib2.iface.reference.MethodReference -import com.android.tools.smali.dexlib2.immutable.ImmutableMethod -import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter -private const val EXTENSION_CLASS_DESCRIPTOR = - "Lapp/revanced/extension/youtube/patches/spoof/SpoofVideoStreamsPatch;" - -val spoofVideoStreamsPatch = bytecodePatch( - name = "Spoof video streams", - description = "Spoofs the client video streams to allow video playback.", -) { - compatibleWith( - "com.google.android.youtube"( - "18.38.44", - "18.49.37", - "19.16.39", - "19.25.37", - "19.34.42", - "19.43.41", - "19.45.38", - "19.46.42", - ), - ) - - dependsOn( - settingsPatch, - addResourcesPatch, - userAgentClientSpoofPatch, - ) - - execute { - addResources("youtube", "misc.fix.playback.spoofVideoStreamsPatch") - - PreferenceScreen.MISC.addPreferences( - PreferenceScreenPreference( - key = "revanced_spoof_video_streams_screen", - sorting = PreferenceScreenPreference.Sorting.UNSORTED, - preferences = setOf( - SwitchPreference("revanced_spoof_video_streams"), - ListPreference( - "revanced_spoof_video_streams_client", - summaryKey = null, - ), - SwitchPreference( - "revanced_spoof_video_streams_ios_force_avc", - tag = "app.revanced.extension.youtube.settings.preference.ForceAVCSpoofingPreference", - ), - NonInteractivePreference("revanced_spoof_video_streams_about_android_vr"), - NonInteractivePreference("revanced_spoof_video_streams_about_ios"), - ), - ), - ) - - // region Block /initplayback requests to fall back to /get_watch requests. - - val moveUriStringIndex = buildInitPlaybackRequestFingerprint.patternMatch!!.startIndex - - buildInitPlaybackRequestFingerprint.method.apply { - val targetRegister = getInstruction(moveUriStringIndex).registerA - - addInstructions( - moveUriStringIndex + 1, - """ - invoke-static { v$targetRegister }, $EXTENSION_CLASS_DESCRIPTOR->blockInitPlaybackRequest(Ljava/lang/String;)Ljava/lang/String; - move-result-object v$targetRegister - """, - ) - } - - // endregion - - // region Block /get_watch requests to fall back to /player requests. - - val invokeToStringIndex = buildPlayerRequestURIFingerprint.patternMatch!!.startIndex - - buildPlayerRequestURIFingerprint.method.apply { - val uriRegister = getInstruction(invokeToStringIndex).registerC - - addInstructions( - invokeToStringIndex, - """ - invoke-static { v$uriRegister }, $EXTENSION_CLASS_DESCRIPTOR->blockGetWatchRequest(Landroid/net/Uri;)Landroid/net/Uri; - move-result-object v$uriRegister - """, - ) - } - - // endregion - - // region Get replacement streams at player requests. - - buildRequestFingerprint.method.apply { - val newRequestBuilderIndex = indexOfFirstInstructionOrThrow { - opcode == Opcode.INVOKE_VIRTUAL && - getReference()?.name == "newUrlRequestBuilder" - } - val urlRegister = getInstruction(newRequestBuilderIndex).registerD - val freeRegister = getInstruction(newRequestBuilderIndex + 1).registerA - - addInstructions( - newRequestBuilderIndex, - """ - move-object v$freeRegister, p1 - invoke-static { v$urlRegister, v$freeRegister }, $EXTENSION_CLASS_DESCRIPTOR->fetchStreams(Ljava/lang/String;Ljava/util/Map;)V - """, - ) - } - - // endregion - - // region Replace the streaming data with the replacement streams. - - createStreamingDataFingerprint.method.apply { - val setStreamDataMethodName = "patch_setStreamingData" - val resultMethodType = createStreamingDataFingerprint.classDef.type - val videoDetailsIndex = createStreamingDataFingerprint.patternMatch!!.endIndex - val videoDetailsRegister = getInstruction(videoDetailsIndex).registerA - val videoDetailsClass = getInstruction(videoDetailsIndex).getReference()!!.type - - addInstruction( - videoDetailsIndex + 1, - "invoke-direct { p0, v$videoDetailsRegister }, " + - "$resultMethodType->$setStreamDataMethodName($videoDetailsClass)V", - ) - - val protobufClass = protobufClassParseByteBufferFingerprint.method.definingClass - val setStreamingDataIndex = createStreamingDataFingerprint.patternMatch!!.startIndex - - val playerProtoClass = getInstruction(setStreamingDataIndex + 1) - .getReference()!!.definingClass - - val setStreamingDataField = getInstruction(setStreamingDataIndex).getReference() - - val getStreamingDataField = getInstruction( - indexOfFirstInstructionOrThrow { - opcode == Opcode.IGET_OBJECT && getReference()?.definingClass == playerProtoClass - }, - ).getReference() - - // Use a helper method to avoid the need of picking out multiple free registers from the hooked code. - createStreamingDataFingerprint.classDef.methods.add( - ImmutableMethod( - resultMethodType, - setStreamDataMethodName, - listOf(ImmutableMethodParameter(videoDetailsClass, null, "videoDetails")), - "V", - AccessFlags.PRIVATE.value or AccessFlags.FINAL.value, - null, - null, - MutableMethodImplementation(9), - ).toMutable().apply { - addInstructionsWithLabels( - 0, - """ - invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->isSpoofingEnabled()Z - move-result v0 - if-eqz v0, :disabled - - # Get video id. - iget-object v2, p1, $videoDetailsClass->c:Ljava/lang/String; - if-eqz v2, :disabled - - # Get streaming data. - invoke-static { v2 }, $EXTENSION_CLASS_DESCRIPTOR->getStreamingData(Ljava/lang/String;)Ljava/nio/ByteBuffer; - move-result-object v3 - if-eqz v3, :disabled - - # Parse streaming data. - sget-object v4, $playerProtoClass->a:$playerProtoClass - invoke-static { v4, v3 }, $protobufClass->parseFrom(${protobufClass}Ljava/nio/ByteBuffer;)$protobufClass - move-result-object v5 - check-cast v5, $playerProtoClass - - # Set streaming data. - iget-object v6, v5, $getStreamingDataField - if-eqz v6, :disabled - iput-object v6, p0, $setStreamingDataField - - :disabled - return-void - """, - ) - }, - ) - } - - // endregion - - // region Remove /videoplayback request body to fix playback. - // It is assumed, YouTube makes a request with a body tuned for Android. - // Requesting streams intended for other platforms with a body tuned for Android could be the cause of 400 errors. - // A proper fix may include modifying the request body to match the platforms expected body. - - buildMediaDataSourceFingerprint.method.apply { - val targetIndex = instructions.lastIndex - - // Instructions are added just before the method returns, - // so there's no concern of clobbering in-use registers. - addInstructions( - targetIndex, - """ - # Field a: Stream uri. - # Field c: Http method. - # Field d: Post data. - move-object v0, p0 # method has over 15 registers and must copy p0 to a lower register. - iget-object v1, v0, $definingClass->a:Landroid/net/Uri; - iget v2, v0, $definingClass->c:I - iget-object v3, v0, $definingClass->d:[B - invoke-static { v1, v2, v3 }, $EXTENSION_CLASS_DESCRIPTOR->removeVideoPlaybackPostBody(Landroid/net/Uri;I[B)[B - move-result-object v1 - iput-object v1, v0, $definingClass->d:[B - """, - ) - } - // endregion - } +@Deprecated("Use app.revanced.patches.youtube.misc.spoof.spoofVideoStreamsPatch instead.") +@Suppress("unused") +val spoofVideoStreamsPatch = bytecodePatch { + dependsOn(app.revanced.patches.youtube.misc.spoof.spoofVideoStreamsPatch) } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/UserAgentClientSpoofPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/UserAgentClientSpoofPatch.kt index 8bbd0ec778..eb4c9492be 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/UserAgentClientSpoofPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/UserAgentClientSpoofPatch.kt @@ -1,82 +1,9 @@ package app.revanced.patches.youtube.misc.fix.playback -import app.revanced.patcher.extensions.InstructionExtensions.getInstruction -import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction -import app.revanced.patches.all.misc.transformation.IMethodCall -import app.revanced.patches.all.misc.transformation.filterMapInstruction35c -import app.revanced.patches.all.misc.transformation.transformInstructionsPatch -import app.revanced.util.getReference -import app.revanced.util.indexOfFirstInstruction -import com.android.tools.smali.dexlib2.Opcode -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.StringReference - -private const val ORIGINAL_PACKAGE_NAME = "com.google.android.youtube" -private const val USER_AGENT_STRING_BUILDER_APPEND_METHOD_REFERENCE = - "Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;" - -val userAgentClientSpoofPatch = transformInstructionsPatch( - filterMap = { classDef, _, instruction, instructionIndex -> - filterMapInstruction35c( - "Lapp/revanced/extension", - classDef, - instruction, - instructionIndex, - ) - }, - transform = transform@{ mutableMethod, entry -> - val (_, _, instructionIndex) = entry - - // Replace the result of context.getPackageName(), if it is used in a user agent string. - mutableMethod.apply { - // After context.getPackageName() the result is moved to a register. - val targetRegister = ( - getInstruction(instructionIndex + 1) - as? OneRegisterInstruction ?: return@transform - ).registerA - - // IndexOutOfBoundsException is technically possible here, - // but no such occurrences are present in the app. - val referee = getInstruction(instructionIndex + 2).getReference()?.toString() - - // Only replace string builder usage. - if (referee != USER_AGENT_STRING_BUILDER_APPEND_METHOD_REFERENCE) { - return@transform - } - - // Do not change the package name in methods that use resources, or for methods that use GmsCore. - // Changing these package names will result in playback limitations, - // particularly Android VR background audio only playback. - val resourceOrGmsStringInstructionIndex = indexOfFirstInstruction { - val reference = getReference() - opcode == Opcode.CONST_STRING && - (reference?.string == "android.resource://" || reference?.string == "gcore_") - } - if (resourceOrGmsStringInstructionIndex >= 0) { - return@transform - } - - // Overwrite the result of context.getPackageName() with the original package name. - replaceInstruction( - instructionIndex + 1, - "const-string v$targetRegister, \"$ORIGINAL_PACKAGE_NAME\"", - ) - } - }, -) +import app.revanced.patcher.patch.bytecodePatch +@Deprecated("Use app.revanced.patches.youtube.misc.spoof.userAgentClientSpoofPatch instead.") @Suppress("unused") -private enum class MethodCall( - override val definedClassName: String, - override val methodName: String, - override val methodParams: Array, - override val returnType: String, -) : IMethodCall { - GetPackageName( - "Landroid/content/Context;", - "getPackageName", - emptyArray(), - "Ljava/lang/String;", - ), +val userAgentClientSpoofPatch = bytecodePatch { + dependsOn(app.revanced.patches.youtube.misc.spoof.userAgentClientSpoofPatch) } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/gms/GmsCoreSupportPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/gms/GmsCoreSupportPatch.kt index bb86b663f9..dc73116ebf 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/gms/GmsCoreSupportPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/gms/GmsCoreSupportPatch.kt @@ -9,11 +9,11 @@ import app.revanced.patches.shared.misc.settings.preference.IntentPreference import app.revanced.patches.shared.primeMethodFingerprint import app.revanced.patches.youtube.layout.buttons.overlay.hidePlayerOverlayButtonsPatch import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch -import app.revanced.patches.youtube.misc.fix.playback.spoofVideoStreamsPatch import app.revanced.patches.youtube.misc.gms.Constants.REVANCED_YOUTUBE_PACKAGE_NAME import app.revanced.patches.youtube.misc.gms.Constants.YOUTUBE_PACKAGE_NAME import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.settingsPatch +import app.revanced.patches.youtube.misc.spoof.spoofVideoStreamsPatch import app.revanced.patches.youtube.shared.mainActivityOnCreateFingerprint @Suppress("unused") diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/spoof/SpoofVideoStreamsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/spoof/SpoofVideoStreamsPatch.kt new file mode 100644 index 0000000000..a6181db7e4 --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/spoof/SpoofVideoStreamsPatch.kt @@ -0,0 +1,52 @@ +package app.revanced.patches.youtube.misc.spoof + +import app.revanced.patches.all.misc.resources.addResources +import app.revanced.patches.shared.misc.settings.preference.ListPreference +import app.revanced.patches.shared.misc.settings.preference.NonInteractivePreference +import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference +import app.revanced.patches.shared.misc.spoof.spoofVideoStreamsPatch +import app.revanced.patches.youtube.misc.settings.PreferenceScreen +import app.revanced.patches.youtube.misc.settings.settingsPatch + +val spoofVideoStreamsPatch = spoofVideoStreamsPatch({ + compatibleWith( + "com.google.android.youtube"( + "18.38.44", + "18.49.37", + "19.16.39", + "19.25.37", + "19.34.42", + "19.43.41", + "19.45.38", + "19.46.42", + ), + ) + + dependsOn( + userAgentClientSpoofPatch, + settingsPatch, + ) +}, { + addResources("youtube", "misc.fix.playback.spoofVideoStreamsPatch") + + PreferenceScreen.MISC.addPreferences( + PreferenceScreenPreference( + key = "revanced_spoof_video_streams_screen", + sorting = PreferenceScreenPreference.Sorting.UNSORTED, + preferences = setOf( + SwitchPreference("revanced_spoof_video_streams"), + ListPreference( + "revanced_spoof_video_streams_client", + summaryKey = null, + ), + SwitchPreference( + "revanced_spoof_video_streams_ios_force_avc", + tag = "app.revanced.extension.youtube.settings.preference.ForceAVCSpoofingPreference", + ), + NonInteractivePreference("revanced_spoof_video_streams_about_android_vr"), + NonInteractivePreference("revanced_spoof_video_streams_about_ios"), + ), + ), + ) +}) diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/spoof/UserAgentClientSpoofPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/spoof/UserAgentClientSpoofPatch.kt new file mode 100644 index 0000000000..d9b6596138 --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/spoof/UserAgentClientSpoofPatch.kt @@ -0,0 +1,82 @@ +package app.revanced.patches.youtube.misc.spoof + +import app.revanced.patcher.extensions.InstructionExtensions.getInstruction +import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction +import app.revanced.patches.all.misc.transformation.IMethodCall +import app.revanced.patches.all.misc.transformation.filterMapInstruction35c +import app.revanced.patches.all.misc.transformation.transformInstructionsPatch +import app.revanced.util.getReference +import app.revanced.util.indexOfFirstInstruction +import com.android.tools.smali.dexlib2.Opcode +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.StringReference + +private const val ORIGINAL_PACKAGE_NAME = "com.google.android.youtube" +private const val USER_AGENT_STRING_BUILDER_APPEND_METHOD_REFERENCE = + "Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;" + +val userAgentClientSpoofPatch = transformInstructionsPatch( + filterMap = { classDef, _, instruction, instructionIndex -> + filterMapInstruction35c( + "Lapp/revanced/extension", + classDef, + instruction, + instructionIndex, + ) + }, + transform = transform@{ mutableMethod, entry -> + val (_, _, instructionIndex) = entry + + // Replace the result of context.getPackageName(), if it is used in a user agent string. + mutableMethod.apply { + // After context.getPackageName() the result is moved to a register. + val targetRegister = ( + getInstruction(instructionIndex + 1) + as? OneRegisterInstruction ?: return@transform + ).registerA + + // IndexOutOfBoundsException is technically possible here, + // but no such occurrences are present in the app. + val referee = getInstruction(instructionIndex + 2).getReference()?.toString() + + // Only replace string builder usage. + if (referee != USER_AGENT_STRING_BUILDER_APPEND_METHOD_REFERENCE) { + return@transform + } + + // Do not change the package name in methods that use resources, or for methods that use GmsCore. + // Changing these package names will result in playback limitations, + // particularly Android VR background audio only playback. + val resourceOrGmsStringInstructionIndex = indexOfFirstInstruction { + val reference = getReference() + opcode == Opcode.CONST_STRING && + (reference?.string == "android.resource://" || reference?.string == "gcore_") + } + if (resourceOrGmsStringInstructionIndex >= 0) { + return@transform + } + + // Overwrite the result of context.getPackageName() with the original package name. + replaceInstruction( + instructionIndex + 1, + "const-string v$targetRegister, \"$ORIGINAL_PACKAGE_NAME\"", + ) + } + }, +) + +@Suppress("unused") +private enum class MethodCall( + override val definedClassName: String, + override val methodName: String, + override val methodParams: Array, + override val returnType: String, +) : IMethodCall { + GetPackageName( + "Landroid/content/Context;", + "getPackageName", + emptyArray(), + "Ljava/lang/String;", + ), +}