diff --git a/CHANGELOG.md b/CHANGELOG.md index 17481f04f..5728a55aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,31 @@ +# [5.41.0-dev.10](https://github.com/ReVanced/revanced-patches/compare/v5.41.0-dev.9...v5.41.0-dev.10) (2025-09-23) + + +### Bug Fixes + +* **TikTok:** Show correct dialog restart text, use correct font color for non-dark mode ([d1a1293](https://github.com/ReVanced/revanced-patches/commit/d1a12930c35f630793a0f240d4203c2ff9060158)) + +# [5.41.0-dev.9](https://github.com/ReVanced/revanced-patches/compare/v5.41.0-dev.8...v5.41.0-dev.9) (2025-09-23) + + +### Bug Fixes + +* **Instagram - Hide navigation buttons:** Remove button based on name ([#5971](https://github.com/ReVanced/revanced-patches/issues/5971)) ([6fa4043](https://github.com/ReVanced/revanced-patches/commit/6fa404331b5162682d83fba5f38ed570c31495fc)) + +# [5.41.0-dev.8](https://github.com/ReVanced/revanced-patches/compare/v5.41.0-dev.7...v5.41.0-dev.8) (2025-09-23) + + +### Features + +* **YouTube Music:** Add `Check watch history domain name resolution` ([#5979](https://github.com/ReVanced/revanced-patches/issues/5979)) ([8af70fe](https://github.com/ReVanced/revanced-patches/commit/8af70fe2d10c0f4da2d7e53bd00f5b3979775d5d)) + +# [5.41.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v5.41.0-dev.6...v5.41.0-dev.7) (2025-09-23) + + +### Features + +* **Tumblr:** Add `Disable Tumblr TV` patch ([#5959](https://github.com/ReVanced/revanced-patches/issues/5959)) ([212418b](https://github.com/ReVanced/revanced-patches/commit/212418b8db9a730ae9efa89ad2bef24952afbadd)) + # [5.41.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v5.41.0-dev.5...v5.41.0-dev.6) (2025-09-22) diff --git a/extensions/instagram/src/main/java/app/revanced/extension/instagram/hide/navigation/HideNavigationButtonsPatch.java b/extensions/instagram/src/main/java/app/revanced/extension/instagram/hide/navigation/HideNavigationButtonsPatch.java new file mode 100644 index 000000000..1dd99e204 --- /dev/null +++ b/extensions/instagram/src/main/java/app/revanced/extension/instagram/hide/navigation/HideNavigationButtonsPatch.java @@ -0,0 +1,33 @@ +package app.revanced.extension.instagram.hide.navigation; + +import java.lang.reflect.Field; +import java.util.List; + +@SuppressWarnings("unused") +public class HideNavigationButtonsPatch { + + /** + * Injection point. + * @param navigationButtonsList the list of navigation buttons, as an (obfuscated) Enum type + * @param buttonNameToRemove the name of the button we want to remove + * @param enumNameField the field in the nav button enum class which contains the name of the button + * @return the patched list of navigation buttons + */ + public static List removeNavigationButtonByName( + List navigationButtonsList, + String buttonNameToRemove, + String enumNameField + ) + throws IllegalAccessException, NoSuchFieldException { + for (Object button : navigationButtonsList) { + Field f = button.getClass().getDeclaredField(enumNameField); + String currentButtonEnumName = (String) f.get(button); + + if (buttonNameToRemove.equals(currentButtonEnumName)) { + navigationButtonsList.remove(button); + break; + } + } + return navigationButtonsList; + } +} diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/CheckWatchHistoryDomainNameResolutionPatch.java b/extensions/shared/library/src/main/java/app/revanced/extension/shared/patches/CheckWatchHistoryDomainNameResolutionPatch.java similarity index 88% rename from extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/CheckWatchHistoryDomainNameResolutionPatch.java rename to extensions/shared/library/src/main/java/app/revanced/extension/shared/patches/CheckWatchHistoryDomainNameResolutionPatch.java index 62a0a0de8..ff2c55ade 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/CheckWatchHistoryDomainNameResolutionPatch.java +++ b/extensions/shared/library/src/main/java/app/revanced/extension/shared/patches/CheckWatchHistoryDomainNameResolutionPatch.java @@ -1,4 +1,4 @@ -package app.revanced.extension.youtube.patches; +package app.revanced.extension.shared.patches; import static app.revanced.extension.shared.StringRef.str; @@ -13,8 +13,8 @@ import java.net.UnknownHostException; import app.revanced.extension.shared.Logger; import app.revanced.extension.shared.Utils; +import app.revanced.extension.shared.settings.BaseSettings; import app.revanced.extension.shared.ui.CustomDialog; -import app.revanced.extension.youtube.settings.Settings; @SuppressWarnings("unused") public class CheckWatchHistoryDomainNameResolutionPatch { @@ -49,7 +49,7 @@ public class CheckWatchHistoryDomainNameResolutionPatch { * Checks if s.youtube.com is blacklisted and playback history will fail to work. */ public static void checkDnsResolver(Activity context) { - if (!Utils.isNetworkConnected() || !Settings.CHECK_WATCH_HISTORY_DOMAIN_NAME.get()) return; + if (!Utils.isNetworkConnected() || !BaseSettings.CHECK_WATCH_HISTORY_DOMAIN_NAME.get()) return; Utils.runOnBackgroundThread(() -> { try { @@ -61,8 +61,8 @@ public class CheckWatchHistoryDomainNameResolutionPatch { // Prevent this false positive by verify youtube.com resolves. // If youtube.com does not resolve, then it's not a watch history domain resolving error // because the entire app will not work since no domains are resolving. - if (domainResolvesToValidIP(HISTORY_TRACKING_ENDPOINT) - || !domainResolvesToValidIP("youtube.com")) { + if (!domainResolvesToValidIP("youtube.com") + || domainResolvesToValidIP(HISTORY_TRACKING_ENDPOINT)) { return; } @@ -78,7 +78,7 @@ public class CheckWatchHistoryDomainNameResolutionPatch { () -> {}, // OK button action (just dismiss). () -> {}, // Cancel button action (just dismiss). str("revanced_check_watch_history_domain_name_dialog_ignore"), // Neutral button text. - () -> Settings.CHECK_WATCH_HISTORY_DOMAIN_NAME.save(false), // Neutral button action (Ignore). + () -> BaseSettings.CHECK_WATCH_HISTORY_DOMAIN_NAME.save(false), // Neutral button action (Ignore). true // Dismiss dialog on Neutral button click. ); 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 f42c38379..1eff30361 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 @@ -28,10 +28,16 @@ public class BaseSettings { public static final BooleanSetting SETTINGS_SEARCH_HISTORY = new BooleanSetting("revanced_settings_search_history", TRUE, true); public static final StringSetting SETTINGS_SEARCH_ENTRIES = new StringSetting("revanced_settings_search_entries", ""); + // + // Settings shared by YouTube and YouTube Music. + // + 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 EnumSetting SPOOF_VIDEO_STREAMS_LANGUAGE = new EnumSetting<>("revanced_spoof_video_streams_language", AppLanguage.DEFAULT, new AudioStreamLanguageOverrideAvailability()); public static final BooleanSetting SPOOF_STREAMING_DATA_STATS_FOR_NERDS = new BooleanSetting("revanced_spoof_streaming_data_stats_for_nerds", TRUE, parent(SPOOF_VIDEO_STREAMS)); public static final BooleanSetting SANITIZE_SHARED_LINKS = new BooleanSetting("revanced_sanitize_sharing_links", TRUE); public static final BooleanSetting REPLACE_MUSIC_LINKS_WITH_YOUTUBE = new BooleanSetting("revanced_replace_music_with_youtube", FALSE); + + public static final BooleanSetting CHECK_WATCH_HISTORY_DOMAIN_NAME = new BooleanSetting("revanced_check_watch_history_domain_name", TRUE, false, false); } diff --git a/extensions/shared/library/src/main/java/app/revanced/extension/shared/settings/preference/AbstractPreferenceFragment.java b/extensions/shared/library/src/main/java/app/revanced/extension/shared/settings/preference/AbstractPreferenceFragment.java index e829b8b1f..67fa51fce 100644 --- a/extensions/shared/library/src/main/java/app/revanced/extension/shared/settings/preference/AbstractPreferenceFragment.java +++ b/extensions/shared/library/src/main/java/app/revanced/extension/shared/settings/preference/AbstractPreferenceFragment.java @@ -54,7 +54,7 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment { * Set by subclasses if Strings cannot be added as a resource. */ @Nullable - protected static String restartDialogButtonText, restartDialogTitle, confirmDialogTitle, restartDialogMessage; + protected static CharSequence restartDialogTitle, restartDialogMessage, restartDialogButtonText, confirmDialogTitle; private final SharedPreferences.OnSharedPreferenceChangeListener listener = (sharedPreferences, str) -> { try { @@ -126,10 +126,13 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment { showingUserDialogMessage = true; + CharSequence message = BulletPointPreference.formatIntoBulletPoints( + Objects.requireNonNull(setting.userDialogMessage).toString()); + Pair dialogPair = CustomDialog.create( context, confirmDialogTitle, // Title. - Objects.requireNonNull(setting.userDialogMessage).toString(), // No message. + message, null, // No EditText. null, // OK button text. () -> { @@ -153,6 +156,7 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment { ); dialogPair.first.setOnDismissListener(d -> showingUserDialogMessage = false); + dialogPair.first.setCancelable(false); // Show the dialog. dialogPair.first.show(); diff --git a/extensions/shared/library/src/main/java/app/revanced/extension/shared/settings/preference/BulletPointPreference.java b/extensions/shared/library/src/main/java/app/revanced/extension/shared/settings/preference/BulletPointPreference.java index 204697228..ee3f02fc8 100644 --- a/extensions/shared/library/src/main/java/app/revanced/extension/shared/settings/preference/BulletPointPreference.java +++ b/extensions/shared/library/src/main/java/app/revanced/extension/shared/settings/preference/BulletPointPreference.java @@ -15,7 +15,15 @@ import android.util.AttributeSet; @SuppressWarnings({"unused", "deprecation"}) public class BulletPointPreference extends Preference { - public static SpannedString formatIntoBulletPoints(CharSequence source) { + /** + * Replaces bullet points with styled spans. + */ + public static CharSequence formatIntoBulletPoints(CharSequence source) { + final char bulletPoint = '•'; + if (TextUtils.indexOf(source, bulletPoint) < 0) { + return source; // Nothing to do. + } + SpannableStringBuilder builder = new SpannableStringBuilder(source); int lineStart = 0; @@ -26,7 +34,7 @@ public class BulletPointPreference extends Preference { if (lineEnd < 0) lineEnd = length; // Apply BulletSpan only if the line starts with the '•' character. - if (lineEnd > lineStart && builder.charAt(lineStart) == '•') { + if (lineEnd > lineStart && builder.charAt(lineStart) == bulletPoint) { int deleteEnd = lineStart + 1; // remove the bullet itself // If there's a single space right after the bullet, remove that too. diff --git a/extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/requests/PlayerRoutes.java b/extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/requests/PlayerRoutes.java index ef5907b01..cfc811d75 100644 --- a/extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/requests/PlayerRoutes.java +++ b/extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/requests/PlayerRoutes.java @@ -42,11 +42,8 @@ final class PlayerRoutes { JSONObject context = new JSONObject(); AppLanguage language = SpoofVideoStreamsPatch.getLanguageOverride(); - if (language == null || clientType == ANDROID_VR_1_43_32) { + if (language == null) { // Force original audio has not overrode the language. - // Or if YT has fallen over to the last unauthenticated client (VR 1.43), then - // always use the app language because forcing an audio stream of specific languages - // can sometimes fail so it's better to try and load something rather than nothing. language = BaseSettings.SPOOF_VIDEO_STREAMS_LANGUAGE.get(); } //noinspection ExtractMethodRecommender diff --git a/extensions/shared/library/src/main/java/app/revanced/extension/shared/ui/CustomDialog.java b/extensions/shared/library/src/main/java/app/revanced/extension/shared/ui/CustomDialog.java index 43a698ed1..1b65bea32 100644 --- a/extensions/shared/library/src/main/java/app/revanced/extension/shared/ui/CustomDialog.java +++ b/extensions/shared/library/src/main/java/app/revanced/extension/shared/ui/CustomDialog.java @@ -58,10 +58,10 @@ public class CustomDialog { * @param dismissDialogOnNeutralClick If the dialog should be dismissed when the Neutral button is clicked. * @return The Dialog and its main LinearLayout container. */ - public static Pair create(Context context, String title, CharSequence message, - @Nullable EditText editText, String okButtonText, + public static Pair create(Context context, CharSequence title, CharSequence message, + @Nullable EditText editText, CharSequence okButtonText, Runnable onOkClick, Runnable onCancelClick, - @Nullable String neutralButtonText, + @Nullable CharSequence neutralButtonText, @Nullable Runnable onNeutralClick, boolean dismissDialogOnNeutralClick) { Logger.printDebug(() -> "Creating custom dialog with title: " + title); @@ -85,9 +85,9 @@ public class CustomDialog { * @param onNeutralClick Action to perform when the Neutral button is clicked, or null if no Neutral button is needed. * @param dismissDialogOnNeutralClick If the dialog should be dismissed when the Neutral button is clicked. */ - private CustomDialog(Context context, String title, CharSequence message, @Nullable EditText editText, - String okButtonText, Runnable onOkClick, Runnable onCancelClick, - @Nullable String neutralButtonText, @Nullable Runnable onNeutralClick, + private CustomDialog(Context context, CharSequence title, CharSequence message, @Nullable EditText editText, + CharSequence okButtonText, Runnable onOkClick, Runnable onCancelClick, + @Nullable CharSequence neutralButtonText, @Nullable Runnable onNeutralClick, boolean dismissDialogOnNeutralClick) { this.context = context; this.dialog = new Dialog(context); @@ -139,7 +139,7 @@ public class CustomDialog { * * @param title The title text to display. */ - private void addTitle(String title) { + private void addTitle(CharSequence title) { if (TextUtils.isEmpty(title)) return; TextView titleView = new TextView(context); @@ -232,8 +232,8 @@ public class CustomDialog { * @param onNeutralClick Action for the Neutral button click, or null if no Neutral button. * @param dismissDialogOnNeutralClick If the dialog should dismiss on Neutral button click. */ - private void addButtons(String okButtonText, Runnable onOkClick, Runnable onCancelClick, - @Nullable String neutralButtonText, @Nullable Runnable onNeutralClick, + private void addButtons(CharSequence okButtonText, Runnable onOkClick, Runnable onCancelClick, + @Nullable CharSequence neutralButtonText, @Nullable Runnable onNeutralClick, boolean dismissDialogOnNeutralClick) { // Button container. LinearLayout buttonContainer = new LinearLayout(context); @@ -280,7 +280,7 @@ public class CustomDialog { * @param dismissDialog If the dialog should dismiss when the button is clicked. * @return The created Button. */ - private Button createButton(String text, Runnable onClick, boolean isOkButton, boolean dismissDialog) { + private Button createButton(CharSequence text, Runnable onClick, boolean isOkButton, boolean dismissDialog) { Button button = new Button(context, null, 0); button.setText(text); button.setTextSize(14); diff --git a/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/settings/preference/TikTokPreferenceFragment.java b/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/settings/preference/TikTokPreferenceFragment.java index cf7223333..82120de78 100644 --- a/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/settings/preference/TikTokPreferenceFragment.java +++ b/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/settings/preference/TikTokPreferenceFragment.java @@ -2,12 +2,15 @@ package app.revanced.extension.tiktok.settings.preference; import android.preference.Preference; import android.preference.PreferenceScreen; + import androidx.annotation.NonNull; + +import app.revanced.extension.shared.Utils; import app.revanced.extension.shared.settings.Setting; import app.revanced.extension.shared.settings.preference.AbstractPreferenceFragment; import app.revanced.extension.tiktok.settings.preference.categories.DownloadsPreferenceCategory; -import app.revanced.extension.tiktok.settings.preference.categories.FeedFilterPreferenceCategory; import app.revanced.extension.tiktok.settings.preference.categories.ExtensionPreferenceCategory; +import app.revanced.extension.tiktok.settings.preference.categories.FeedFilterPreferenceCategory; import app.revanced.extension.tiktok.settings.preference.categories.SimSpoofPreferenceCategory; /** @@ -37,10 +40,14 @@ public class TikTokPreferenceFragment extends AbstractPreferenceFragment { // Currently no resources can be compiled for TikTok (fails with aapt error). // So all TikTok Strings are hard coded in the extension. - restartDialogTitle = "Refresh and restart"; + restartDialogTitle = "Restart required"; + restartDialogMessage = "Restart the app for this change to take effect."; restartDialogButtonText = "Restart"; confirmDialogTitle = "Do you wish to proceed?"; + // App does not use dark mode. + Utils.setIsDarkModeEnabled(false); + PreferenceScreen preferenceScreen = getPreferenceManager().createPreferenceScreen(context); setPreferenceScreen(preferenceScreen); diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/DisableHdrPatch.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/DisableVideoCodecsPatch.java similarity index 71% rename from extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/DisableHdrPatch.java rename to extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/DisableVideoCodecsPatch.java index d89bf72f5..5e4dd06f6 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/DisableHdrPatch.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/DisableVideoCodecsPatch.java @@ -5,7 +5,7 @@ import android.view.Display; import app.revanced.extension.youtube.settings.Settings; @SuppressWarnings("unused") -public class DisableHdrPatch { +public class DisableVideoCodecsPatch { /** * Injection point. @@ -15,5 +15,12 @@ public class DisableHdrPatch { ? new int[0] : capabilities.getSupportedHdrTypes(); } + + /** + * Injection point. + */ + public static boolean allowVP9() { + return !Settings.FORCE_AVC_CODEC.get(); + } } diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/ForceOriginalAudioPatch.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/ForceOriginalAudioPatch.java index 290928f98..8836e7b32 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/ForceOriginalAudioPatch.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/ForceOriginalAudioPatch.java @@ -15,7 +15,8 @@ public class ForceOriginalAudioPatch { */ public static void setPreferredLanguage() { if (Settings.FORCE_ORIGINAL_AUDIO.get() - && SpoofVideoStreamsPatch.spoofingToClientWithNoMultiAudioStreams()) { + && SpoofVideoStreamsPatch.spoofingToClientWithNoMultiAudioStreams() + && !Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get().useAuth) { // If client spoofing does not use authentication and lacks multi-audio streams, // then can use any language code for the request and if that requested language is // not available YT uses the original audio language. Authenticated requests ignore diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/spoof/SpoofVideoStreamsPatch.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/spoof/SpoofVideoStreamsPatch.java index 2af74b2a0..da200ef67 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/spoof/SpoofVideoStreamsPatch.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/spoof/SpoofVideoStreamsPatch.java @@ -18,7 +18,22 @@ public class SpoofVideoStreamsPatch { * Injection point. */ public static void setClientOrderToUse() { - List availableClients = List.of( + final boolean forceAVC = Settings.FORCE_AVC_CODEC.get(); + + // VR 1.61 uses VP9/AV1, and cannot force AVC. + ClientType client = Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get(); + if (forceAVC && client == ANDROID_VR_1_61_48) { + client = ANDROID_VR_1_43_32; // Use VR 1.43 instead. + } + + List availableClients = forceAVC + ? List.of( + ANDROID_VR_1_43_32, + VISIONOS, + ANDROID_CREATOR, + ANDROID_VR_1_61_48, + IPADOS) + : List.of( ANDROID_VR_1_61_48, VISIONOS, ANDROID_CREATOR, @@ -27,6 +42,6 @@ public class SpoofVideoStreamsPatch { ); app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch.setClientsToUse( - availableClients, Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get()); + availableClients, client); } } \ No newline at end of file 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 6d8faac12..404c015a7 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 @@ -53,6 +53,9 @@ import app.revanced.extension.youtube.swipecontrols.SwipeControlsConfigurationPr public class Settings extends BaseSettings { // Video + public static final BooleanSetting ADVANCED_VIDEO_QUALITY_MENU = new BooleanSetting("revanced_advanced_video_quality_menu", TRUE); + public static final BooleanSetting DISABLE_HDR_VIDEO = new BooleanSetting("revanced_disable_hdr_video", FALSE); + public static final BooleanSetting FORCE_AVC_CODEC = new BooleanSetting("revanced_force_avc_codec", FALSE, true, "revanced_force_avc_codec_user_dialog_message"); public static final IntegerSetting VIDEO_QUALITY_DEFAULT_WIFI = new IntegerSetting("revanced_video_quality_default_wifi", -2); public static final IntegerSetting VIDEO_QUALITY_DEFAULT_MOBILE = new IntegerSetting("revanced_video_quality_default_mobile", -2); public static final BooleanSetting REMEMBER_VIDEO_QUALITY_LAST_SELECTED = new BooleanSetting("revanced_remember_video_quality_last_selected", FALSE); @@ -61,8 +64,6 @@ public class Settings extends BaseSettings { public static final BooleanSetting REMEMBER_SHORTS_QUALITY_LAST_SELECTED = new BooleanSetting("revanced_remember_shorts_quality_last_selected", FALSE); public static final BooleanSetting REMEMBER_VIDEO_QUALITY_LAST_SELECTED_TOAST = new BooleanSetting("revanced_remember_video_quality_last_selected_toast", TRUE, false, parentsAny(REMEMBER_VIDEO_QUALITY_LAST_SELECTED, REMEMBER_SHORTS_QUALITY_LAST_SELECTED)); - public static final BooleanSetting ADVANCED_VIDEO_QUALITY_MENU = new BooleanSetting("revanced_advanced_video_quality_menu", TRUE); - public static final BooleanSetting DISABLE_HDR_VIDEO = new BooleanSetting("revanced_disable_hdr_video", FALSE); // Speed public static final FloatSetting SPEED_TAP_AND_HOLD = new FloatSetting("revanced_speed_tap_and_hold", 2.0f, true); @@ -351,7 +352,6 @@ public class Settings extends BaseSettings { public static final BooleanSetting LOOP_VIDEO = new BooleanSetting("revanced_loop_video", FALSE); public static final BooleanSetting LOOP_VIDEO_BUTTON = new BooleanSetting("revanced_loop_video_button", 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_HAPTIC_FEEDBACK_CHAPTERS = new BooleanSetting("revanced_disable_haptic_feedback_chapters", FALSE); public static final BooleanSetting DISABLE_HAPTIC_FEEDBACK_PRECISE_SEEKING = new BooleanSetting("revanced_disable_haptic_feedback_precise_seeking", FALSE); public static final BooleanSetting DISABLE_HAPTIC_FEEDBACK_SEEK_UNDO = new BooleanSetting("revanced_disable_haptic_feedback_seek_undo", FALSE); diff --git a/gradle.properties b/gradle.properties index 88da24c5d..0e2be7f81 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,4 +3,4 @@ org.gradle.jvmargs = -Xms512M -Xmx2048M org.gradle.parallel = true android.useAndroidX = true kotlin.code.style = official -version = 5.41.0-dev.6 +version = 5.41.0-dev.10 diff --git a/patches/api/patches.api b/patches/api/patches.api index caa37632b..166ca34d7 100644 --- a/patches/api/patches.api +++ b/patches/api/patches.api @@ -368,6 +368,10 @@ public final class app/revanced/patches/music/misc/debugging/EnableDebuggingPatc public static final fun getEnableDebuggingPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } +public final class app/revanced/patches/music/misc/dns/CheckWatchHistoryDomainNameResolutionPatchKt { + public static final fun getCheckWatchHistoryDomainNameResolutionPatch ()Lapp/revanced/patcher/patch/BytecodePatch; +} + public final class app/revanced/patches/music/misc/extension/SharedExtensionPatchKt { public static final fun getSharedExtensionPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } @@ -1642,6 +1646,10 @@ public final class app/revanced/patches/youtube/video/audio/ForceOriginalAudioPa public static final fun getForceOriginalAudioPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } +public final class app/revanced/patches/youtube/video/codecs/DisableVideoCodecsPatchKt { + public static final fun getDisableVideoCodecsPatch ()Lapp/revanced/patcher/patch/BytecodePatch; +} + public final class app/revanced/patches/youtube/video/hdr/DisableHdrPatchKt { public static final fun getDisableHdrPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } diff --git a/patches/src/main/kotlin/app/revanced/patches/instagram/hide/navigation/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/instagram/hide/navigation/Fingerprints.kt index 870eed3f5..21653771a 100644 --- a/patches/src/main/kotlin/app/revanced/patches/instagram/hide/navigation/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/instagram/hide/navigation/Fingerprints.kt @@ -2,28 +2,22 @@ package app.revanced.patches.instagram.hide.navigation import app.revanced.patcher.fingerprint -import com.android.tools.smali.dexlib2.Opcode +import app.revanced.patcher.patch.BytecodePatchContext -internal val tabCreateButtonsLoopStartFingerprint by fingerprint { - returns("V") - strings("InstagramMainActivity.createTabButtons") - opcodes( - //Loop Start - Opcode.IF_GE, // Check if index is finished (index, size) - //Injection - Opcode.INVOKE_INTERFACE, - Opcode.MOVE_RESULT_OBJECT - ) +internal val initializeNavigationButtonsListFingerprint = fingerprint { + strings("Nav3") + parameters("Lcom/instagram/common/session/UserSession;", "Z") + returns("Ljava/util/List;") } -internal val tabCreateButtonsLoopEndFingerprint by fingerprint { - returns("V") - strings("InstagramMainActivity.createTabButtons") - opcodes( - Opcode.IPUT_OBJECT, - // Injection Jump - Opcode.ADD_INT_LIT8, //Increase Index - Opcode.GOTO // Jump to loopStart - // LoopEnd - ) +private val navigationButtonsEnumClassDef by fingerprint { + strings("FEED", "fragment_feed", "SEARCH", "fragment_search") +} + +context(BytecodePatchContext) +internal val navigationButtonsEnumInitFingerprint get() = fingerprint { + custom { method, classDef -> + method.name == "" + && classDef == navigationButtonsEnumClassDef.classDef + } } diff --git a/patches/src/main/kotlin/app/revanced/patches/instagram/hide/navigation/HideNavigationButtons.kt b/patches/src/main/kotlin/app/revanced/patches/instagram/hide/navigation/HideNavigationButtons.kt index cac9c35c3..4ada34d27 100644 --- a/patches/src/main/kotlin/app/revanced/patches/instagram/hide/navigation/HideNavigationButtons.kt +++ b/patches/src/main/kotlin/app/revanced/patches/instagram/hide/navigation/HideNavigationButtons.kt @@ -1,21 +1,28 @@ package app.revanced.patches.instagram.hide.navigation -import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.patch.booleanOption import app.revanced.patcher.patch.bytecodePatch -import app.revanced.patcher.util.smali.ExternalLabel +import app.revanced.util.addInstructionsAtControlFlowLabel import app.revanced.util.findFreeRegister +import app.revanced.util.getReference +import app.revanced.util.indexOfFirstInstructionOrThrow +import com.android.tools.smali.dexlib2.Opcode +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 java.util.logging.Logger +private const val EXTENSION_CLASS_DESCRIPTOR = + "Lapp/revanced/extension/instagram/hide/navigation/HideNavigationButtonsPatch;" + @Suppress("unused") val hideNavigationButtonsPatch = bytecodePatch( name = "Hide navigation buttons", description = "Hides navigation bar buttons, such as the Reels and Create button.", use = false ) { - compatibleWith("com.instagram.android"("397.1.0.52.81")) + compatibleWith("com.instagram.android") val hideReels by booleanOption( key = "hideReels", @@ -38,43 +45,44 @@ val hideNavigationButtonsPatch = bytecodePatch( ) } - tabCreateButtonsLoopStartFingerprint.method.apply { - // Check the current loop index, and skip over adding the - // navigation button view if the index matches a given button. + val enumNameField: String - val startIndex = tabCreateButtonsLoopStartFingerprint.patternMatch!!.startIndex - val endIndex = tabCreateButtonsLoopEndFingerprint.patternMatch!!.endIndex - val insertIndex = startIndex + 1 - val loopIndexRegister = getInstruction(startIndex).registerA - val freeRegister = findFreeRegister(insertIndex, loopIndexRegister) - val instruction = getInstruction(endIndex - 1) - - val instructions = buildString { - if (hideCreate!!) { - appendLine( - """ - const v$freeRegister, 0x2 - if-eq v$freeRegister, v$loopIndexRegister, :skipAddView - """ - ) - } - - if (hideReels!!) { - appendLine( - """ - const v$freeRegister, 0x3 - if-eq v$freeRegister, v$loopIndexRegister, :skipAddView - """ - ) - } - } - - addInstructionsWithLabels( - insertIndex, - instructions, - ExternalLabel("skipAddView", instruction) - ) + // Get the field name which contains the name of the enum for the navigation button ("fragment_clips", "fragment_share", ...) + with(navigationButtonsEnumInitFingerprint.method) { + enumNameField = indexOfFirstInstructionOrThrow { + opcode == Opcode.IPUT_OBJECT && + (this as TwoRegisterInstruction).registerA == 2 // The p2 register + }.let { + getInstruction(it).getReference()!!.name } } - } + initializeNavigationButtonsListFingerprint.method.apply { + val returnIndex = indexOfFirstInstructionOrThrow(Opcode.RETURN_OBJECT) + val buttonsListRegister = getInstruction(returnIndex).registerA + val freeRegister = findFreeRegister(returnIndex) + val freeRegister2 = findFreeRegister(returnIndex, freeRegister) + + fun instructionsRemoveButtonByName(buttonEnumName: String): String { + return """ + const-string v$freeRegister, "$buttonEnumName" + const-string v$freeRegister2, "$enumNameField" + invoke-static { v$buttonsListRegister, v$freeRegister, v$freeRegister2 }, $EXTENSION_CLASS_DESCRIPTOR->removeNavigationButtonByName(Ljava/util/List;Ljava/lang/String;Ljava/lang/String;)Ljava/util/List; + move-result-object v$buttonsListRegister + """ + } + + if (hideReels!!) + addInstructionsAtControlFlowLabel( + returnIndex, + instructionsRemoveButtonByName("fragment_clips") + ) + + if (hideCreate!!) + addInstructionsAtControlFlowLabel( + returnIndex, + instructionsRemoveButtonByName("fragment_share") + ) + } + } +} diff --git a/patches/src/main/kotlin/app/revanced/patches/music/misc/dns/CheckWatchHistoryDomainNameResolutionPatch.kt b/patches/src/main/kotlin/app/revanced/patches/music/misc/dns/CheckWatchHistoryDomainNameResolutionPatch.kt new file mode 100644 index 000000000..d6ac3ef78 --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/music/misc/dns/CheckWatchHistoryDomainNameResolutionPatch.kt @@ -0,0 +1,22 @@ +package app.revanced.patches.music.misc.dns + +import app.revanced.patches.music.misc.extension.sharedExtensionPatch +import app.revanced.patches.music.shared.mainActivityOnCreateFingerprint +import app.revanced.patches.shared.misc.dns.checkWatchHistoryDomainNameResolutionPatch + +val checkWatchHistoryDomainNameResolutionPatch = checkWatchHistoryDomainNameResolutionPatch( + block = { + dependsOn( + sharedExtensionPatch + ) + + compatibleWith( + "com.google.android.apps.youtube.music"( + "7.29.52", + "8.10.52" + ) + ) + }, + + mainActivityFingerprint = mainActivityOnCreateFingerprint +) diff --git a/patches/src/main/kotlin/app/revanced/patches/music/misc/extension/SharedExtensionPatch.kt b/patches/src/main/kotlin/app/revanced/patches/music/misc/extension/SharedExtensionPatch.kt index 9351b600e..b10c321a4 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/misc/extension/SharedExtensionPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/misc/extension/SharedExtensionPatch.kt @@ -1,9 +1,10 @@ package app.revanced.patches.music.misc.extension import app.revanced.patches.music.misc.extension.hooks.applicationInitHook +import app.revanced.patches.music.misc.extension.hooks.applicationInitOnCreateHook import app.revanced.patches.shared.misc.extension.sharedExtensionPatch val sharedExtensionPatch = sharedExtensionPatch( "music", - applicationInitHook, + applicationInitHook, applicationInitOnCreateHook ) diff --git a/patches/src/main/kotlin/app/revanced/patches/music/misc/extension/hooks/ApplicationInitHook.kt b/patches/src/main/kotlin/app/revanced/patches/music/misc/extension/hooks/ApplicationInitHook.kt index 869174c45..032e10697 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/misc/extension/hooks/ApplicationInitHook.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/misc/extension/hooks/ApplicationInitHook.kt @@ -1,5 +1,6 @@ package app.revanced.patches.music.misc.extension.hooks +import app.revanced.patches.music.shared.YOUTUBE_MUSIC_MAIN_ACTIVITY_CLASS_TYPE import app.revanced.patcher.string import app.revanced.patches.shared.misc.extension.extensionHook @@ -11,3 +12,11 @@ internal val applicationInitHook = extensionHook { ) custom { method, _ -> method.name == "onCreate" } } + +internal val applicationInitOnCreateHook = extensionHook { + returns("V") + parameters("Landroid/os/Bundle;") + custom { method, classDef -> + method.name == "onCreate" && classDef.type == YOUTUBE_MUSIC_MAIN_ACTIVITY_CLASS_TYPE + } +} diff --git a/patches/src/main/kotlin/app/revanced/patches/music/shared/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/music/shared/Fingerprints.kt new file mode 100644 index 000000000..d6c79197d --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/music/shared/Fingerprints.kt @@ -0,0 +1,13 @@ +package app.revanced.patches.music.shared + +import app.revanced.patcher.fingerprint + +internal const val YOUTUBE_MUSIC_MAIN_ACTIVITY_CLASS_TYPE = "Lcom/google/android/apps/youtube/music/activities/MusicActivity;" + +internal val mainActivityOnCreateFingerprint = fingerprint { + returns("V") + parameters("Landroid/os/Bundle;") + custom { method, classDef -> + method.name == "onCreate" && classDef.type == YOUTUBE_MUSIC_MAIN_ACTIVITY_CLASS_TYPE + } +} diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/misc/dns/CheckWatchHistoryDomainNameResolutionPatch.kt b/patches/src/main/kotlin/app/revanced/patches/shared/misc/dns/CheckWatchHistoryDomainNameResolutionPatch.kt new file mode 100644 index 000000000..f409ee9b1 --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/shared/misc/dns/CheckWatchHistoryDomainNameResolutionPatch.kt @@ -0,0 +1,36 @@ +package app.revanced.patches.shared.misc.dns + +import app.revanced.patcher.Fingerprint +import app.revanced.patcher.extensions.InstructionExtensions.addInstruction +import app.revanced.patcher.patch.BytecodePatchBuilder +import app.revanced.patcher.patch.BytecodePatchContext +import app.revanced.patcher.patch.bytecodePatch +import app.revanced.patches.all.misc.resources.addResources + +private const val EXTENSION_CLASS_DESCRIPTOR = + "Lapp/revanced/extension/shared/patches/CheckWatchHistoryDomainNameResolutionPatch;" + +/** + * Patch shared with YouTube and YT Music. + */ +internal fun checkWatchHistoryDomainNameResolutionPatch( + block: BytecodePatchBuilder.() -> Unit = {}, + executeBlock: BytecodePatchContext.() -> Unit = {}, + mainActivityFingerprint: Fingerprint +) = bytecodePatch( + name = "Check watch history domain name resolution", + description = "Checks if the device DNS server is preventing user watch history from being saved.", +) { + block() + + execute { + executeBlock() + + addResources("shared", "misc.dns.checkWatchHistoryDomainNameResolutionPatch") + + mainActivityFingerprint.method.addInstruction( + 0, + "invoke-static/range { p0 .. p0 }, $EXTENSION_CLASS_DESCRIPTOR->checkDnsResolver(Landroid/app/Activity;)V", + ) + } +} diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/dns/CheckWatchHistoryDomainNameResolutionPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/dns/CheckWatchHistoryDomainNameResolutionPatch.kt index 699f8a983..5bd5da415 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/dns/CheckWatchHistoryDomainNameResolutionPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/dns/CheckWatchHistoryDomainNameResolutionPatch.kt @@ -1,39 +1,23 @@ package app.revanced.patches.youtube.misc.dns -import app.revanced.patcher.extensions.InstructionExtensions.addInstruction -import app.revanced.patcher.patch.bytecodePatch -import app.revanced.patches.all.misc.resources.addResources -import app.revanced.patches.all.misc.resources.addResourcesPatch +import app.revanced.patches.shared.misc.dns.checkWatchHistoryDomainNameResolutionPatch import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch import app.revanced.patches.youtube.shared.mainActivityOnCreateFingerprint -private const val EXTENSION_CLASS_DESCRIPTOR = - "Lapp/revanced/extension/youtube/patches/CheckWatchHistoryDomainNameResolutionPatch;" - -val checkWatchHistoryDomainNameResolutionPatch = bytecodePatch( - name = "Check watch history domain name resolution", - description = "Checks if the device DNS server is preventing user watch history from being saved.", -) { - dependsOn( - sharedExtensionPatch, - addResourcesPatch - ) - - compatibleWith( - "com.google.android.youtube"( - "19.34.42", - "20.07.39", - "20.13.41", - "20.14.43", +val checkWatchHistoryDomainNameResolutionPatch = checkWatchHistoryDomainNameResolutionPatch( + block = { + dependsOn( + sharedExtensionPatch ) - ) - execute { - addResources("youtube", "misc.dns.checkWatchHistoryDomainNameResolutionPatch") - - mainActivityOnCreateFingerprint.method.addInstruction( - 0, - "invoke-static/range { p0 .. p0 }, $EXTENSION_CLASS_DESCRIPTOR->checkDnsResolver(Landroid/app/Activity;)V", + compatibleWith( + "com.google.android.youtube"( + "19.34.42", + "20.07.39", + "20.13.41", + "20.14.43", + ) ) - } -} + }, + mainActivityFingerprint = mainActivityOnCreateFingerprint +) diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/video/codecs/DisableVideoCodecsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/video/codecs/DisableVideoCodecsPatch.kt new file mode 100644 index 000000000..fd509f573 --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/video/codecs/DisableVideoCodecsPatch.kt @@ -0,0 +1,87 @@ +package app.revanced.patches.youtube.video.codecs + +import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels +import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction +import app.revanced.patcher.patch.bytecodePatch +import app.revanced.patches.all.misc.resources.addResources +import app.revanced.patches.all.misc.resources.addResourcesPatch +import app.revanced.patches.all.misc.transformation.transformInstructionsPatch +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference +import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch +import app.revanced.patches.youtube.misc.settings.PreferenceScreen +import app.revanced.patches.youtube.misc.settings.settingsPatch +import app.revanced.util.getReference +import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction +import com.android.tools.smali.dexlib2.iface.reference.MethodReference + +private const val EXTENSION_CLASS_DESCRIPTOR = + "Lapp/revanced/extension/youtube/patches/DisableVideoCodecsPatch;" + +@Suppress("unused") +val disableVideoCodecsPatch = bytecodePatch( + name = "disable video codecs", + description = "Adds options to disable HDR and VP9 codecs.", +) { + dependsOn( + sharedExtensionPatch, + settingsPatch, + addResourcesPatch, + /** + * Override all calls of `getSupportedHdrTypes`. + */ + transformInstructionsPatch( + filterMap = filterMap@{ classDef, _, instruction, instructionIndex -> + if (classDef.type.startsWith("Lapp/revanced/")) { + return@filterMap null + } + + val reference = instruction.getReference() + if (reference?.definingClass =="Landroid/view/Display\$HdrCapabilities;" + && reference.name == "getSupportedHdrTypes") { + return@filterMap instruction to instructionIndex + } + return@filterMap null + }, + transform = { method, entry -> + val (instruction, index) = entry + val register = (instruction as FiveRegisterInstruction).registerC + + method.replaceInstruction( + index, + "invoke-static/range { v$register .. v$register }, $EXTENSION_CLASS_DESCRIPTOR->" + + "disableHdrVideo(Landroid/view/Display\$HdrCapabilities;)[I", + ) + } + ) + ) + + compatibleWith( + "com.google.android.youtube"( + "19.34.42", + "20.07.39", + "20.13.41", + "20.14.43", + ) + ) + + execute { + addResources("youtube", "video.codecs.disableVideoCodecsPatch") + + PreferenceScreen.VIDEO.addPreferences( + SwitchPreference("revanced_disable_hdr_video"), + SwitchPreference("revanced_force_avc_codec") + ) + + vp9CapabilityFingerprint.method.addInstructionsWithLabels( + 0, + """ + invoke-static {}, $EXTENSION_CLASS_DESCRIPTOR->allowVP9()Z + move-result v0 + if-nez v0, :default + return v0 + :default + nop + """ + ) + } +} diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/video/codecs/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/video/codecs/Fingerprints.kt new file mode 100644 index 000000000..a7790191f --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/video/codecs/Fingerprints.kt @@ -0,0 +1,13 @@ +package app.revanced.patches.youtube.video.codecs + +import app.revanced.patcher.fingerprint +import com.android.tools.smali.dexlib2.AccessFlags + +internal val vp9CapabilityFingerprint = fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) + returns("Z") + strings( + "vp9_supported", + "video/x-vnd.on2.vp9" + ) +} diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/video/hdr/DisableHdrPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/video/hdr/DisableHdrPatch.kt index dd02c7b52..d0591f2c7 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/video/hdr/DisableHdrPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/video/hdr/DisableHdrPatch.kt @@ -1,71 +1,10 @@ package app.revanced.patches.youtube.video.hdr -import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.patch.bytecodePatch -import app.revanced.patches.all.misc.resources.addResources -import app.revanced.patches.all.misc.resources.addResourcesPatch -import app.revanced.patches.all.misc.transformation.transformInstructionsPatch -import app.revanced.patches.shared.misc.settings.preference.SwitchPreference -import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch -import app.revanced.patches.youtube.misc.settings.PreferenceScreen -import app.revanced.patches.youtube.misc.settings.settingsPatch -import app.revanced.util.getReference -import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction -import com.android.tools.smali.dexlib2.iface.reference.MethodReference - -private const val EXTENSION_CLASS_DESCRIPTOR = - "Lapp/revanced/extension/youtube/patches/DisableHdrPatch;" +import app.revanced.patches.youtube.video.codecs.disableVideoCodecsPatch +@Deprecated("Patch was renamed", ReplaceWith("disableVideoCodecsPatch")) @Suppress("unused") -val disableHdrPatch = bytecodePatch( - name = "Disable HDR video", - description = "Adds an option to disable video HDR.", -) { - dependsOn( - sharedExtensionPatch, - settingsPatch, - addResourcesPatch, - // Override all calls of `getSupportedHdrTypes`. - transformInstructionsPatch( - filterMap = filterMap@{ classDef, _, instruction, instructionIndex -> - if (classDef.type.startsWith("Lapp/revanced/")) { - return@filterMap null - } - - val reference = instruction.getReference() - if (reference?.definingClass =="Landroid/view/Display\$HdrCapabilities;" - && reference.name == "getSupportedHdrTypes") { - return@filterMap instruction to instructionIndex - } - return@filterMap null - }, - transform = { method, entry -> - val (instruction, index) = entry - val register = (instruction as FiveRegisterInstruction).registerC - - method.replaceInstruction( - index, - "invoke-static/range { v$register .. v$register }, $EXTENSION_CLASS_DESCRIPTOR->" + - "disableHdrVideo(Landroid/view/Display\$HdrCapabilities;)[I", - ) - } - ) - ) - - compatibleWith( - "com.google.android.youtube"( - "19.34.42", - "20.07.39", - "20.13.41", - "20.14.43", - ) - ) - - execute { - addResources("youtube", "video.hdr.disableHdrPatch") - - PreferenceScreen.VIDEO.addPreferences( - SwitchPreference("revanced_disable_hdr_video") - ) - } -} +val disableHdrPatch = bytecodePatch{ + dependsOn(disableVideoCodecsPatch) +} \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/video/quality/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/video/quality/Fingerprints.kt index 44b54b647..12ef264e5 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/video/quality/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/video/quality/Fingerprints.kt @@ -29,7 +29,6 @@ internal val videoQualityItemOnClickFingerprint by fingerprint { } } - internal val videoQualityMenuOptionsFingerprint by fingerprint { accessFlags(AccessFlags.STATIC) returns("[L") diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/video/quality/VideoQualityPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/video/quality/VideoQualityPatch.kt index bbeb29e10..1a7908772 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/video/quality/VideoQualityPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/video/quality/VideoQualityPatch.kt @@ -14,12 +14,13 @@ internal val settingsMenuVideoQualityGroup = mutableSetOf() @Suppress("unused") val videoQualityPatch = bytecodePatch( name = "Video quality", - description = "Adds options to use the advanced video quality menu and set default video qualities." + description = "Adds options to use the advanced video quality menu, set default video qualities, " + + "and disable video codecs such as VP9/HDR." ) { dependsOn( rememberVideoQualityPatch, advancedVideoQualityMenuPatch, - videoQualityDialogButtonPatch, + videoQualityDialogButtonPatch ) compatibleWith( diff --git a/patches/src/main/resources/addresources/values/strings.xml b/patches/src/main/resources/addresources/values/strings.xml index 2d36ef7c2..1377f23f6 100644 --- a/patches/src/main/resources/addresources/values/strings.xml +++ b/patches/src/main/resources/addresources/values/strings.xml @@ -30,6 +30,11 @@ Second \"item\" text" Patched %s days ago APK build date is corrupted + + Warning + Your watch history is not being saved.<br><br>This most likely is caused by a DNS ad blocker or network proxy.<br><br>To fix this, whitelist <b>s.youtube.com</b> or turn off all DNS blockers and proxies. + Do not show again + Settings ReVanced @@ -1528,11 +1533,6 @@ Tap here to learn more about DeArrow" Failed connecting to announcements provider Dismiss - - Warning - Your watch history is not being saved.<br><br>This most likely is caused by a DNS ad blocker or network proxy.<br><br>To fix this, whitelist <b>s.youtube.com</b> or turn off all DNS blockers and proxies. - Do not show again - Enable loop video Video will loop @@ -1647,10 +1647,22 @@ Enabling this can unlock higher video qualities" Default playback speed Changed default speed to: %s - + Disable HDR video HDR video is disabled HDR video is enabled + Force AVC (H.264) + Video codec is forced to AVC (H.264) + Video codec is determined automatically + "Benefits: +• Can improve battery life. +• Can restore missing video resolutions on older device. + +Limitations: +• Maximum resolution is 1080p. +• Video playback will use more internet data than VP9 or AV1. +• HDR videos may not use AVC. +• Some devices cannot force AVC." Show advanced video quality menu