feat(YouTube Music): Add Spoof video streams patch to fix playback (#4065)

Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
This commit is contained in:
oSumAtrIX 2024-12-08 16:19:29 +01:00 committed by GitHub
parent 6a44e75203
commit cf3116a758
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 563 additions and 504 deletions

View File

@ -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.
*
* <p>
* 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<ClientType> SPOOF_VIDEO_STREAMS_CLIENT_TYPE = new EnumSetting<>("revanced_spoof_video_streams_client", ClientType.ANDROID_VR, true, parent(SPOOF_VIDEO_STREAMS));
}

View File

@ -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;

View File

@ -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() {

View File

@ -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.Logger;
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 class SpoofVideoStreamsPatch {
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;
}
}
}

View File

@ -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.Logger;
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(

View File

@ -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 java.util.concurrent.TimeoutException;
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 @@ public class StreamingDataRequest {
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;

View File

@ -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;
}
}

View File

@ -2,25 +2,42 @@ package app.revanced.extension.youtube.settings;
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<ThumbnailOption> ALT_THUMBNAIL_HOME = new EnumSetting<>("revanced_alt_thumbnail_home", ThumbnailOption.ORIGINAL);
public static final EnumSetting<ThumbnailOption> 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<ThumbnailStillTime> 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.
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_CAPTIONS_BUTTON = new BooleanSetting("revanced_hide_captions_button", FALSE);
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_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 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 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_COMMUNITY_GUIDELINES = new BooleanSetting("revanced_hide_community_guidelines", 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_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_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_MEDICAL_PANELS = new BooleanSetting("revanced_hide_medical_panels", 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_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_VIDEO_CHANNEL_WATERMARK = new BooleanSetting("revanced_hide_channel_watermark", 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<MiniplayerType> 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_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_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_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_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_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_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);
// 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_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_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_LOCK_SCREEN = new BooleanSetting("revanced_hide_player_flyout_lock_screen", 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<StartPage> 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<StartPage> 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 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_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_LOCATION_LABEL = new BooleanSetting("revanced_hide_shorts_location_label", FALSE);
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 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_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_HOME = new BooleanSetting("revanced_hide_shorts_home", FALSE);
public static final BooleanSetting HIDE_SHORTS_INFO_PANEL = new BooleanSetting("revanced_hide_shorts_info_panel", 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_JOIN_BUTTON = new BooleanSetting("revanced_hide_shorts_join_button", 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_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_SHARE_BUTTON = new BooleanSetting("revanced_hide_shorts_share_button", FALSE);
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_SOUND_METADATA_LABEL = new BooleanSetting("revanced_hide_shorts_sound_metadata_label", FALSE);
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 AUTO_REPEAT = new BooleanSetting("revanced_auto_repeat", FALSE);
public static final BooleanSetting BYPASS_URL_REDIRECTS = new BooleanSetting("revanced_bypass_url_redirects", TRUE);
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 AUTO_REPEAT = new BooleanSetting("revanced_auto_repeat", FALSE);
public static final BooleanSetting REMOVE_TRACKING_QUERY_PARAMETER = new BooleanSetting("revanced_remove_tracking_query_parameter", TRUE);
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<ClientType> 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 REMOVE_TRACKING_QUERY_PARAMETER = new BooleanSetting("revanced_remove_tracking_query_parameter", TRUE);
// Debugging
/**
* 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));
@ -338,7 +336,6 @@ public class Settings extends BaseSettings {
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_SELF_PROMO = new StringSetting("sb_selfpromo", MANUAL_SKIP.reVancedKeyValue);
@ -360,6 +357,11 @@ public class Settings extends BaseSettings {
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");
// 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

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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)
}

View File

@ -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")
})

View File

@ -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",
)

View File

@ -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<OneRegisterInstruction>(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<FiveRegisterInstruction>(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<MethodReference>()?.name == "newUrlRequestBuilder"
}
val urlRegister = getInstruction<FiveRegisterInstruction>(newRequestBuilderIndex).registerD
val freeRegister = getInstruction<OneRegisterInstruction>(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<TwoRegisterInstruction>(videoDetailsIndex).registerA
val videoDetailsClass = getInstruction(videoDetailsIndex).getReference<FieldReference>()!!.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<FieldReference>()!!.definingClass
val setStreamingDataField = getInstruction(setStreamingDataIndex).getReference<FieldReference>()
val getStreamingDataField = getInstruction(
indexOfFirstInstructionOrThrow {
opcode == Opcode.IGET_OBJECT && getReference<FieldReference>()?.definingClass == playerProtoClass
},
).getReference<FieldReference>()
// 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()
}
}

View File

@ -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<OneRegisterInstruction>(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<FiveRegisterInstruction>(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<MethodReference>()?.name == "newUrlRequestBuilder"
}
val urlRegister = getInstruction<FiveRegisterInstruction>(newRequestBuilderIndex).registerD
val freeRegister = getInstruction<OneRegisterInstruction>(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<TwoRegisterInstruction>(videoDetailsIndex).registerA
val videoDetailsClass = getInstruction(videoDetailsIndex).getReference<FieldReference>()!!.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<FieldReference>()!!.definingClass
val setStreamingDataField = getInstruction(setStreamingDataIndex).getReference<FieldReference>()
val getStreamingDataField = getInstruction(
indexOfFirstInstructionOrThrow {
opcode == Opcode.IGET_OBJECT && getReference<FieldReference>()?.definingClass == playerProtoClass
},
).getReference<FieldReference>()
// 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)
}

View File

@ -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<MethodCall>(
"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<MethodReference>()?.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<StringReference>()
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<String>,
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)
}

View File

@ -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")

View File

@ -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"),
),
),
)
})

View File

@ -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<MethodCall>(
"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<MethodReference>()?.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<StringReference>()
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<String>,
override val returnType: String,
) : IMethodCall {
GetPackageName(
"Landroid/content/Context;",
"getPackageName",
emptyArray(),
"Ljava/lang/String;",
),
}