From 8af8cdbfd6c46229c9f08016e1c7d8f75b7535eb Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Mon, 22 Aug 2022 01:59:43 +0200 Subject: [PATCH] feat: `settings` patch framework (#266) --- .../bytecode/patch/GeneralBytecodeAdsPatch.kt | 134 +++++++- .../patch/HideInfocardSuggestionsPatch.kt | 15 +- .../youtube/ad/video/patch/VideoAdsPatch.kt | 21 +- .../patch/EnableSeekbarTappingPatch.kt | 17 +- .../bytecode/SwipeControlsBytecodePatch.kt | 3 +- .../resource/SwipeControlsResourcePatch.kt | 77 +++++ ...print.kt => AutoNavInformerFingerprint.kt} | 5 +- .../LayoutConstructorFingerprint.kt | 22 +- .../patch/HideAutoplayButton.kt | 88 ------ .../patch/HideAutoplayButtonPatch.kt | 92 ++++++ .../castbutton/patch/HideCastButtonPatch.kt | 15 +- .../patch/CreateButtonRemoverPatch.kt | 15 +- .../patch/FullscreenPanelsRemoverPatch.kt | 15 +- .../patch/OldQualityLayoutPatch.kt | 15 +- .../layout/reels/patch/HideReelsPatch.kt | 15 + .../patch/ReturnYouTubeDislikePatch.kt | 11 +- .../ReturnYouTubeDislikeResourcePatch.kt | 47 +++ .../button/patch/ShortsButtonRemoverPatch.kt | 15 +- .../patch/SponsorBlockResourcePatch.kt | 132 ++++---- .../watermark/patch/HideWatermarkPatch.kt | 15 +- .../WideSearchbarTwoParentFingerprint.kt | 5 +- .../widesearchbar/patch/WideSearchbarPatch.kt | 15 +- .../misc/autorepeat/patch/AutoRepeatPatch.kt | 13 + .../patch/CustomPlaybackSpeedPatch.kt | 2 + .../hdrbrightness/patch/HDRBrightnessPatch.kt | 15 +- .../patch/FixLocaleConfigErrorPatch.kt | 3 +- .../patch/resource/MicroGResourcePatch.kt | 26 +- .../MinimizedPlaybackCompatibility.kt | 2 +- .../MinimizedPlaybackKidsFingerprint.kt | 4 +- .../MinimizedPlaybackManagerFingerprint.kt | 4 +- .../MinimizedPlaybackSettingsFingerprint.kt | 5 +- .../patch/MinimizedPlaybackPatch.kt | 25 +- .../patch/RememberVideoQualityPatch.kt | 2 + .../LicenseActivityFingerprint.kt | 4 +- .../ReVancedSettingsActivityFingerprint.kt | 5 +- .../fingerprints/ThemeSetterFingerprint.kt | 4 +- .../settings/bytecode/patch/SettingsPatch.kt | 74 ++++- .../framework/components/BasePreference.kt | 14 + .../framework/components/IPreference.kt | 23 ++ .../components/impl/ArrayResource.kt | 9 + .../framework/components/impl/InputType.kt | 6 + .../framework/components/impl/Preference.kt | 18 ++ .../components/impl/PreferenceScreen.kt | 20 ++ .../components/impl/StringResource.kt | 10 + .../components/impl/SwitchPreference.kt | 21 ++ .../components/impl/TextPreference.kt | 22 ++ .../resource/patch/SettingsResourcePatch.kt | 289 +++++++++++++++--- .../patch/CustomVideoBufferPatch.kt | 62 +++- .../revanced/util/resources/ResourceUtils.kt | 27 +- .../host/values/strings.xml | 6 + .../quantum_ic_arrow_back_white_24.png | Bin 0 -> 200 bytes .../quantum_ic_arrow_back_white_24.png | Bin 0 -> 194 bytes .../resources/settings/host/values/arrays.xml | 14 - .../settings/host/values/strings.xml | 227 -------------- .../settings/host/xml/settings_fragment.xml | 12 - ...lbar.xml => revanced_settings_toolbar.xml} | 2 +- .../layout/revanced_settings_with_toolbar.xml | 4 + ...revanced_settings_with_toolbar_layout.xml} | 4 +- .../layout/xsettings_with_toolbar.xml | 4 - .../resources/settings/xml/revanced_prefs.xml | 176 ----------- .../quantum_ic_skip_next_white_24.png | Bin 0 -> 357 bytes .../{ => host}/values/strings.xml | 0 62 files changed, 1219 insertions(+), 728 deletions(-) rename src/main/kotlin/app/revanced/patches/youtube/layout/autoplaybutton/fingerprints/{AutonavInformerFingerprint.kt => AutoNavInformerFingerprint.kt} (92%) delete mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/autoplaybutton/patch/HideAutoplayButton.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/autoplaybutton/patch/HideAutoplayButtonPatch.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/resource/patch/ReturnYouTubeDislikeResourcePatch.kt rename src/main/kotlin/app/revanced/patches/youtube/{layout => misc}/minimizedplayback/annotations/MinimizedPlaybackCompatibility.kt (86%) rename src/main/kotlin/app/revanced/patches/youtube/{layout => misc}/minimizedplayback/fingerprints/MinimizedPlaybackKidsFingerprint.kt (84%) rename src/main/kotlin/app/revanced/patches/youtube/{layout => misc}/minimizedplayback/fingerprints/MinimizedPlaybackManagerFingerprint.kt (88%) rename src/main/kotlin/app/revanced/patches/youtube/{layout => misc}/minimizedplayback/fingerprints/MinimizedPlaybackSettingsFingerprint.kt (80%) rename src/main/kotlin/app/revanced/patches/youtube/{layout => misc}/minimizedplayback/patch/MinimizedPlaybackPatch.kt (68%) create mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/settings/framework/components/BasePreference.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/settings/framework/components/IPreference.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/settings/framework/components/impl/ArrayResource.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/settings/framework/components/impl/InputType.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/settings/framework/components/impl/Preference.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/settings/framework/components/impl/PreferenceScreen.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/settings/framework/components/impl/StringResource.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/settings/framework/components/impl/SwitchPreference.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/settings/framework/components/impl/TextPreference.kt create mode 100644 src/main/resources/returnyoutubedislike/host/values/strings.xml create mode 100644 src/main/resources/settings/drawable-ldrtl-xxxhdpi/quantum_ic_arrow_back_white_24.png create mode 100644 src/main/resources/settings/drawable-xxxhdpi/quantum_ic_arrow_back_white_24.png delete mode 100644 src/main/resources/settings/host/values/arrays.xml delete mode 100644 src/main/resources/settings/host/values/strings.xml delete mode 100644 src/main/resources/settings/host/xml/settings_fragment.xml rename src/main/resources/settings/layout/{xsettings_toolbar.xml => revanced_settings_toolbar.xml} (93%) create mode 100644 src/main/resources/settings/layout/revanced_settings_with_toolbar.xml rename src/main/resources/settings/layout/{xsettings_with_toolbar_layout.xml => revanced_settings_with_toolbar_layout.xml} (60%) delete mode 100644 src/main/resources/settings/layout/xsettings_with_toolbar.xml create mode 100644 src/main/resources/sponsorblock/drawable-xxxhdpi/quantum_ic_skip_next_white_24.png rename src/main/resources/sponsorblock/{ => host}/values/strings.xml (100%) diff --git a/src/main/kotlin/app/revanced/patches/youtube/ad/general/bytecode/patch/GeneralBytecodeAdsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/ad/general/bytecode/patch/GeneralBytecodeAdsPatch.kt index 2b64b0042..cb3d26a07 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/ad/general/bytecode/patch/GeneralBytecodeAdsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/ad/general/bytecode/patch/GeneralBytecodeAdsPatch.kt @@ -23,6 +23,9 @@ import app.revanced.patches.youtube.ad.general.bytecode.extensions.MethodExtensi import app.revanced.patches.youtube.ad.general.bytecode.utils.MethodUtils.createMutableMethod import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch import app.revanced.patches.youtube.misc.mapping.patch.ResourceIdMappingProviderResourcePatch +import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch +import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource +import app.revanced.patches.youtube.misc.settings.framework.components.impl.SwitchPreference import org.jf.dexlib2.Opcode import org.jf.dexlib2.builder.MutableMethodImplementation import org.jf.dexlib2.builder.instruction.* @@ -38,7 +41,7 @@ import org.jf.dexlib2.iface.reference.StringReference import org.jf.dexlib2.immutable.reference.ImmutableMethodReference @Patch -@DependsOn([ResourceIdMappingProviderResourcePatch::class, IntegrationsPatch::class]) +@DependsOn([ResourceIdMappingProviderResourcePatch::class, IntegrationsPatch::class, SettingsPatch::class]) @Name("general-ads") @Description("Removes general ads.") @GeneralAdsCompatibility @@ -68,6 +71,135 @@ class GeneralBytecodeAdsPatch : BytecodePatch() { ) override fun execute(data: BytecodeData): PatchResult { + SettingsPatch.PreferenceScreen.ADS.addPreferences( + SwitchPreference( + "revanced_home_ads_enabled", + StringResource("revanced_home_ads_enabled_title", "Hide home ads"), + true, + StringResource("revanced_home_ads_enabled_summary_on", "Home ads are shown"), + StringResource("revanced_home_ads_enabled_summary_off", "Home ads are hidden") + ), + SwitchPreference( + "revanced_adremover_ad_removal", + StringResource("revanced_adremover_ad_removal_enabled_title", "Remove general ads"), + true, + StringResource("revanced_adremover_ad_removal_enabled_summary_on", "General ads are hidden"), + StringResource("revanced_adremover_ad_removal_enabled_summary_off", "General ads are shown") + ), + SwitchPreference( + "revanced_adremover_merchandise", + StringResource("revanced_adremover_merchandise_enabled_title", "Remove merchandise banners"), + true, + StringResource("revanced_adremover_merchandise_enabled_summary_on", "Merchandise banners are hidden"), + StringResource("revanced_adremover_merchandise_enabled_summary_off", "Merchandise banners are shown") + ), + SwitchPreference( + "revanced_adremover_community_posts_removal", + StringResource("revanced_adremover_community_posts_enabled_title", "Remove community posts"), + true, + StringResource("revanced_adremover_community_posts_enabled_summary_on", "Community posts are hidden"), + StringResource("revanced_adremover_community_posts_enabled_summary_off", "Community posts are shown") + ), + SwitchPreference( + "revanced_adremover_compact_banner_removal", + StringResource("revanced_adremover_compact_banner_enabled_title", "Remove compact banners"), + true, + StringResource("revanced_adremover_compact_banner_enabled_summary_on", "Compact banners are hidden"), + StringResource("revanced_adremover_compact_banner_enabled_summary_off", "Compact banners are shown") + ), + SwitchPreference( + "revanced_adremover_comments_removal", + StringResource("revanced_adremover_comments_enabled_title", "Remove comments section"), + false, + StringResource("revanced_adremover_comments_enabled_summary_on", "Comment section is hidden"), + StringResource("revanced_adremover_comments_enabled_summary_off", "Comment section is shown") + ), + SwitchPreference( + "revanced_adremover_movie", + StringResource("revanced_adremover_movie_enabled_title", "Remove movies section"), + true, + StringResource("revanced_adremover_movie_enabled_summary_on", "Movies section is hidden"), + StringResource("revanced_adremover_movie_enabled_summary_off", "Movies section is shown") + ), + SwitchPreference( + "revanced_adremover_feed_survey", + StringResource("revanced_adremover_feed_survey_enabled_title", "Remove feed surveys"), + true, + StringResource("revanced_adremover_feed_survey_enabled_summary_on", "Feed surveys are hidden"), + StringResource("revanced_adremover_feed_survey_enabled_summary_off", "Feed surveys are shown") + ), + SwitchPreference( + "revanced_adremover_shorts_shelf", + StringResource("revanced_adremover_shorts_shelf_enabled_title", "Remove shorts shelf"), + true, + StringResource("revanced_adremover_shorts_shelf_enabled_summary_on", "Shorts shelves are hidden"), + StringResource("revanced_adremover_shorts_shelf_enabled_summary_off", "Shorts shelves are shown") + ), + SwitchPreference( + "revanced_adremover_community_guidelines", + StringResource("revanced_adremover_community_guidelines_enabled_title", "Remove community guidelines"), + true, + StringResource("revanced_adremover_community_guidelines_enabled_summary_on", "Community guidelines are hidden"), + StringResource("revanced_adremover_community_guidelines_enabled_summary_off", "Community guidelines are shown") + ), + SwitchPreference( + "revanced_adremover_emergency_box_removal", + StringResource("revanced_adremover_emergency_box_enabled_title", "Remove emergency boxes"), + true, + StringResource("revanced_adremover_emergency_box_enabled_summary_on", "Emergency boxes are hidden"), + StringResource("revanced_adremover_emergency_box_enabled_summary_off", "Emergency boxes are shown") + ), + SwitchPreference( + "revanced_adremover_info_panel", + StringResource("revanced_adremover_info_panel_enabled_title", "Remove info panels"), + true, + StringResource("revanced_adremover_info_panel_enabled_summary_on", "Merchandise banners are hidden"), + StringResource("revanced_adremover_info_panel_enabled_summary_off", "Merchandise banners are shown") + ), + SwitchPreference( + "revanced_adremover_medical_panel", + StringResource("revanced_adremover_medical_panel_enabled_title", "Remove medical panels"), + true, + StringResource("revanced_adremover_medical_panel_enabled_summary_on", "Medical panels are hidden"), + StringResource("revanced_adremover_medical_panel_enabled_summary_off", "Medical panels are shown") + ), + SwitchPreference( + "revanced_adremover_paid_content", + StringResource("revanced_adremover_paid_content_enabled_title", "Remove paid content"), + true, + StringResource("revanced_adremover_paid_content_enabled_summary_on", "Paid content is hidden"), + StringResource("revanced_adremover_paid_content_enabled_summary_off", "Paid content is shown") + ), + SwitchPreference( + "revanced_adremover_suggested", + StringResource("revanced_adremover_suggested_enabled_title", "Remove personal suggestions"), + true, + StringResource("revanced_adremover_suggested_enabled_summary_on", "Personal suggestions are hidden"), + StringResource("revanced_adremover_suggested_enabled_summary_off", "Personal suggestions are shown") + ), + SwitchPreference( + "revanced_adremover_hide_suggestions", + StringResource("revanced_adremover_hide_suggestions_enabled_title", "Hide suggestions"), + true, + StringResource("revanced_adremover_hide_suggestions_enabled_summary_on", "Suggestions are hidden"), + StringResource("revanced_adremover_hide_suggestions_enabled_summary_off", "Suggestions are shown") + ), + SwitchPreference( + "revanced_adremover_hide_latest_posts", + StringResource("revanced_adremover_hide_latest_posts_enabled_title", "Hide latest posts"), + true, + StringResource("revanced_adremover_hide_latest_posts_enabled_summary_on", "Latest posts are hidden"), + StringResource("revanced_adremover_hide_latest_posts_enabled_summary_off", "Latest posts are shown") + ), + SwitchPreference( + "revanced_adremover_hide_channel_guidelines", + StringResource("revanced_adremover_hide_channel_guidelines_enabled_title", "Hide channel guidelines"), + true, + StringResource("revanced_adremover_hide_channel_guidelines_enabled_summary_on", "Channel guidelines are hidden"), + StringResource("revanced_adremover_hide_channel_guidelines_enabled_summary_off", "Channel guidelines are shown") + ), + ) + // iterating through all classes is expensive for (classDef in data.classes) { var mutableClass: MutableClass? = null diff --git a/src/main/kotlin/app/revanced/patches/youtube/ad/infocardsuggestions/patch/HideInfocardSuggestionsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/ad/infocardsuggestions/patch/HideInfocardSuggestionsPatch.kt index 7a40acdce..0d49d39bb 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/ad/infocardsuggestions/patch/HideInfocardSuggestionsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/ad/infocardsuggestions/patch/HideInfocardSuggestionsPatch.kt @@ -16,10 +16,13 @@ import app.revanced.patches.youtube.ad.infocardsuggestions.annotations.HideInfoc import app.revanced.patches.youtube.ad.infocardsuggestions.fingerprints.HideInfocardSuggestionsFingerprint import app.revanced.patches.youtube.ad.infocardsuggestions.fingerprints.HideInfocardSuggestionsParentFingerprint import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch +import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch +import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource +import app.revanced.patches.youtube.misc.settings.framework.components.impl.SwitchPreference import org.jf.dexlib2.builder.instruction.BuilderInstruction35c @Patch -@DependsOn([IntegrationsPatch::class]) +@DependsOn([IntegrationsPatch::class, SettingsPatch::class]) @Name("hide-infocard-suggestions") @Description("Hides infocards in videos.") @HideInfocardSuggestionsCompatibility @@ -30,6 +33,16 @@ class HideInfocardSuggestionsPatch : BytecodePatch( ) ) { override fun execute(data: BytecodeData): PatchResult { + SettingsPatch.PreferenceScreen.ADS.addPreferences( + SwitchPreference( + "revanced_info_cards_enabled", + StringResource("revanced_info_cards_enabled_title", "Show info-cards"), + false, + StringResource("revanced_info_cards_enabled_summary_on", "Info-cards are shown"), + StringResource("revanced_info_cards_enabled_summary_off", "Info-cards are hidden") + ) + ) + val parentResult = HideInfocardSuggestionsParentFingerprint.result ?: return PatchResultError("Parent fingerprint not resolved!") diff --git a/src/main/kotlin/app/revanced/patches/youtube/ad/video/patch/VideoAdsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/ad/video/patch/VideoAdsPatch.kt index 437dd4730..e116a520c 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/ad/video/patch/VideoAdsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/ad/video/patch/VideoAdsPatch.kt @@ -15,9 +15,12 @@ import app.revanced.patches.youtube.ad.video.annotations.VideoAdsCompatibility import app.revanced.patches.youtube.ad.video.fingerprints.ShowVideoAdsConstructorFingerprint import app.revanced.patches.youtube.ad.video.fingerprints.ShowVideoAdsFingerprint import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch +import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch +import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource +import app.revanced.patches.youtube.misc.settings.framework.components.impl.SwitchPreference @Patch -@DependsOn([IntegrationsPatch::class]) +@DependsOn([IntegrationsPatch::class, SettingsPatch::class]) @Name("video-ads") @Description("Removes ads in the video player.") @VideoAdsCompatibility @@ -28,7 +31,19 @@ class VideoAdsPatch : BytecodePatch( ) ) { override fun execute(data: BytecodeData): PatchResult { - ShowVideoAdsFingerprint.resolve(data, ShowVideoAdsConstructorFingerprint.result!!.classDef) + SettingsPatch.PreferenceScreen.ADS.addPreferences( + SwitchPreference( + "revanced_video_ads_enabled", + StringResource("revanced_video_ads_enabled_title", "Hide video ads"), + true, + StringResource("revanced_video_ads_enabled_summary_on", "Video ads are hidden"), + StringResource("revanced_video_ads_enabled_summary_off", "Video ads are shown") + ) + ) + + ShowVideoAdsFingerprint.resolve( + data, ShowVideoAdsConstructorFingerprint.result!!.classDef + ) // Override the parameter by calling shouldShowAds and setting the parameter to the result ShowVideoAdsFingerprint.result!!.mutableMethod.addInstructions( @@ -40,4 +55,4 @@ class VideoAdsPatch : BytecodePatch( return PatchResultSuccess() } -} +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/patch/EnableSeekbarTappingPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/patch/EnableSeekbarTappingPatch.kt index 14e87bce1..c0374a94b 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/patch/EnableSeekbarTappingPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/patch/EnableSeekbarTappingPatch.kt @@ -15,6 +15,9 @@ import app.revanced.patches.youtube.interaction.seekbar.annotation.SeekbarTappin import app.revanced.patches.youtube.interaction.seekbar.fingerprints.SeekbarTappingFingerprint import app.revanced.patches.youtube.interaction.seekbar.fingerprints.SeekbarTappingParentFingerprint import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch +import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch +import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource +import app.revanced.patches.youtube.misc.settings.framework.components.impl.SwitchPreference import org.jf.dexlib2.Opcode import org.jf.dexlib2.builder.instruction.BuilderInstruction21t import org.jf.dexlib2.iface.Method @@ -22,7 +25,7 @@ import org.jf.dexlib2.iface.instruction.formats.Instruction11n import org.jf.dexlib2.iface.instruction.formats.Instruction35c @Patch -@DependsOn([IntegrationsPatch::class]) +@DependsOn([IntegrationsPatch::class, SettingsPatch::class]) @Name("seekbar-tapping") @Description("Enables tap-to-seek on the seekbar of the video player.") @SeekbarTappingCompatibility @@ -33,6 +36,16 @@ class EnableSeekbarTappingPatch : BytecodePatch( ) ) { override fun execute(data: BytecodeData): PatchResult { + SettingsPatch.PreferenceScreen.INTERACTIONS.addPreferences( + SwitchPreference( + "revanced_enable_tap_seeking", + StringResource("revanced_seekbar_tapping_enabled_title", "Enable seekbar tapping"), + true, + StringResource("revanced_seekbar_tapping_summary_on", "Seekbar tapping is enabled"), + StringResource("revanced_seekbar_tapping_summary_off", "Seekbar tapping is disabled") + ) + ) + var result = SeekbarTappingParentFingerprint.result!! val tapSeekMethods = mutableMapOf() @@ -42,7 +55,7 @@ class EnableSeekbarTappingPatch : BytecodePatch( if (it.implementation == null) continue val instructions = it.implementation!!.instructions - // here we make sure we actually find the method because it has more then 7 instructions + // here we make sure we actually find the method because it has more than 7 instructions if (instructions.count() < 7) continue // we know that the 7th instruction has the opcode CONST_4 diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/patch/bytecode/SwipeControlsBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/patch/bytecode/SwipeControlsBytecodePatch.kt index 53908cd0c..e7cbd1ad3 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/patch/bytecode/SwipeControlsBytecodePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/patch/bytecode/SwipeControlsBytecodePatch.kt @@ -65,5 +65,4 @@ class SwipeControlsBytecodePatch : BytecodePatch( } return PatchResultSuccess() } -} - +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/patch/resource/SwipeControlsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/patch/resource/SwipeControlsResourcePatch.kt index f719010c0..05d732e04 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/patch/resource/SwipeControlsResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/patch/resource/SwipeControlsResourcePatch.kt @@ -6,14 +6,91 @@ import app.revanced.patcher.annotation.Version import app.revanced.patcher.data.impl.ResourceData import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.impl.ResourcePatch import app.revanced.patches.youtube.interaction.swipecontrols.annotation.SwipeControlsCompatibility +import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch +import app.revanced.patches.youtube.misc.settings.framework.components.impl.* @Name("swipe-controls-resource-patch") +@DependsOn([SettingsPatch::class]) @SwipeControlsCompatibility @Version("0.0.1") class SwipeControlsResourcePatch : ResourcePatch() { override fun execute(data: ResourceData): PatchResult { + SettingsPatch.PreferenceScreen.INTERACTIONS.addPreferences( + PreferenceScreen( + "revanced_swipe_controls", StringResource("revanced_swipe_controls_title", "Swipe controls"), listOf( + SwitchPreference( + "revanced_enable_swipe_brightness", + StringResource("revanced_swipe_brightness_enabled_title", "Enable brightness gesture"), + true, + StringResource("revanced_swipe_brightness_summary_on", "Brightness swipe is enabled"), + StringResource("revanced_swipe_brightness_summary_off", "Brightness swipe is disabled") + ), + SwitchPreference( + "revanced_enable_swipe_volume", + StringResource("revanced_swipe_volume_enabled_title", "Enable volume gesture"), + true, + StringResource("revanced_swipe_volume_summary_on", "Volume swipe is enabled"), + StringResource("revanced_swipe_volume_summary_off", "Volume swipe is disabled") + ), + SwitchPreference( + "revanced_enable_press_to_swipe", + StringResource("revanced_press_to_swipe_enabled_title", "Enable press-to-swipe gesture"), + false, + StringResource("revanced_press_to_swipe_summary_on", "Press-to-swipe is enabled"), + StringResource("revanced_press_to_swipe_summary_off", "Press-to-swipe is disabled") + ), + SwitchPreference( + "revanced_enable_swipe_haptic_feedback", + StringResource("revanced_swipe_haptic_feedback_enabled_title", "Enable haptic feedback"), + true, + StringResource("revanced_swipe_haptic_feedback_summary_on", "Haptic feedback is enabled"), + StringResource("revanced_swipe_haptic_feedback_summary_off", "Haptic feedback is disabled") + ), + TextPreference( + "revanced_swipe_overlay_timeout", + StringResource("revanced_swipe_overlay_timeout_title", "Swipe overlay timeout"), + InputType.NUMBER, + "500", + StringResource( + "revanced_swipe_overlay_timeout_summary", + "The amount of milliseconds the overlay is visible" + ) + ), + TextPreference( + "revanced_swipe_overlay_text_size", + StringResource("revanced_swipe_overlay_text_size_title", "Swipe overlay text size"), + InputType.NUMBER, + "22", + StringResource("revanced_swipe_overlay_text_size_summary", "The text size for swipe overlay") + ), + TextPreference( + "revanced_swipe_overlay_background_alpha", + StringResource("revanced_swipe_overlay_background_alpha_title", "Swipe background visibility"), + InputType.NUMBER, + "127", + StringResource( + "revanced_swipe_overlay_background_alpha_summary", + "The visibility of swipe overlay background" + ) + ), + TextPreference( + "revanced_swipe_magnitude_threshold", + StringResource("revanced_swipe_magnitude_threshold_title", "Swipe magnitude threshold"), + InputType.NUMBER, + "30", + StringResource( + "revanced_swipe_magnitude_threshold_summary", + "The amount of threshold for swipe to occur" + ) + ) + ), + StringResource("revanced_swipe_controls_summary","Control volume and brightness") + ) + ) + val resourcesDir = "swipecontrols" data.injectResources( diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/autoplaybutton/fingerprints/AutonavInformerFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/autoplaybutton/fingerprints/AutoNavInformerFingerprint.kt similarity index 92% rename from src/main/kotlin/app/revanced/patches/youtube/layout/autoplaybutton/fingerprints/AutonavInformerFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/layout/autoplaybutton/fingerprints/AutoNavInformerFingerprint.kt index 104bef6cc..1eadc9a59 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/autoplaybutton/fingerprints/AutonavInformerFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/autoplaybutton/fingerprints/AutoNavInformerFingerprint.kt @@ -14,10 +14,9 @@ import org.jf.dexlib2.Opcode @MatchingMethod( "LWillAutonavInformer;", "k" ) -@FuzzyPatternScanMethod(2) @AutoplayButtonCompatibility @Version("0.0.1") -object AutonavInformerFingerprint : MethodFingerprint( +object AutoNavInformerFingerprint : MethodFingerprint( "Z", AccessFlags.PUBLIC or AccessFlags.FINAL, null, @@ -31,4 +30,4 @@ object AutonavInformerFingerprint : MethodFingerprint( ), null, { it.definingClass.endsWith("WillAutonavInformer;") } -) +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/autoplaybutton/fingerprints/LayoutConstructorFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/autoplaybutton/fingerprints/LayoutConstructorFingerprint.kt index e870501d9..b4959dee9 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/autoplaybutton/fingerprints/LayoutConstructorFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/autoplaybutton/fingerprints/LayoutConstructorFingerprint.kt @@ -2,31 +2,19 @@ package app.revanced.patches.youtube.layout.autoplaybutton.fingerprints import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patches.youtube.layout.autoplaybutton.annotations.AutoplayButtonCompatibility -import org.jf.dexlib2.AccessFlags -import org.jf.dexlib2.Opcode @Name("layout-constructor-fingerprint") @MatchingMethod( "LYouTubeControlsOverlay;", "F" ) -@FuzzyPatternScanMethod(2) @AutoplayButtonCompatibility @Version("0.0.1") object LayoutConstructorFingerprint : MethodFingerprint( - "V", - AccessFlags.PUBLIC or AccessFlags.FINAL, - null, - listOf( - Opcode.CONST, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.CHECK_CAST, - Opcode.INVOKE_VIRTUAL, - ), - listOf("1.0x") -) + null, null, null, null, listOf("1.0x"), + { methodDef -> + methodDef.definingClass.endsWith("YouTubeControlsOverlay;") + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/autoplaybutton/patch/HideAutoplayButton.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/autoplaybutton/patch/HideAutoplayButton.kt deleted file mode 100644 index 149f06be3..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/autoplaybutton/patch/HideAutoplayButton.kt +++ /dev/null @@ -1,88 +0,0 @@ -package app.revanced.patches.youtube.layout.autoplaybutton.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.impl.BytecodeData -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.extensions.removeInstruction -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patcher.patch.impl.BytecodePatch -import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod -import app.revanced.patches.youtube.layout.autoplaybutton.annotations.AutoplayButtonCompatibility -import app.revanced.patches.youtube.layout.autoplaybutton.fingerprints.AutonavInformerFingerprint -import app.revanced.patches.youtube.layout.autoplaybutton.fingerprints.LayoutConstructorFingerprint -import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch -import app.revanced.patches.youtube.misc.mapping.patch.ResourceIdMappingProviderResourcePatch -import org.jf.dexlib2.iface.instruction.WideLiteralInstruction -import org.jf.dexlib2.iface.instruction.formats.Instruction35c - -@Patch -@DependsOn([ResourceIdMappingProviderResourcePatch::class, IntegrationsPatch::class]) -@Name("hide-autoplay-button") -@Description("Hides the autoplay button in the video player.") -@AutoplayButtonCompatibility -@Version("0.0.1") -class HideAutoplayButton : BytecodePatch( - listOf( - LayoutConstructorFingerprint, AutonavInformerFingerprint - ) -) { - override fun execute(data: BytecodeData): PatchResult { - val layoutGenMethod = LayoutConstructorFingerprint.result!!.mutableMethod - - val autonavToggle = - ResourceIdMappingProviderResourcePatch.resourceMappings.single { it.type == "id" && it.name == "autonav_toggle" } - val autonavPreviewStub = - ResourceIdMappingProviderResourcePatch.resourceMappings.single { it.type == "id" && it.name == "autonav_preview_stub" } - - val instructions = layoutGenMethod.implementation!!.instructions - - val autonavToggleConstIndex = - instructions.indexOfFirst { (it as? WideLiteralInstruction)?.wideLiteral == autonavToggle.id } + 4 - val autonavPreviewStubConstIndex = - instructions.indexOfFirst { (it as? WideLiteralInstruction)?.wideLiteral == autonavPreviewStub.id } + 4 - - injectIfBranch(layoutGenMethod, autonavToggleConstIndex) - injectIfBranch(layoutGenMethod, autonavPreviewStubConstIndex) - - val autonavInformerMethod = AutonavInformerFingerprint.result!!.mutableMethod - - //force disable autoplay since it's hard to do without the button - autonavInformerMethod.addInstructions( - 0, """ - invoke-static {}, Lapp/revanced/integrations/patches/HideAutoplayButtonPatch;->isButtonShown()Z - move-result v0 - if-nez v0, :hidden - const/4 v0, 0x0 - return v0 - :hidden - nop - """ - ) - - return PatchResultSuccess() - } - - private fun injectIfBranch(method: MutableMethod, index: Int) { - val instructions = method.implementation!!.instructions - val insn = (instructions.get(index) as? Instruction35c)!! - val methodToCall = insn.reference.toString() - - //remove the invoke-virtual because we want to put it in an if-statement - method.removeInstruction(index) - method.addInstructions( - index, """ - invoke-static {}, Lapp/revanced/integrations/patches/HideAutoplayButtonPatch;->isButtonShown()Z - move-result v11 - if-eqz v11, :hidebutton - invoke-virtual {v${insn.registerC}, v${insn.registerD}, v${insn.registerE}}, $methodToCall - :hidebutton - nop - """ - ) - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/autoplaybutton/patch/HideAutoplayButtonPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/autoplaybutton/patch/HideAutoplayButtonPatch.kt new file mode 100644 index 000000000..669db4b83 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/autoplaybutton/patch/HideAutoplayButtonPatch.kt @@ -0,0 +1,92 @@ +package app.revanced.patches.youtube.layout.autoplaybutton.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.impl.BytecodeData +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.impl.BytecodePatch +import app.revanced.patcher.util.smali.ExternalLabel +import app.revanced.patches.youtube.layout.autoplaybutton.annotations.AutoplayButtonCompatibility +import app.revanced.patches.youtube.layout.autoplaybutton.fingerprints.AutoNavInformerFingerprint +import app.revanced.patches.youtube.layout.autoplaybutton.fingerprints.LayoutConstructorFingerprint +import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch +import app.revanced.patches.youtube.misc.mapping.patch.ResourceIdMappingProviderResourcePatch +import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch +import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource +import app.revanced.patches.youtube.misc.settings.framework.components.impl.SwitchPreference +import org.jf.dexlib2.iface.instruction.Instruction +import org.jf.dexlib2.iface.instruction.ReferenceInstruction +import org.jf.dexlib2.iface.instruction.WideLiteralInstruction +import org.jf.dexlib2.iface.reference.MethodReference + +@Patch +@DependsOn([IntegrationsPatch::class, SettingsPatch::class, ResourceIdMappingProviderResourcePatch::class]) +@Name("hide-autoplay-button") +@Description("Hides the autoplay button in the video player.") +@AutoplayButtonCompatibility +@Version("0.0.1") +class HideAutoplayButtonPatch : BytecodePatch( + listOf( + LayoutConstructorFingerprint, AutoNavInformerFingerprint + ) +) { + override fun execute(data: BytecodeData): PatchResult { + SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( + SwitchPreference( + "revanced_autoplay_button_enabled", + StringResource("revanced_autoplay_button_enabled_title", "Show autoplay button"), + false, + StringResource("revanced_autoplay_button_summary_on", "Autoplay button is shown"), + StringResource("revanced_autoplay_button_summary_off", "Autoplay button is hidden") + ) + ) + + val autoNavInformerMethod = AutoNavInformerFingerprint.result!!.mutableMethod + + val layoutGenMethodResult = LayoutConstructorFingerprint.result!! + val layoutGenMethod = layoutGenMethodResult.mutableMethod + val layoutGenMethodInstructions = layoutGenMethod.implementation!!.instructions + + // resolve the offsets such as ... + val autoNavPreviewStubId = ResourceIdMappingProviderResourcePatch.resourceMappings.single { + it.name == "autonav_preview_stub" + }.id + // where to insert the branch instructions and ... + val insertIndex = layoutGenMethodInstructions.indexOfFirst { + (it as? WideLiteralInstruction)?.wideLiteral == autoNavPreviewStubId + } + // where to branch away + val branchIndex = layoutGenMethodInstructions.subList(insertIndex + 1, layoutGenMethodInstructions.size - 1).indexOfFirst { + ((it as? ReferenceInstruction)?.reference as? MethodReference)?.name == "addOnLayoutChangeListener" + } + 2 + + val jumpInstruction = layoutGenMethodInstructions[insertIndex + branchIndex] as Instruction + layoutGenMethod.addInstructions( + insertIndex, """ + invoke-static {}, Lapp/revanced/integrations/patches/HideAutoplayButtonPatch;->isButtonShown()Z + move-result v11 + if-eqz v11, :hidden + """, listOf(ExternalLabel("hidden", jumpInstruction)) + ) + + //force disable autoplay since it's hard to do without the button + autoNavInformerMethod.addInstructions( + 0, """ + invoke-static {}, Lapp/revanced/integrations/patches/HideAutoplayButtonPatch;->isButtonShown()Z + move-result v0 + if-nez v0, :hidden + const/4 v0, 0x0 + return v0 + :hidden + nop + """ + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/castbutton/patch/HideCastButtonPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/castbutton/patch/HideCastButtonPatch.kt index fc3736f92..635e8c930 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/castbutton/patch/HideCastButtonPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/castbutton/patch/HideCastButtonPatch.kt @@ -12,15 +12,28 @@ import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patches.youtube.layout.castbutton.annotations.CastButtonCompatibility import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch +import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch +import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource +import app.revanced.patches.youtube.misc.settings.framework.components.impl.SwitchPreference @Patch -@DependsOn([IntegrationsPatch::class]) +@DependsOn([IntegrationsPatch::class, SettingsPatch::class]) @Name("hide-cast-button") @Description("Hides the cast button in the video player.") @CastButtonCompatibility @Version("0.0.1") class HideCastButtonPatch : BytecodePatch() { override fun execute(data: BytecodeData): PatchResult { + SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( + SwitchPreference( + "revanced_cast_button_enabled", + StringResource("revanced_cast_button_enabled_title", "Show cast button"), + false, + StringResource("revanced_cast_button_summary_on", "Cast button is shown"), + StringResource("revanced_cast_button_summary_off", "Cast button is hidden") + ) + ) + data.classes.forEach { classDef -> classDef.methods.forEach { method -> if (classDef.type.endsWith("MediaRouteButton;") && method.name == "setVisibility") { diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/createbutton/patch/CreateButtonRemoverPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/createbutton/patch/CreateButtonRemoverPatch.kt index f7b540560..b3e3a5541 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/createbutton/patch/CreateButtonRemoverPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/createbutton/patch/CreateButtonRemoverPatch.kt @@ -15,6 +15,9 @@ import app.revanced.patches.youtube.layout.createbutton.annotations.CreateButton import app.revanced.patches.youtube.layout.createbutton.fingerprints.CreateButtonFingerprint import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch import app.revanced.patches.youtube.misc.mapping.patch.ResourceIdMappingProviderResourcePatch +import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch +import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource +import app.revanced.patches.youtube.misc.settings.framework.components.impl.SwitchPreference import org.jf.dexlib2.Opcode import org.jf.dexlib2.iface.instruction.OneRegisterInstruction import org.jf.dexlib2.iface.instruction.ReferenceInstruction @@ -22,7 +25,7 @@ import org.jf.dexlib2.iface.instruction.WideLiteralInstruction import org.jf.dexlib2.iface.reference.MethodReference @Patch -@DependsOn([IntegrationsPatch::class, ResourceIdMappingProviderResourcePatch::class]) +@DependsOn([IntegrationsPatch::class, ResourceIdMappingProviderResourcePatch::class, SettingsPatch::class]) @Name("disable-create-button") @Description("Hides the create button in the navigation bar.") @CreateButtonCompatibility @@ -33,6 +36,16 @@ class CreateButtonRemoverPatch : BytecodePatch( ) ) { override fun execute(data: BytecodeData): PatchResult { + SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( + SwitchPreference( + "revanced_create_button_enabled", + StringResource("revanced_create_button_enabled_title", "Show create button"), + false, + StringResource("revanced_create_button_summary_on", "Create button is shown."), + StringResource("revanced_create_button_summary_off", "Create button is hidden.") + ) + ) + val result = CreateButtonFingerprint.result!! // Get the required register which holds the view object we need to pass to the method hideCreateButton diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreenpanels/patch/FullscreenPanelsRemoverPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreenpanels/patch/FullscreenPanelsRemoverPatch.kt index 403117839..4cd0a3c7d 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreenpanels/patch/FullscreenPanelsRemoverPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreenpanels/patch/FullscreenPanelsRemoverPatch.kt @@ -17,10 +17,13 @@ import app.revanced.patches.youtube.layout.fullscreenpanels.annotations.Fullscre import app.revanced.patches.youtube.layout.fullscreenpanels.fingerprints.FullscreenViewAdderFingerprint import app.revanced.patches.youtube.layout.fullscreenpanels.fingerprints.FullscreenViewAdderParentFingerprint import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch +import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch +import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource +import app.revanced.patches.youtube.misc.settings.framework.components.impl.SwitchPreference @Patch @Name("disable-fullscreen-panels") -@DependsOn([IntegrationsPatch::class]) +@DependsOn([IntegrationsPatch::class, SettingsPatch::class]) @Description("Disables video description and comments panel in fullscreen view.") @FullscreenPanelsCompatibility @Version("0.0.1") @@ -30,6 +33,16 @@ class FullscreenPanelsRemoverPatch : BytecodePatch( ) ) { override fun execute(data: BytecodeData): PatchResult { + SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( + SwitchPreference( + "revanced_fullscreen_panels_enabled", + StringResource("revanced_fullscreen_panels_enabled_title", "Show fullscreen panels"), + false, + StringResource("revanced_fullscreen_panels_summary_on", "Fullscreen panels are shown"), + StringResource("revanced_fullscreen_panels_summary_off", "Fullscreen panels are hidden") + ) + ) + val parentResult = FullscreenViewAdderParentFingerprint.result!! FullscreenViewAdderFingerprint.resolve(data, parentResult.method, parentResult.classDef) val result = FullscreenViewAdderParentFingerprint.result diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/oldqualitylayout/patch/OldQualityLayoutPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/oldqualitylayout/patch/OldQualityLayoutPatch.kt index 69f366032..a1d2090fe 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/oldqualitylayout/patch/OldQualityLayoutPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/oldqualitylayout/patch/OldQualityLayoutPatch.kt @@ -13,10 +13,13 @@ import app.revanced.patcher.patch.impl.BytecodePatch import app.revanced.patches.youtube.layout.oldqualitylayout.annotations.OldQualityLayoutCompatibility import app.revanced.patches.youtube.layout.oldqualitylayout.fingerprints.QualityMenuViewInflateFingerprint import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch +import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch +import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource +import app.revanced.patches.youtube.misc.settings.framework.components.impl.SwitchPreference import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction @Patch -@DependsOn([IntegrationsPatch::class]) +@DependsOn([IntegrationsPatch::class, SettingsPatch::class]) @Name("old-quality-layout") @Description("Enables the original quality flyout menu.") @OldQualityLayoutCompatibility @@ -25,6 +28,16 @@ class OldQualityLayoutPatch : BytecodePatch( listOf(QualityMenuViewInflateFingerprint) ) { override fun execute(data: BytecodeData): PatchResult { + SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( + SwitchPreference( + "revanced_use_old_style_quality_settings", + StringResource("revanced_old_style_quality_settings_enabled_title", "Use old quality layout"), + true, + StringResource("revanced_old_style_quality_settings_summary_on", "Old quality settings are shown"), + StringResource("revanced_old_style_quality_settings_summary_off", "New quality settings are shown") + ) + ) + val inflateFingerprintResult = QualityMenuViewInflateFingerprint.result!! val method = inflateFingerprintResult.mutableMethod val instructions = method.implementation!!.instructions diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/reels/patch/HideReelsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/reels/patch/HideReelsPatch.kt index c1e7982d2..7025d4e05 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/reels/patch/HideReelsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/reels/patch/HideReelsPatch.kt @@ -7,13 +7,18 @@ import app.revanced.patcher.annotation.Version import app.revanced.patcher.data.impl.BytecodeData import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.impl.BytecodePatch import app.revanced.patches.youtube.layout.reels.annotations.HideReelsCompatibility import app.revanced.patches.youtube.layout.reels.fingerprints.HideReelsFingerprint +import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch +import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource +import app.revanced.patches.youtube.misc.settings.framework.components.impl.SwitchPreference //@Patch TODO: this is currently in the general-bytecode-ads patch due to the integrations having a preference for including reels or not. Move it here. @Name("hide-reels") @Description("Hides reels on the home page.") +@DependsOn([SettingsPatch::class]) @HideReelsCompatibility @Version("0.0.1") class HideReelsPatch : BytecodePatch( @@ -22,6 +27,16 @@ class HideReelsPatch : BytecodePatch( ) ) { override fun execute(data: BytecodeData): PatchResult { + SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( + SwitchPreference( + "revanced_reel_button_enabled", + StringResource("revanced_reel_button_enabled_title", "Show reels button"), + false, + StringResource("revanced_reel_button_summary_on", "Reels button is shown"), + StringResource("revanced_reel_button_summary_off", "Reels button is hidden") + ) + ) + val result = HideReelsFingerprint.result!! // HideReel will hide the reel view before it is being used, diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/patch/ReturnYouTubeDislikePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/patch/ReturnYouTubeDislikePatch.kt index aca52dca1..4acceb9b0 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/patch/ReturnYouTubeDislikePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/patch/ReturnYouTubeDislikePatch.kt @@ -12,15 +12,16 @@ import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.annotations.Patch import app.revanced.patcher.patch.impl.BytecodePatch import app.revanced.patches.youtube.layout.returnyoutubedislike.annotations.ReturnYouTubeDislikeCompatibility -import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.TextComponentSpecParentFingerprint import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.DislikeFingerprint import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.LikeFingerprint import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.RemoveLikeFingerprint +import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.TextComponentSpecParentFingerprint +import app.revanced.patches.youtube.layout.returnyoutubedislike.resource.patch.ReturnYouTubeDislikeResourcePatch import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch import app.revanced.patches.youtube.misc.videoid.patch.VideoIdPatch @Patch -@DependsOn([IntegrationsPatch::class, VideoIdPatch::class]) +@DependsOn([IntegrationsPatch::class, VideoIdPatch::class, ReturnYouTubeDislikeResourcePatch::class]) @Name("return-youtube-dislike") @Description("Shows the dislike count of videos using the Return YouTube Dislike API.") @ReturnYouTubeDislikeCompatibility @@ -57,9 +58,9 @@ class ReturnYouTubeDislikePatch : BytecodePatch( val parentResult = TextComponentSpecParentFingerprint.result!! val createComponentMethod = parentResult.mutableClass.methods.find { method -> - method.parameters.size >= 19 && method.parameterTypes.takeLast(4) - .all { param -> param == "Ljava/util/concurrent/atomic/AtomicReference;" } - } + method.parameters.size >= 19 && method.parameterTypes.takeLast(4) + .all { param -> param == "Ljava/util/concurrent/atomic/AtomicReference;" } + } ?: return PatchResultError("TextComponentSpec.createComponent not found") val conversionContextParam = 5 diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/resource/patch/ReturnYouTubeDislikeResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/resource/patch/ReturnYouTubeDislikeResourcePatch.kt new file mode 100644 index 000000000..a229d7d38 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/resource/patch/ReturnYouTubeDislikeResourcePatch.kt @@ -0,0 +1,47 @@ +package app.revanced.patches.youtube.layout.returnyoutubedislike.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.impl.ResourceData +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.impl.ResourcePatch +import app.revanced.patches.youtube.layout.returnyoutubedislike.annotations.ReturnYouTubeDislikeCompatibility +import app.revanced.patches.youtube.misc.manifest.patch.FixLocaleConfigErrorPatch +import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch +import app.revanced.patches.youtube.misc.settings.framework.components.impl.Preference +import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource +import app.revanced.util.resources.ResourceUtils.iterateXmlNodeChildren + +@DependsOn([FixLocaleConfigErrorPatch::class, SettingsPatch::class]) +@Name("return-youtube-dislike-resource-patch") +@Description("Adds the preferences for Return YouTube Dislike.") +@ReturnYouTubeDislikeCompatibility +@Version("0.0.1") +class ReturnYouTubeDislikeResourcePatch : ResourcePatch() { + override fun execute(data: ResourceData): PatchResult { + val youtubePackage = "com.google.android.youtube" + SettingsPatch.addPreference( + Preference( + StringResource("revanced_ryd_settings_title", "Return YouTube Dislike"), + Preference.Intent( + youtubePackage, + "ryd_settings", + "com.google.android.libraries.social.licenses.LicenseActivity" + ), + StringResource("revanced_ryd_settings_summary", "Settings for Return YouTube Dislike"), + ) + ) + // merge strings + data.iterateXmlNodeChildren("returnyoutubedislike/host/values/strings.xml", "resources") { + // TODO: figure out why this is needed + if (!it.hasAttributes()) return@iterateXmlNodeChildren + val attributes = it.attributes + SettingsPatch.addString(attributes.getNamedItem("name")!!.nodeValue!!, it.textContent!!) + } + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/shorts/button/patch/ShortsButtonRemoverPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/shorts/button/patch/ShortsButtonRemoverPatch.kt index c30f43f9f..c3e2c3068 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/shorts/button/patch/ShortsButtonRemoverPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/shorts/button/patch/ShortsButtonRemoverPatch.kt @@ -14,11 +14,14 @@ import app.revanced.patches.youtube.layout.shorts.button.annotations.ShortsButto import app.revanced.patches.youtube.layout.shorts.button.fingerprints.PivotBarButtonTabEnumFingerprint import app.revanced.patches.youtube.layout.shorts.button.fingerprints.PivotBarButtonsViewFingerprint import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch +import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch +import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource +import app.revanced.patches.youtube.misc.settings.framework.components.impl.SwitchPreference import org.jf.dexlib2.iface.instruction.OneRegisterInstruction import org.jf.dexlib2.Opcode @Patch -@DependsOn([IntegrationsPatch::class]) +@DependsOn([IntegrationsPatch::class, SettingsPatch::class]) @Name("hide-shorts-button") @Description("Hides the shorts button on the navigation bar.") @ShortsButtonCompatibility @@ -29,6 +32,16 @@ class ShortsButtonRemoverPatch : BytecodePatch( ) ) { override fun execute(data: BytecodeData): PatchResult { + SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( + SwitchPreference( + "revanced_shorts_button_enabled", + StringResource("revanced_shorts_button_enabled_title", "Show shorts button"), + false, + StringResource("revanced_shorts_button_summary_on", "Shorts button is shown"), + StringResource("revanced_shorts_button_summary_off", "Shorts button is hidden") + ) + ) + val tabEnumResult = PivotBarButtonTabEnumFingerprint.result!! val tabEnumImplementation = tabEnumResult.mutableMethod.implementation!! val scanResultEndIndex = tabEnumResult.patternScanResult!!.endIndex diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/resource/patch/SponsorBlockResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/resource/patch/SponsorBlockResourcePatch.kt index f7f92ff95..b2d1c50f6 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/resource/patch/SponsorBlockResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/resource/patch/SponsorBlockResourcePatch.kt @@ -9,96 +9,112 @@ import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.impl.ResourcePatch import app.revanced.patches.youtube.layout.sponsorblock.annotations.SponsorBlockCompatibility import app.revanced.patches.youtube.misc.manifest.patch.FixLocaleConfigErrorPatch +import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch +import app.revanced.patches.youtube.misc.settings.framework.components.impl.Preference +import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource +import app.revanced.util.resources.ResourceUtils +import app.revanced.util.resources.ResourceUtils.copyResources import app.revanced.util.resources.ResourceUtils.copyXmlNode -import java.nio.file.Files +import app.revanced.util.resources.ResourceUtils.iterateXmlNodeChildren @Name("sponsorblock-resource-patch") @SponsorBlockCompatibility -@DependsOn([FixLocaleConfigErrorPatch::class]) +@DependsOn([FixLocaleConfigErrorPatch::class, SettingsPatch::class]) @Version("0.0.1") class SponsorBlockResourcePatch : ResourcePatch() { override fun execute(data: ResourceData): PatchResult { + val youtubePackage = "com.google.android.youtube" + SettingsPatch.addPreference( + Preference( + StringResource("sb_settings", "SponsorBlock"), + Preference.Intent( + youtubePackage, + "sponsorblock_settings", + "com.google.android.libraries.social.licenses.LicenseActivity" + ), + StringResource("revanced_sponsorblock_settings_summary", "SponsorBlock related settings"), + ) + ) val classLoader = this.javaClass.classLoader /* merge SponsorBlock strings to main strings */ - val stringsResourcePath = "values/strings.xml" - val stringsResourceInputStream = classLoader.getResourceAsStream("sponsorblock/$stringsResourcePath")!! + data.iterateXmlNodeChildren("sponsorblock/host/values/strings.xml", "resources") { + // TODO: figure out why this is needed + if (!it.hasAttributes()) return@iterateXmlNodeChildren - // copy nodes from the resources node to the real resource node - "resources".copyXmlNode( - data.xmlEditor[stringsResourceInputStream], - data.xmlEditor["res/$stringsResourcePath"] - ).close() // close afterwards + val attributes = it.attributes + val key = attributes.getNamedItem("name")!!.nodeValue!! + val value = it.textContent!! + + // all strings of SponsorBlock which have this attribute have the attribute value false, + // hence a null check suffices + val formatted = attributes.getNamedItem("formatted") == null + + SettingsPatch.addString(key, value, formatted) + } /* merge SponsorBlock drawables to main drawables */ - val drawables = "drawable" to arrayOf( - "ic_sb_adjust", - "ic_sb_compare", - "ic_sb_edit", - "ic_sb_logo", - "ic_sb_publish", - "ic_sb_voting" - ) - val layouts = "layout" to arrayOf( - "inline_sponsor_overlay", "new_segment", "skip_sponsor_button" - ) - - // collect resources - val xmlResources = arrayOf(drawables, layouts) - - // write resources - xmlResources.forEach { (path, resourceNames) -> - resourceNames.forEach { name -> - val relativePath = "$path/$name.xml" - - Files.copy( - classLoader.getResourceAsStream("sponsorblock/$relativePath")!!, - data["res"].resolve(relativePath).toPath() - ) - } + arrayOf( + ResourceUtils.ResourceGroup( + "layout", + "inline_sponsor_overlay.xml", + "new_segment.xml", + "skip_sponsor_button.xml" + ), + ResourceUtils.ResourceGroup( + // required resource for back button, because when the base APK is used, this resource will not exist + "drawable", + "ic_sb_adjust.xml", + "ic_sb_compare.xml", + "ic_sb_edit.xml", + "ic_sb_logo.xml", + "ic_sb_publish.xml", + "ic_sb_voting.xml" + ), + ResourceUtils.ResourceGroup( + // required resource for back button, because when the base APK is used, this resource will not exist + "drawable-xxxhdpi", "quantum_ic_skip_next_white_24.png" + ) + ).forEach { resourceGroup -> + data.copyResources("sponsorblock", resourceGroup) } /* merge xml nodes from the host to their real xml files */ - // collect all host resources - val hostingXmlResources = mapOf("layout" to arrayOf("youtube_controls_layout")) - // copy nodes from host resources to their real xml files - hostingXmlResources.forEach { (path, resources) -> - resources.forEach { resource -> - val hostingResourceStream = classLoader.getResourceAsStream("sponsorblock/host/$path/$resource.xml")!! + val hostingResourceStream = + classLoader.getResourceAsStream("sponsorblock/host/layout/youtube_controls_layout.xml")!! - val targetXmlEditor = data.xmlEditor["res/$path/$resource.xml"] - "RelativeLayout".copyXmlNode( - data.xmlEditor[hostingResourceStream], - targetXmlEditor - ).also { - val children = targetXmlEditor.file.getElementsByTagName("RelativeLayout").item(0).childNodes + val targetXmlEditor = data.xmlEditor["res/layout/youtube_controls_layout.xml"] + "RelativeLayout".copyXmlNode( + data.xmlEditor[hostingResourceStream], + targetXmlEditor + ).also { + val children = targetXmlEditor.file.getElementsByTagName("RelativeLayout").item(0).childNodes - // Replace the startOf with the voting button view so that the button does not overlap - for (i in 1 until children.length) { - val view = children.item(i) + // Replace the startOf with the voting button view so that the button does not overlap + for (i in 1 until children.length) { + val view = children.item(i) - // Replace the attribute for a specific node only - if (!(view.hasAttributes() && view.attributes.getNamedItem("android:id").nodeValue.endsWith("live_chat_overlay_button"))) continue + // Replace the attribute for a specific node only + if (!(view.hasAttributes() && view.attributes.getNamedItem("android:id").nodeValue.endsWith("live_chat_overlay_button"))) continue - // voting button id from the voting button view from the youtube_controls_layout.xml host file - val votingButtonId = "@+id/voting_button" + // voting button id from the voting button view from the youtube_controls_layout.xml host file + val votingButtonId = "@+id/voting_button" - view.attributes.getNamedItem("android:layout_toStartOf").nodeValue = votingButtonId + view.attributes.getNamedItem("android:layout_toStartOf").nodeValue = votingButtonId - break - } - }.close() // close afterwards + break } - } + }.close() // close afterwards + return PatchResultSuccess() } } \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/watermark/patch/HideWatermarkPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/watermark/patch/HideWatermarkPatch.kt index e9aa9317d..17eef1171 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/watermark/patch/HideWatermarkPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/watermark/patch/HideWatermarkPatch.kt @@ -17,9 +17,12 @@ import app.revanced.patches.youtube.layout.watermark.annotations.HideWatermarkCo import app.revanced.patches.youtube.layout.watermark.fingerprints.HideWatermarkParentFingerprint import app.revanced.patches.youtube.layout.watermark.fingerprints.HideWatermarkFingerprint import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch +import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch +import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource +import app.revanced.patches.youtube.misc.settings.framework.components.impl.SwitchPreference @Patch -@DependsOn([IntegrationsPatch::class]) +@DependsOn([IntegrationsPatch::class, SettingsPatch::class]) @Name("hide-watermark") @Description("Hides creator's watermarks on videos.") @HideWatermarkCompatibility @@ -30,6 +33,16 @@ class HideWatermarkPatch : BytecodePatch( ) ) { override fun execute(data: BytecodeData): PatchResult { + SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( + SwitchPreference( + "revanced_branding_watermark_enabled", + StringResource("revanced_branding_watermark_enabled_title", "Show branding watermark"), + false, + StringResource("revanced_branding_watermark_summary_on", "Branding watermark is shown"), + StringResource("revanced_branding_watermark_summary_off", "Branding watermark is hidden") + ) + ) + HideWatermarkFingerprint.resolve(data, HideWatermarkParentFingerprint.result!!.classDef) val result = HideWatermarkFingerprint.result ?: return PatchResultError("Required parent method could not be found.") diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/widesearchbar/fingerprints/WideSearchbarTwoParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/widesearchbar/fingerprints/WideSearchbarTwoParentFingerprint.kt index ae3a3f97b..67af9a034 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/widesearchbar/fingerprints/WideSearchbarTwoParentFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/widesearchbar/fingerprints/WideSearchbarTwoParentFingerprint.kt @@ -3,10 +3,8 @@ package app.revanced.patches.youtube.layout.widesearchbar.fingerprints import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod -import app.revanced.patches.youtube.layout.reels.annotations.HideReelsCompatibility +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patches.youtube.layout.widesearchbar.annotations.WideSearchbarCompatibility import org.jf.dexlib2.AccessFlags @@ -14,7 +12,6 @@ import org.jf.dexlib2.AccessFlags @MatchingMethod( "Lkrf;", "i" ) -@FuzzyPatternScanMethod(3) @WideSearchbarCompatibility @Version("0.0.1") diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/widesearchbar/patch/WideSearchbarPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/widesearchbar/patch/WideSearchbarPatch.kt index 30c9e18f7..3eb19836f 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/widesearchbar/patch/WideSearchbarPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/widesearchbar/patch/WideSearchbarPatch.kt @@ -19,9 +19,12 @@ import app.revanced.patches.youtube.layout.widesearchbar.fingerprints.WideSearch import app.revanced.patches.youtube.layout.widesearchbar.fingerprints.WideSearchbarTwoFingerprint import app.revanced.patches.youtube.layout.widesearchbar.fingerprints.WideSearchbarTwoParentFingerprint import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch +import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch +import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource +import app.revanced.patches.youtube.misc.settings.framework.components.impl.SwitchPreference @Patch -@DependsOn([IntegrationsPatch::class]) +@DependsOn([IntegrationsPatch::class, SettingsPatch::class]) @Name("enable-wide-searchbar") @Description("Replaces the search icon with a wide search bar. This will hide the YouTube logo when active.") @WideSearchbarCompatibility @@ -32,6 +35,16 @@ class WideSearchbarPatch : BytecodePatch( ) ) { override fun execute(data: BytecodeData): PatchResult { + SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( + SwitchPreference( + "revanced_wide_searchbar_enabled", + StringResource("revanced_wide_searchbar_enabled_title", "Enable wide search bar"), + false, + StringResource("revanced_wide_searchbar_summary_on", "Wide search bar is enabled"), + StringResource("revanced_wide_searchbar_summary_off", "Wide search bar is disabled") + ) + ) + WideSearchbarOneFingerprint.resolve(data, WideSearchbarOneParentFingerprint.result!!.classDef) WideSearchbarTwoFingerprint.resolve(data, WideSearchbarTwoParentFingerprint.result!!.classDef) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/autorepeat/patch/AutoRepeatPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/autorepeat/patch/AutoRepeatPatch.kt index 27e7ba7cd..3cdad5e13 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/autorepeat/patch/AutoRepeatPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/autorepeat/patch/AutoRepeatPatch.kt @@ -17,6 +17,9 @@ import app.revanced.patches.youtube.misc.autorepeat.annotations.AutoRepeatCompat import app.revanced.patches.youtube.misc.autorepeat.fingerprints.AutoRepeatFingerprint import app.revanced.patches.youtube.misc.autorepeat.fingerprints.AutoRepeatParentFingerprint import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch +import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch +import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource +import app.revanced.patches.youtube.misc.settings.framework.components.impl.SwitchPreference @Patch @DependsOn([IntegrationsPatch::class]) @@ -30,6 +33,16 @@ class AutoRepeatPatch : BytecodePatch( ) ) { override fun execute(data: BytecodeData): PatchResult { + SettingsPatch.PreferenceScreen.MISC.addPreferences( + SwitchPreference( + "revanced_pref_auto_repeat", + StringResource("revanced_auto_repeat_enabled_title", "Enable auto-repeat"), + true, + StringResource("revanced_auto_repeat_summary_on", "Auto-repeat is enabled"), + StringResource("revanced_auto_repeat_summary_off", "Auto-repeat is disabled") + ) + ) + //Get Result from the ParentFingerprint which is the playMethod we need to get. val parentResult = AutoRepeatParentFingerprint.result ?: return PatchResultError("ParentFingerprint did not resolve.") diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/customplaybackspeed/patch/CustomPlaybackSpeedPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/customplaybackspeed/patch/CustomPlaybackSpeedPatch.kt index 34d92b494..09ef68f6b 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/customplaybackspeed/patch/CustomPlaybackSpeedPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/customplaybackspeed/patch/CustomPlaybackSpeedPatch.kt @@ -35,6 +35,8 @@ class CustomPlaybackSpeedPatch : BytecodePatch( ) { override fun execute(data: BytecodeData): PatchResult { + //TODO: include setting to skip remembering the new speed + val arrayGenMethod = SpeedArrayGeneratorFingerprint.result?.mutableMethod!! val arrayGenMethodImpl = arrayGenMethod.implementation!! diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/hdrbrightness/patch/HDRBrightnessPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/hdrbrightness/patch/HDRBrightnessPatch.kt index 5183bdd94..b7550a221 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/hdrbrightness/patch/HDRBrightnessPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/hdrbrightness/patch/HDRBrightnessPatch.kt @@ -14,6 +14,9 @@ import app.revanced.patcher.patch.impl.BytecodePatch import app.revanced.patches.youtube.misc.hdrbrightness.annotations.HDRBrightnessCompatibility import app.revanced.patches.youtube.misc.hdrbrightness.fingerprints.HDRBrightnessFingerprintXXZ import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch +import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch +import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource +import app.revanced.patches.youtube.misc.settings.framework.components.impl.SwitchPreference import org.jf.dexlib2.iface.instruction.ReferenceInstruction import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction import org.jf.dexlib2.iface.reference.FieldReference @@ -23,13 +26,23 @@ import org.jf.dexlib2.iface.reference.FieldReference @Description("Makes the brightness of HDR videos follow the system default.") @HDRBrightnessCompatibility @Version("0.0.2") -@DependsOn([IntegrationsPatch::class]) +@DependsOn([IntegrationsPatch::class, SettingsPatch::class]) class HDRBrightnessPatch : BytecodePatch( listOf( HDRBrightnessFingerprintXXZ ) ) { override fun execute(data: BytecodeData): PatchResult { + SettingsPatch.PreferenceScreen.MISC.addPreferences( + SwitchPreference( + "revanced_pref_hdr_autobrightness", + StringResource("revanced_hdr_autobrightness_enabled_title", "Enable auto HDR brightness"), + true, + StringResource("revanced_hdr_autobrightness_summary_on", "Auto HDR brightness is enabled"), + StringResource("revanced_hdr_autobrightness_summary_off", "Auto HDR brightness is disabled") + ) + ) + val method = HDRBrightnessFingerprintXXZ.result?.mutableMethod ?: return PatchResultError("HDRBrightnessFingerprint could not resolve the method!") diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/manifest/patch/FixLocaleConfigErrorPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/manifest/patch/FixLocaleConfigErrorPatch.kt index fd9eaa30e..30ed3f3ed 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/manifest/patch/FixLocaleConfigErrorPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/manifest/patch/FixLocaleConfigErrorPatch.kt @@ -28,8 +28,7 @@ class FixLocaleConfigErrorPatch : ResourcePatch() { // by replacing the attributes name val attribute = "android:localeConfig" applicationNode.setAttribute("localeConfig", applicationNode.getAttribute(attribute)) - applicationNode.removeAttribute("android:localeConfig") - + applicationNode.removeAttribute(attribute) } return PatchResultSuccess() diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/microg/patch/resource/MicroGResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/microg/patch/resource/MicroGResourcePatch.kt index 2b1ab0275..20720f774 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/microg/patch/resource/MicroGResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/microg/patch/resource/MicroGResourcePatch.kt @@ -13,6 +13,9 @@ import app.revanced.patches.youtube.misc.microg.annotations.MicroGPatchCompatibi import app.revanced.patches.youtube.misc.microg.shared.Constants.BASE_MICROG_PACKAGE_NAME import app.revanced.patches.youtube.misc.microg.shared.Constants.REVANCED_PACKAGE_NAME import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsResourcePatch +import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch +import app.revanced.patches.youtube.misc.settings.framework.components.impl.Preference +import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource @Name("microg-resource-patch") @DependsOn([FixLocaleConfigErrorPatch::class, SettingsResourcePatch::class]) @@ -21,25 +24,14 @@ import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsResourc @Version("0.0.1") class MicroGResourcePatch : ResourcePatch() { override fun execute(data: ResourceData): PatchResult { - data.xmlEditor["res/xml/settings_fragment.xml"].use { - val settingsElementIntent = it.file.createElement("intent") - settingsElementIntent.setAttribute("android:targetPackage", "$BASE_MICROG_PACKAGE_NAME.android.gms") - settingsElementIntent.setAttribute("android:targetClass", "org.microg.gms.ui.SettingsActivity") - - val settingsElement = it.file.createElement("Preference") - settingsElement.setAttribute("android:title", "@string/microg_settings") - settingsElement.appendChild(settingsElementIntent) - - it.file.firstChild.appendChild(settingsElement) - } - - val settingsFragment = data["res/xml/settings_fragment.xml"] - settingsFragment.writeText( - settingsFragment.readText().replace( - "android:targetPackage=\"com.google.android.youtube", - "android:targetPackage=\"$REVANCED_PACKAGE_NAME" + SettingsPatch.addPreference( + Preference( + StringResource("microg_settings", "MicroG Settings"), + Preference.Intent("$BASE_MICROG_PACKAGE_NAME.android.gms", "", "org.microg.gms.ui.SettingsActivity"), + StringResource("microg_settings_summary", "Settings for MicroG"), ) ) + SettingsPatch.renameIntentsTargetPackage(REVANCED_PACKAGE_NAME) val manifest = data["AndroidManifest.xml"] manifest.writeText( diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/minimizedplayback/annotations/MinimizedPlaybackCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/annotations/MinimizedPlaybackCompatibility.kt similarity index 86% rename from src/main/kotlin/app/revanced/patches/youtube/layout/minimizedplayback/annotations/MinimizedPlaybackCompatibility.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/annotations/MinimizedPlaybackCompatibility.kt index ef3fe3217..45ff2cbab 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/minimizedplayback/annotations/MinimizedPlaybackCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/annotations/MinimizedPlaybackCompatibility.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.layout.minimizedplayback.annotations +package app.revanced.patches.youtube.misc.minimizedplayback.annotations import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/minimizedplayback/fingerprints/MinimizedPlaybackKidsFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/fingerprints/MinimizedPlaybackKidsFingerprint.kt similarity index 84% rename from src/main/kotlin/app/revanced/patches/youtube/layout/minimizedplayback/fingerprints/MinimizedPlaybackKidsFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/fingerprints/MinimizedPlaybackKidsFingerprint.kt index 4856108fe..d7f9555b9 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/minimizedplayback/fingerprints/MinimizedPlaybackKidsFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/fingerprints/MinimizedPlaybackKidsFingerprint.kt @@ -1,11 +1,11 @@ -package app.revanced.patches.youtube.layout.minimizedplayback.fingerprints +package app.revanced.patches.youtube.misc.minimizedplayback.fingerprints import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import app.revanced.patches.youtube.layout.minimizedplayback.annotations.MinimizedPlaybackCompatibility +import app.revanced.patches.youtube.misc.minimizedplayback.annotations.MinimizedPlaybackCompatibility import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.Opcode diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/minimizedplayback/fingerprints/MinimizedPlaybackManagerFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/fingerprints/MinimizedPlaybackManagerFingerprint.kt similarity index 88% rename from src/main/kotlin/app/revanced/patches/youtube/layout/minimizedplayback/fingerprints/MinimizedPlaybackManagerFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/fingerprints/MinimizedPlaybackManagerFingerprint.kt index a8cd631c9..5bf64a58f 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/minimizedplayback/fingerprints/MinimizedPlaybackManagerFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/fingerprints/MinimizedPlaybackManagerFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.layout.minimizedplayback.fingerprints +package app.revanced.patches.youtube.misc.minimizedplayback.fingerprints import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version @@ -6,7 +6,7 @@ import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod -import app.revanced.patches.youtube.layout.minimizedplayback.annotations.MinimizedPlaybackCompatibility +import app.revanced.patches.youtube.misc.minimizedplayback.annotations.MinimizedPlaybackCompatibility import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.Opcode diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/minimizedplayback/fingerprints/MinimizedPlaybackSettingsFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/fingerprints/MinimizedPlaybackSettingsFingerprint.kt similarity index 80% rename from src/main/kotlin/app/revanced/patches/youtube/layout/minimizedplayback/fingerprints/MinimizedPlaybackSettingsFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/fingerprints/MinimizedPlaybackSettingsFingerprint.kt index 4014c6007..c36f14f2a 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/minimizedplayback/fingerprints/MinimizedPlaybackSettingsFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/fingerprints/MinimizedPlaybackSettingsFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.layout.minimizedplayback.fingerprints +package app.revanced.patches.youtube.misc.minimizedplayback.fingerprints import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version @@ -6,10 +6,9 @@ import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import app.revanced.patches.youtube.layout.minimizedplayback.annotations.MinimizedPlaybackCompatibility +import app.revanced.patches.youtube.misc.minimizedplayback.annotations.MinimizedPlaybackCompatibility import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.Opcode -import org.jf.dexlib2.iface.instruction.WideLiteralInstruction @Name("minimized-playback-manager-fingerprint") @MatchingMethod( diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/minimizedplayback/patch/MinimizedPlaybackPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/patch/MinimizedPlaybackPatch.kt similarity index 68% rename from src/main/kotlin/app/revanced/patches/youtube/layout/minimizedplayback/patch/MinimizedPlaybackPatch.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/patch/MinimizedPlaybackPatch.kt index 9b8fe1453..ddb309382 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/minimizedplayback/patch/MinimizedPlaybackPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/patch/MinimizedPlaybackPatch.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.layout.minimizedplayback.patch +package app.revanced.patches.youtube.misc.minimizedplayback.patch import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name @@ -12,11 +12,14 @@ import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.annotations.Patch import app.revanced.patcher.patch.impl.BytecodePatch import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod -import app.revanced.patches.youtube.layout.minimizedplayback.annotations.MinimizedPlaybackCompatibility -import app.revanced.patches.youtube.layout.minimizedplayback.fingerprints.MinimizedPlaybackKidsFingerprint -import app.revanced.patches.youtube.layout.minimizedplayback.fingerprints.MinimizedPlaybackManagerFingerprint -import app.revanced.patches.youtube.layout.minimizedplayback.fingerprints.MinimizedPlaybackSettingsFingerprint +import app.revanced.patches.youtube.misc.minimizedplayback.annotations.MinimizedPlaybackCompatibility +import app.revanced.patches.youtube.misc.minimizedplayback.fingerprints.MinimizedPlaybackKidsFingerprint +import app.revanced.patches.youtube.misc.minimizedplayback.fingerprints.MinimizedPlaybackManagerFingerprint +import app.revanced.patches.youtube.misc.minimizedplayback.fingerprints.MinimizedPlaybackSettingsFingerprint import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch +import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch +import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource +import app.revanced.patches.youtube.misc.settings.framework.components.impl.SwitchPreference import org.jf.dexlib2.iface.instruction.ReferenceInstruction import org.jf.dexlib2.iface.reference.MethodReference @@ -24,7 +27,7 @@ import org.jf.dexlib2.iface.reference.MethodReference @Patch @Name("minimized-playback") @Description("Enables minimized and background playback.") -@DependsOn([IntegrationsPatch::class]) +@DependsOn([IntegrationsPatch::class, SettingsPatch::class]) @MinimizedPlaybackCompatibility @Version("0.0.1") class MinimizedPlaybackPatch : BytecodePatch( @@ -33,6 +36,16 @@ class MinimizedPlaybackPatch : BytecodePatch( ) ) { override fun execute(data: BytecodeData): PatchResult { + SettingsPatch.PreferenceScreen.MISC.addPreferences( + SwitchPreference( + "revanced_enable_minimized_playback", + StringResource("revanced_minimized_playback_enabled_title", "Enable minimized playback"), + true, + StringResource("revanced_minimized_playback_summary_on", "Minimized playback is enabled"), + StringResource("revanced_minimized_playback_summary_off", "Minimized playback is disabled") + ) + ) + // Instead of removing all instructions like Vanced, // we return the method at the beginning instead MinimizedPlaybackManagerFingerprint.result!!.mutableMethod.addInstructions( diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/quality/patch/RememberVideoQualityPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/quality/patch/RememberVideoQualityPatch.kt index 17c201389..78ef2ed48 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/quality/patch/RememberVideoQualityPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/quality/patch/RememberVideoQualityPatch.kt @@ -33,6 +33,8 @@ class RememberVideoQualityPatch : BytecodePatch( ) ) { override fun execute(data: BytecodeData): PatchResult { + //TODO: include setting to skip remembering the new quality + val setterMethod = VideoQualitySetterFingerprint.result!! VideoUserQualityChangeFingerprint.resolve(data, setterMethod.classDef) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/LicenseActivityFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/LicenseActivityFingerprint.kt index 12885932d..3b58257ac 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/LicenseActivityFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/LicenseActivityFingerprint.kt @@ -4,7 +4,7 @@ import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import app.revanced.patches.youtube.layout.returnyoutubedislike.annotations.ReturnYouTubeDislikeCompatibility +import app.revanced.patches.youtube.misc.settings.annotations.SettingsCompatibility // TODO: This is more of a class fingerprint than a method fingerprint. // Convert to a class fingerprint whenever possible. @@ -12,7 +12,7 @@ import app.revanced.patches.youtube.layout.returnyoutubedislike.annotations.Retu @MatchingMethod( "Lcom/google/android/libraries/social/licenses/LicenseActivity;", "onCreate" ) -@ReturnYouTubeDislikeCompatibility +@SettingsCompatibility @Version("0.0.1") object LicenseActivityFingerprint : MethodFingerprint( null, diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/ReVancedSettingsActivityFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/ReVancedSettingsActivityFingerprint.kt index 4b102f6f0..60d0a06ce 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/ReVancedSettingsActivityFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/ReVancedSettingsActivityFingerprint.kt @@ -2,10 +2,9 @@ package app.revanced.patches.youtube.misc.settings.bytecode.fingerprints import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version -import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import app.revanced.patches.youtube.layout.returnyoutubedislike.annotations.ReturnYouTubeDislikeCompatibility +import app.revanced.patches.youtube.misc.settings.annotations.SettingsCompatibility // TODO: This is more of a class fingerprint than a method fingerprint. // Convert to a class fingerprint whenever possible. @@ -13,7 +12,7 @@ import app.revanced.patches.youtube.layout.returnyoutubedislike.annotations.Retu @MatchingMethod( "Lapp/revanced/integrations/settingsmenu/ReVancedSettingActivity;", "initializeSettings" ) -@ReturnYouTubeDislikeCompatibility +@SettingsCompatibility @Version("0.0.1") object ReVancedSettingsActivityFingerprint : MethodFingerprint( null, diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/ThemeSetterFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/ThemeSetterFingerprint.kt index 148590939..45c5b69a4 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/ThemeSetterFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/ThemeSetterFingerprint.kt @@ -4,7 +4,7 @@ import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import app.revanced.patches.youtube.layout.returnyoutubedislike.annotations.ReturnYouTubeDislikeCompatibility +import app.revanced.patches.youtube.misc.settings.annotations.SettingsCompatibility import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch import org.jf.dexlib2.Opcode import org.jf.dexlib2.iface.instruction.WideLiteralInstruction @@ -13,7 +13,7 @@ import org.jf.dexlib2.iface.instruction.WideLiteralInstruction @MatchingMethod( "Lfyq;", "a" ) -@ReturnYouTubeDislikeCompatibility +@SettingsCompatibility @Version("0.0.1") object ThemeSetterFingerprint : MethodFingerprint( "L", diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/patch/SettingsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/patch/SettingsPatch.kt index d4e7b4227..72eb3d048 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/patch/SettingsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/patch/SettingsPatch.kt @@ -18,14 +18,20 @@ import app.revanced.patches.youtube.misc.settings.annotations.SettingsCompatibil import app.revanced.patches.youtube.misc.settings.bytecode.fingerprints.LicenseActivityFingerprint import app.revanced.patches.youtube.misc.settings.bytecode.fingerprints.ReVancedSettingsActivityFingerprint import app.revanced.patches.youtube.misc.settings.bytecode.fingerprints.ThemeSetterFingerprint +import app.revanced.patches.youtube.misc.settings.framework.components.BasePreference +import app.revanced.patches.youtube.misc.settings.framework.components.impl.ArrayResource +import app.revanced.patches.youtube.misc.settings.framework.components.impl.Preference +import app.revanced.patches.youtube.misc.settings.framework.components.impl.PreferenceScreen +import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsResourcePatch +import org.jf.dexlib2.util.MethodUtil +import java.io.Closeable @Patch @DependsOn( [ IntegrationsPatch::class, SettingsResourcePatch::class, - ResourceIdMappingProviderResourcePatch::class ] ) @Name("settings") @@ -34,7 +40,7 @@ import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsResourc @Version("0.0.1") class SettingsPatch : BytecodePatch( listOf(LicenseActivityFingerprint, ReVancedSettingsActivityFingerprint, ThemeSetterFingerprint) -) { +), Closeable { override fun execute(data: BytecodeData): PatchResult { val licenseActivityResult = LicenseActivityFingerprint.result!! val settingsResult = ReVancedSettingsActivityFingerprint.result!! @@ -65,7 +71,7 @@ class SettingsPatch : BytecodePatch( ) } - // add the setTheme call to the onCreate method to not affect the offsets. + // add the setTheme call to the onCreate method to not affect the offsets onCreate.addInstructions( 1, """ @@ -74,18 +80,76 @@ class SettingsPatch : BytecodePatch( """ ) - // add the initializeSettings call to the onCreate method. + // add the initializeSettings call to the onCreate method onCreate.addInstruction( 0, "invoke-static { p0 }, ${settingsClass.type}->$setThemeMethodName(${licenseActivityClass.type})V" ) + // get rid of, now, useless overridden methods + licenseActivityResult.mutableClass.methods.removeIf { it.name != "onCreate" && !MethodUtil.isConstructor(it) } + return PatchResultSuccess() } internal companion object { - val appearanceStringId = ResourceIdMappingProviderResourcePatch.resourceMappings.find { + // TODO: hide this somehow + var appearanceStringId: Long = ResourceIdMappingProviderResourcePatch.resourceMappings.find { it.type == "string" && it.name == "app_theme_appearance_dark" }!!.id + + fun addString(identifier: String, value: String, formatted: Boolean = true) = + SettingsResourcePatch.addString(identifier, value, formatted) + + fun addPreferenceScreen(preferenceScreen: app.revanced.patches.youtube.misc.settings.framework.components.impl.PreferenceScreen) = + SettingsResourcePatch.addPreferenceScreen(preferenceScreen) + + fun addPreference(preference: Preference) = + SettingsResourcePatch.addPreference(preference) + + fun addArray(arrayResource: ArrayResource) = + SettingsResourcePatch.addArray(arrayResource) + + fun renameIntentsTargetPackage(newPackage: String) { + SettingsResourcePatch.overrideIntentsTargetPackage = newPackage + } } + + /** + * Preference screens patches should add their settings to. + */ + internal enum class PreferenceScreen( + private val key: String, + private val title: String, + private val summary: String? = null, + private val preferences: MutableList = mutableListOf() + ) : Closeable { + ADS("ads", "Ads", "Ad related settings"), + INTERACTIONS("interactions", "Interaction", "Settings related to interactions"), + LAYOUT("layout", "Layout", "Settings related to the layout"), + MISC("misc", "Miscellaneous", "Miscellaneous patches"); + + override fun close() { + if (preferences.size == 0) return + + addPreferenceScreen( + PreferenceScreen( + key, + StringResource("${key}_title", title), + preferences, + summary?.let { summary -> + StringResource("${key}_summary", summary) + } + ) + ) + } + + /** + * Add preferences to the preference screen. + */ + fun addPreferences(vararg preferences: BasePreference) = this.preferences.addAll(preferences) + } + + override fun close() = PreferenceScreen.values().forEach(PreferenceScreen::close) + } \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/framework/components/BasePreference.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/framework/components/BasePreference.kt new file mode 100644 index 000000000..da9e7a1e7 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/framework/components/BasePreference.kt @@ -0,0 +1,14 @@ +package app.revanced.patches.youtube.misc.settings.framework.components + +import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource + +/** + * Base preference class for all preferences. + * + * @param key The key of the preference. + * @param title The title of the preference. + */ +internal abstract class BasePreference( + override val key: String, + override val title: StringResource, +) : IPreference \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/framework/components/IPreference.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/framework/components/IPreference.kt new file mode 100644 index 000000000..bf25a62b1 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/framework/components/IPreference.kt @@ -0,0 +1,23 @@ +package app.revanced.patches.youtube.misc.settings.framework.components + +import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource + +/** + * Preference + */ +internal interface IPreference { + /** + * Key of the preference. + */ + val key: String + + /** + * Title of the preference. + */ + val title: StringResource + + /** + * Tag name of the preference. + */ + val tag: String +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/framework/components/impl/ArrayResource.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/framework/components/impl/ArrayResource.kt new file mode 100644 index 000000000..c2c60dcf2 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/framework/components/impl/ArrayResource.kt @@ -0,0 +1,9 @@ +package app.revanced.patches.youtube.misc.settings.framework.components.impl + +/** + * Represents an array resource. + * + * @param name The name of the array resource. + * @param items The items of the array resource. + */ +internal data class ArrayResource(val name: String, val items: List) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/framework/components/impl/InputType.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/framework/components/impl/InputType.kt new file mode 100644 index 000000000..53b54a2b0 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/framework/components/impl/InputType.kt @@ -0,0 +1,6 @@ +package app.revanced.patches.youtube.misc.settings.framework.components.impl + +enum class InputType(val type: String) { + STRING("text"), + NUMBER("number"), +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/framework/components/impl/Preference.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/framework/components/impl/Preference.kt new file mode 100644 index 000000000..6818b5c89 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/framework/components/impl/Preference.kt @@ -0,0 +1,18 @@ +package app.revanced.patches.youtube.misc.settings.framework.components.impl + +/** + * A Preference object. + * + * @param title The title of the preference. + * @param intent The intent of the preference. + * @param summary The summary of the text preference. + */ +internal class Preference( + val title: StringResource, + val intent: Intent, + val summary: StringResource? = null +) { + val tag: String = "Preference" + + data class Intent(val targetPackage: String, val data: String, val targetClass: String) +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/framework/components/impl/PreferenceScreen.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/framework/components/impl/PreferenceScreen.kt new file mode 100644 index 000000000..9087540d3 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/framework/components/impl/PreferenceScreen.kt @@ -0,0 +1,20 @@ +package app.revanced.patches.youtube.misc.settings.framework.components.impl + +import app.revanced.patches.youtube.misc.settings.framework.components.BasePreference + +/** + * Preference screen. + * + * @param key The key of the preference. + * @param title The title of the preference. + * @param preferences Child preferences of this screen. + * @param summary The summary of the text preference. + */ +internal open class PreferenceScreen( + key: String, + title: StringResource, + val preferences: List, + var summary: StringResource? = null +) : BasePreference(key, title) { + override val tag: String = "PreferenceScreen" +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/framework/components/impl/StringResource.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/framework/components/impl/StringResource.kt new file mode 100644 index 000000000..7c731cc1b --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/framework/components/impl/StringResource.kt @@ -0,0 +1,10 @@ +package app.revanced.patches.youtube.misc.settings.framework.components.impl + +/** + * Represents a string value in the strings.xml file + * + * @param name The name of the string + * @param value The value of the string + * @param formatted If the string is formatted. If false, the attribute will be set + */ +internal data class StringResource(val name: String, val value: String, val formatted: Boolean = true) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/framework/components/impl/SwitchPreference.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/framework/components/impl/SwitchPreference.kt new file mode 100644 index 000000000..e98d60eff --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/framework/components/impl/SwitchPreference.kt @@ -0,0 +1,21 @@ +package app.revanced.patches.youtube.misc.settings.framework.components.impl + +import app.revanced.patches.youtube.misc.settings.framework.components.BasePreference + +/** + * Switch preference. + * + * @param key The key of the switch. + * @param title The title of the switch. + * @param default The default value of the switch. + * @param summaryOn The summary to show when the preference is enabled. + * @param summaryOff The summary to show when the preference is disabled. + */ +internal class SwitchPreference( + key: String, title: StringResource, + val default: Boolean = false, + var summaryOn: StringResource? = null, + var summaryOff: StringResource? = null +) : BasePreference(key, title) { + override val tag: String = "SwitchPreference" +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/framework/components/impl/TextPreference.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/framework/components/impl/TextPreference.kt new file mode 100644 index 000000000..e348e3740 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/framework/components/impl/TextPreference.kt @@ -0,0 +1,22 @@ +package app.revanced.patches.youtube.misc.settings.framework.components.impl + +import app.revanced.patches.youtube.misc.settings.framework.components.BasePreference + +/** + * Text preference. + * + * @param key The key of the text preference. + * @param title The title of the text preference. + * @param inputType The input type of the text preference. + * @param default The default value of the text preference. + * @param summary The summary of the text preference. + */ +internal class TextPreference( + key: String, + title: StringResource, + var inputType: InputType = InputType.STRING, + var default: String? = null, + var summary: StringResource? = null +) : BasePreference(key, title) { + override val tag: String = "EditTextPreference" +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/resource/patch/SettingsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/resource/patch/SettingsResourcePatch.kt index d9722fd8b..3db280b73 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/resource/patch/SettingsResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/resource/patch/SettingsResourcePatch.kt @@ -2,71 +2,290 @@ package app.revanced.patches.youtube.misc.settings.resource.patch import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.impl.DomFileEditor import app.revanced.patcher.data.impl.ResourceData import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.impl.ResourcePatch import app.revanced.patches.youtube.misc.manifest.patch.FixLocaleConfigErrorPatch +import app.revanced.patches.youtube.misc.mapping.patch.ResourceIdMappingProviderResourcePatch import app.revanced.patches.youtube.misc.settings.annotations.SettingsCompatibility +import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch +import app.revanced.patches.youtube.misc.settings.framework.components.BasePreference +import app.revanced.patches.youtube.misc.settings.framework.components.impl.* import app.revanced.util.resources.ResourceUtils import app.revanced.util.resources.ResourceUtils.copyResources -import app.revanced.util.resources.ResourceUtils.copyXmlNode import org.w3c.dom.Element +import org.w3c.dom.Node +import java.io.Closeable @Name("settings-resource-patch") @SettingsCompatibility -@DependsOn([FixLocaleConfigErrorPatch::class]) +@DependsOn([FixLocaleConfigErrorPatch::class, ResourceIdMappingProviderResourcePatch::class]) @Version("0.0.1") -class SettingsResourcePatch : ResourcePatch() { +class SettingsResourcePatch : ResourcePatch(), Closeable { + override fun execute(data: ResourceData): PatchResult { /* - * Copy strings + * create missing directory for the resources */ - - data.copyXmlNode("settings/host", "values/strings.xml", "resources") + data["res/drawable-ldrtl-xxxhdpi"].mkdirs() /* - * Copy arrays - */ - - data.copyXmlNode("settings/host", "values/arrays.xml", "resources") - - /* - * Copy preference fragments - */ - - data.copyXmlNode("settings/host", "xml/settings_fragment.xml", "PreferenceScreen") - - /* - * Copy layout resources + * copy layout resources */ arrayOf( ResourceUtils.ResourceGroup( "layout", - "xsettings_toolbar.xml", - "xsettings_with_toolbar.xml", - "xsettings_with_toolbar_layout.xml" - ), - ResourceUtils.ResourceGroup( - "xml", - "revanced_prefs.xml" + "revanced_settings_toolbar.xml", + "revanced_settings_with_toolbar.xml", + "revanced_settings_with_toolbar_layout.xml" + ), ResourceUtils.ResourceGroup( + "xml", "revanced_prefs.xml" // template for new preferences + ), ResourceUtils.ResourceGroup( + // required resource for back button, because when the base APK is used, this resource will not exist + "drawable-xxxhdpi", "quantum_ic_arrow_back_white_24.png" + ), ResourceUtils.ResourceGroup( + // required resource for back button, because when the base APK is used, this resource will not exist + "drawable-ldrtl-xxxhdpi", "quantum_ic_arrow_back_white_24.png" ) ).forEach { resourceGroup -> data.copyResources("settings", resourceGroup) } - data.xmlEditor["AndroidManifest.xml"].use { - val manifestNode = it - .file - .getElementsByTagName("manifest") - .item(0) as Element - - val element = it.file.createElement("uses-permission") - element.setAttribute("android:name", "android.permission.SCHEDULE_EXACT_ALARM") - manifestNode.appendChild(element) + data.xmlEditor["AndroidManifest.xml"].use { editor -> + editor.file.getElementsByTagName("manifest").item(0).also { + it.appendChild(it.ownerDocument.createElement("uses-permission").also { element -> + element.setAttribute("android:name", "android.permission.SCHEDULE_EXACT_ALARM") + }) + } } + revancedPreferencesEditor = data.xmlEditor["res/xml/revanced_prefs.xml"] + preferencesEditor = data.xmlEditor["res/xml/settings_fragment.xml"] + + stringsEditor = data.xmlEditor["res/values/strings.xml"] + arraysEditor = data.xmlEditor["res/values/arrays.xml"] + + // Add the ReVanced settings to the YouTube settings + val youtubePackage = "com.google.android.youtube" + SettingsPatch.addPreference( + Preference( + StringResource("revanced_settings", "ReVanced"), + Preference.Intent( + youtubePackage, "revanced_settings", "com.google.android.libraries.social.licenses.LicenseActivity" + ), + StringResource("revanced_settings_summary", "ReVanced specific settings"), + ) + ) + return PatchResultSuccess() } + + + internal companion object { + // if this is not null, all intents will be renamed to this + var overrideIntentsTargetPackage: String? = null + + private var revancedPreferenceNode: Node? = null + private var preferencesNode: Node? = null + + private var stringsNode: Node? = null + private var arraysNode: Node? = null + + private var strings = mutableListOf() + + private var revancedPreferencesEditor: DomFileEditor? = null + set(value) { + field = value + revancedPreferenceNode = value.getNode("PreferenceScreen") + } + private var preferencesEditor: DomFileEditor? = null + set(value) { + field = value + preferencesNode = value.getNode("PreferenceScreen") + } + + private var stringsEditor: DomFileEditor? = null + set(value) { + field = value + stringsNode = value.getNode("resources") + } + private var arraysEditor: DomFileEditor? = null + set(value) { + field = value + arraysNode = value.getNode("resources") + } + + /** + * Add a new string to the resources. + * + * @param identifier The key of the string. + * @param value The value of the string. + * @throws IllegalArgumentException if the string already exists. + */ + fun addString(identifier: String, value: String, formatted: Boolean) = + StringResource(identifier, value, formatted).include() + + /** + * Add an array to the resources. + * + * @param arrayResource The array resource to add. + */ + fun addArray(arrayResource: ArrayResource) { + arraysNode!!.appendChild(arraysNode!!.ownerDocument.createElement("string-array").also { arrayNode -> + arrayResource.items.forEach { item -> + item.include() + + arrayNode.setAttribute("name", item.name) + + arrayNode.appendChild(arrayNode.ownerDocument.createElement("item").also { itemNode -> + itemNode.textContent = item.value + }) + } + }) + } + + /** + * Add a preference screen to the settings. + * + * @param preferenceScreen The name of the preference screen. + */ + fun addPreferenceScreen(preferenceScreen: PreferenceScreen) = + revancedPreferenceNode!!.addPreference(preferenceScreen) + + /** + * Add a preference fragment to the preferences. + * + * @param preference The preference to add. + */ + fun addPreference(preference: Preference) { + preferencesNode!!.appendChild(preferencesNode.createElement(preference.tag).also { preferenceNode -> + preferenceNode.setAttribute( + "android:title", "@string/${preference.title.also { it.include() }.name}" + ) + preference.summary?.let { summary -> + preferenceNode.setAttribute("android:summary", "@string/${summary.also { it.include() }.name}") + } + + preferenceNode.appendChild(preferenceNode.createElement("intent").also { intentNode -> + intentNode.setAttribute("android:targetPackage", preference.intent.targetPackage) + intentNode.setAttribute("android:data", preference.intent.data) + intentNode.setAttribute("android:targetClass", preference.intent.targetClass) + }) + }) + } + + + /** + * Add a preference to the settings. + * + * @param preference The preference to add. + */ + private fun Node.addPreference(preference: BasePreference) { + // add a summary to the element + fun Element.addSummary(summaryResource: StringResource?, summaryType: SummaryType = SummaryType.DEFAULT) = + summaryResource?.let { summary -> + setAttribute("android:${summaryType.type}", "@string/${summary.also { it.include() }.name}") + } + + fun Element.addDefault(default: T) { + default?.let { + setAttribute( + "android:defaultValue", when (it) { + is Boolean -> if (it) "true" else "false" + is String -> it + else -> throw IllegalArgumentException("Unsupported default value type: ${it::class.java.name}") + } + ) + } + } + + val preferenceElement = ownerDocument.createElement(preference.tag) + preferenceElement.setAttribute("android:key", preference.key) + preferenceElement.setAttribute("android:title", "@string/${preference.title.also { it.include() }.name}") + + when (preference) { + is PreferenceScreen -> { + for (childPreference in preference.preferences) preferenceElement.addPreference(childPreference) + preferenceElement.addSummary(preference.summary) + } + is SwitchPreference -> { + preferenceElement.addDefault(preference.default) + preferenceElement.addSummary(preference.summaryOn, SummaryType.ON) + preferenceElement.addSummary(preference.summaryOff, SummaryType.OFF) + } + is TextPreference -> { + preferenceElement.setAttribute("android:inputType", preference.inputType.type) + preferenceElement.addDefault(preference.default) + preferenceElement.addSummary(preference.summary) + } + } + + appendChild(preferenceElement) + } + + /** + * Add a new string to the resources. + * + * @throws IllegalArgumentException if the string already exists. + */ + private fun StringResource.include() { + if (strings.any { it.name == name }) return + strings.add(this) + } + + private fun DomFileEditor?.getNode(tagName: String) = this!!.file.getElementsByTagName(tagName).item(0) + + private fun Node?.createElement(tagName: String) = this!!.ownerDocument.createElement(tagName) + + private enum class SummaryType(val type: String) { + DEFAULT("summary"), ON("summaryOn"), OFF("summaryOff") + } + } + + override fun close() { + // merge all strings, skip duplicates + strings.forEach { stringResource -> + stringsNode!!.appendChild(stringsNode!!.ownerDocument.createElement("string").also { stringElement -> + stringElement.setAttribute("name", stringResource.name) + + // if the string is un-formatted, explicitly add the formatted attribute + if (!stringResource.formatted) stringElement.setAttribute("formatted", "false") + + stringElement.textContent = stringResource.value + }) + } + + // rename the intent package names if it was set + overrideIntentsTargetPackage?.let { packageName -> + val preferences = preferencesEditor!!.getNode("PreferenceScreen").childNodes + for (i in 1 until preferences.length) { + val preferenceNode = preferences.item(i) + // preferences have a child node with the intent tag, skip over every other node + if (preferenceNode.childNodes.length == 0) continue + + val intentNode = preferenceNode.firstChild + + // if the node doesn't have a target package attribute, skip it + val targetPackageAttribute = intentNode.attributes.getNamedItem("android:targetPackage") ?: continue + + // do not replace intent target package if the package name is not from YouTube + val youtubePackage = "com.google.android.youtube" + if (targetPackageAttribute.nodeValue != youtubePackage) continue + + // replace the target package name + intentNode.attributes.setNamedItem(preferenceNode.ownerDocument.createAttribute("android:targetPackage") + .also { attribute -> + attribute.value = packageName + }) + } + } + + revancedPreferencesEditor?.close() + preferencesEditor?.close() + stringsEditor?.close() + arraysEditor?.close() + } } \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/videobuffer/patch/CustomVideoBufferPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/videobuffer/patch/CustomVideoBufferPatch.kt index 89d47c635..f0f8cb86b 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/videobuffer/patch/CustomVideoBufferPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/videobuffer/patch/CustomVideoBufferPatch.kt @@ -7,8 +7,14 @@ import app.revanced.patcher.data.impl.BytecodeData import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.annotations.Patch import app.revanced.patcher.patch.impl.BytecodePatch +import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch +import app.revanced.patches.youtube.misc.settings.framework.components.impl.InputType +import app.revanced.patches.youtube.misc.settings.framework.components.impl.PreferenceScreen +import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource +import app.revanced.patches.youtube.misc.settings.framework.components.impl.TextPreference import app.revanced.patches.youtube.misc.videobuffer.annotations.CustomVideoBufferCompatibility import app.revanced.patches.youtube.misc.videobuffer.fingerprints.MaxBufferFingerprint import app.revanced.patches.youtube.misc.videobuffer.fingerprints.PlaybackBufferFingerprint @@ -18,6 +24,7 @@ import org.jf.dexlib2.iface.instruction.OneRegisterInstruction @Patch @Name("custom-video-buffer") @Description("Lets you change the buffers of videos.") +@DependsOn([SettingsPatch::class]) @CustomVideoBufferCompatibility @Version("0.0.1") class CustomVideoBufferPatch : BytecodePatch( @@ -26,9 +33,52 @@ class CustomVideoBufferPatch : BytecodePatch( ) ) { override fun execute(data: BytecodeData): PatchResult { + SettingsPatch.PreferenceScreen.MISC.addPreferences( + PreferenceScreen( + "revanced_custom_video_buffer", + StringResource("revanced_custom_video_buffer_title", "Video buffer settings"), + listOf( + TextPreference( + "revanced_pref_max_buffer_ms", + StringResource("revanced_pref_max_buffer_ms_title", "Maximum buffer size"), + InputType.NUMBER, + "120000", + StringResource( + "revanced_pref_max_buffer_ms_summary", + "The maximum size of a buffer for playback" + ) + ), + TextPreference( + "revanced_pref_buffer_for_playback_ms", + StringResource("revanced_pref_buffer_for_playback_ms_title", "Maximum buffer for playback"), + InputType.NUMBER, + "2500", + StringResource( + "revanced_pref_buffer_for_playback_ms_summary", + "Maximum size of a buffer for playback" + ) + ), + TextPreference( + "revanced_pref_buffer_for_playback_after_rebuffer_ms", + StringResource( + "revanced_pref_buffer_for_playback_after_rebuffer_ms_title", + "Maximum buffer for playback after rebuffer" + ), + InputType.NUMBER, + "5000", + StringResource( + "revanced_pref_buffer_for_playback_after_rebuffer_ms_summary", + "Maximum size of a buffer for playback after rebuffering" + ) + ) + ), + StringResource("revanced_custom_video_buffer_summary", "Custom settings for video buffer") + ) + ) + execMaxBuffer() - execPlaybackBuffer(data) - execReBuffer(data) + execPlaybackBuffer() + execReBuffer() return PatchResultSuccess() } @@ -36,7 +86,7 @@ class CustomVideoBufferPatch : BytecodePatch( val result = MaxBufferFingerprint.result!! val method = result.mutableMethod val index = result.patternScanResult!!.endIndex - 1 - val register = (method.implementation!!.instructions.get(index) as OneRegisterInstruction).registerA + val register = (method.implementation!!.instructions[index] as OneRegisterInstruction).registerA method.addInstructions( index + 1, """ invoke-static {}, Lapp/revanced/integrations/patches/VideoBufferPatch;->getMaxBuffer()I @@ -45,11 +95,11 @@ class CustomVideoBufferPatch : BytecodePatch( ) } - private fun execPlaybackBuffer(data: BytecodeData) { + private fun execPlaybackBuffer() { val result = PlaybackBufferFingerprint.result!! val method = result.mutableMethod val index = result.patternScanResult!!.startIndex - val register = (method.implementation!!.instructions.get(index) as OneRegisterInstruction).registerA + val register = (method.implementation!!.instructions[index] as OneRegisterInstruction).registerA method.addInstructions( index + 1, """ invoke-static {}, Lapp/revanced/integrations/patches/VideoBufferPatch;->getPlaybackBuffer()I @@ -58,7 +108,7 @@ class CustomVideoBufferPatch : BytecodePatch( ) } - private fun execReBuffer(data: BytecodeData) { + private fun execReBuffer() { val result = ReBufferFingerprint.result!! val method = result.mutableMethod val index = result.patternScanResult!!.startIndex diff --git a/src/main/kotlin/app/revanced/util/resources/ResourceUtils.kt b/src/main/kotlin/app/revanced/util/resources/ResourceUtils.kt index bf874d3b0..301bad2c4 100644 --- a/src/main/kotlin/app/revanced/util/resources/ResourceUtils.kt +++ b/src/main/kotlin/app/revanced/util/resources/ResourceUtils.kt @@ -2,7 +2,9 @@ package app.revanced.util.resources import app.revanced.patcher.data.impl.DomFileEditor import app.revanced.patcher.data.impl.ResourceData +import org.w3c.dom.Node import java.nio.file.Files +import java.nio.file.StandardCopyOption internal object ResourceUtils { /** @@ -19,7 +21,7 @@ internal object ResourceUtils { val resourceFile = "${resourceGroup.resourceDirectoryName}/$resource" Files.copy( classLoader.getResourceAsStream("$sourceResourceDirectory/$resourceFile")!!, - targetResourceDirectory.resolve(resourceFile).toPath() + targetResourceDirectory.resolve(resourceFile).toPath(), StandardCopyOption.REPLACE_EXISTING ) } } @@ -33,20 +35,17 @@ internal object ResourceUtils { internal class ResourceGroup(val resourceDirectoryName: String, vararg val resources: String) /** - * Copy resources from the current class loader to the resource directory. - * @param resourceDirectory The directory of the resource. - * @param targetResource The target resource. - * @param elementTag The element to copy. + * Iterate through the children of a node by its tag. + * @param resource The xml resource. + * @param targetTag The target xml node. + * @param callback The callback to call when iterating over the nodes. */ - internal fun ResourceData.copyXmlNode(resourceDirectory: String, targetResource: String, elementTag: String) { - val stringsResourceInputStream = ResourceUtils.javaClass.classLoader.getResourceAsStream("$resourceDirectory/$targetResource")!! + internal fun ResourceData.iterateXmlNodeChildren(resource: String, targetTag: String, callback: (node: Node) -> Unit) = + xmlEditor[ResourceUtils.javaClass.classLoader.getResourceAsStream(resource)!!].use { + val stringsNode = it.file.getElementsByTagName(targetTag).item(0).childNodes + for (i in 1 until stringsNode.length - 1) callback(stringsNode.item(i)) + } - // Copy nodes from the resources node to the real resource node - elementTag.copyXmlNode( - this.xmlEditor[stringsResourceInputStream], - this.xmlEditor["res/$targetResource"] - ).close() - } /** * Copies the specified node of the source [DomFileEditor] to the target [DomFileEditor]. @@ -54,7 +53,7 @@ internal object ResourceUtils { * @param target the target [DomFileEditor]- * @return AutoCloseable that closes the target [DomFileEditor]s. */ - internal fun String.copyXmlNode(source: DomFileEditor, target: DomFileEditor): AutoCloseable { + fun String.copyXmlNode(source: DomFileEditor, target: DomFileEditor): AutoCloseable { val hostNodes = source.file.getElementsByTagName(this).item(0).childNodes val destinationResourceFile = target.file diff --git a/src/main/resources/returnyoutubedislike/host/values/strings.xml b/src/main/resources/returnyoutubedislike/host/values/strings.xml new file mode 100644 index 000000000..a223873ea --- /dev/null +++ b/src/main/resources/returnyoutubedislike/host/values/strings.xml @@ -0,0 +1,6 @@ + + Enable Return YouTube Dislike + Switch this on to see the dislike counts again + Return YouTube Dislike patch + This patch uses the Return YouTube Dislike API from https://returnyoutubedislike.com. Tap to learn more + \ No newline at end of file diff --git a/src/main/resources/settings/drawable-ldrtl-xxxhdpi/quantum_ic_arrow_back_white_24.png b/src/main/resources/settings/drawable-ldrtl-xxxhdpi/quantum_ic_arrow_back_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..d409b544b7f62950a69d7d1ea58e97ef6c5ea546 GIT binary patch literal 200 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD0wg^q?%xcg`aNA7Ln;{G-nuAwkU@eaku@Vo zy*{7I`hn!617~ZZ53W<`EZBV>sE~nSrqA|&tuL?bH@N#td|C81OZ4 j;g=t)KhFPL4YI<5v2M!JY~kXSEg+t!tDnm{r-UW|+8j)X literal 0 HcmV?d00001 diff --git a/src/main/resources/settings/drawable-xxxhdpi/quantum_ic_arrow_back_white_24.png b/src/main/resources/settings/drawable-xxxhdpi/quantum_ic_arrow_back_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..e27034d67874687a900f0f960c662e94cd633e2a GIT binary patch literal 194 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD0wg^q?%xcgIz3$+Ln;{G-r^K&b`Wq0WJxHR z+hbl+*u(m6U6udA_c1Lg>hl;G7;?6Tmes9(^C#@)&$XLAN2fmDK5_2;oXs^qKRrD? zT|a&wl=0u{XMX3o{EI(zZSFU;t5*oK`xGb|A7l~sF+e3G`eLnqRNcP#_|M_{efOCe b7~U|>UYh-J>#;zfqZmA0{an^LB{Ts5m>*B+ literal 0 HcmV?d00001 diff --git a/src/main/resources/settings/host/values/arrays.xml b/src/main/resources/settings/host/values/arrays.xml deleted file mode 100644 index 2e9447df8..000000000 --- a/src/main/resources/settings/host/values/arrays.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - @string/revanced_button_location_entry_none - @string/revanced_button_location_entry_player - @string/revanced_button_location_entry_buttoncontainer - @string/revanced_button_location_entry_both - - - NONE - PLAYER - BUTTON_CONTAINER - BOTH - - \ No newline at end of file diff --git a/src/main/resources/settings/host/values/strings.xml b/src/main/resources/settings/host/values/strings.xml deleted file mode 100644 index 4e95d3a5a..000000000 --- a/src/main/resources/settings/host/values/strings.xml +++ /dev/null @@ -1,227 +0,0 @@ - - - "Doesn't show auto-repeat button in the player overlay. Use the toggle below to control auto-repeat" - Auto-repeat button is shown in the player overlay - Auto-repeat button - Always Auto-repeat is off - Always Auto-repeat is on - Always Auto-repeat - Video watermark is hidden - Video watermark is shown - Video watermark - Buffer settings - Cast button is hidden - Cast button is shown - Cast button - Autoplay button is hidden - Autoplay button is shown - Autoplay button - Codec override - Extra debug logging is disabled - Extra Debug logging is enabled - Debug mode - Tap to join ReVanced on Discord - Discord server - Video brightness will follow your device\'s brightness on HDR landscape videos - Video brightness is set to max on HDR landscape videos - Override HDR Video Brightness - Info cards are hidden - Info cards are shown - Info cards - Layout settings - "The maximum duration of media that the player will attempt to buffer (in milliseconds) - - Default: 120000" - Maximum buffer - Miscellaneous - "The duration of media that must be buffered for playback to start or resume following a user action such as seeking (in milliseconds) - - Default: 2500" - Playback start - Select preferred video speed - Preferred video speed - "The duration of media that must be buffered for playback to resume after a rebuffer (in milliseconds). A rebuffer is defined to be caused by buffer depletion rather than a user action - - Default: 5000" - Rebuffer - End screens are hidden - End screens are shown - End screens - Support links - Support - Video settings - Tap to force usage of the VP9 codec - VP9 codec not forced - VP9 codec is enabled by default for supported devices, disable if you encounter stuttering/slowness in videos - VP9 codec - Wide search bar - Search bar style is defined by the app - Forcing wide search bar - Show shorts button - Shorts button is hidden - Shorts button is shown - Fullscreen panels - Fullscreen panels are hidden - Fullscreen panels are shown - Dynamic player - Dynamic player is defined automatically - Dynamic player is forced on square and vertical videos - Captions aren\'t enabled automatically at 0% volume - Captions are enabled automatically at 0% volume - Auto captions - Swipe controls for brightness are disabled - Swipe controls for brightness are enabled - Swipe controls for Brightness - Swipe controls for Brightness and Volume - Swipe controls - Swipe controls for volume are disabled - Swipe controls for volume are enabled - Swipe controls for Volume - Press-to-Swipe - Swipe controls are always active - Swipe controls require a long-press before activating - Vibrate on Press-to-Swipe - You\'ll get haptic feedback when activating Press-to-Swipe - You won\'t get haptic feedback when activating Press-to-Swipe - Overlay Timeout - How long the overlay is shown after changes (ms) - Overlay Text Size - Text size on the overlay - Overlay Background Transparency - Transparency value of the overlay background (0–255) - Swipe Magnitude Threshold - Minimum magnitude before a swipe is detected - Tablet style - Tablet style is turned on. For example suggested videos are only partially working - Tablet style is turned off - Tap to open our website - ReVanced website - Home ADS are hidden - Home ADS are shown - Home ADS - Video ADS - Video ADS are hidden - Video ADS are shown - Stories are hidden - Stories are shown - YouTube stories - AD settings - Tablet miniplayer is not being used - Tablet miniplayer is being used - Tablet miniplayer - - Comments removal - Comments removal is turned off (new comments / phones only) - Comments removal is turned on (new comments / phones only) - Community post removal - Community post removal is turned off - Community post removal is turned on - Compact banner removal - Compact banner removal is turned off - Compact banner removal is turned on - Compact movie removal - Compact movie removal is turned off - Compact movie removal is turned on - General layout ad removal - General layout ad removal is turned off - General layout ad removal is turned on - Movie shelf removal - Movie shelf removal is turned off - Movie shelf removal is turned on - Survey removal - Feed survey removal is turned off - Feed survey removal is turned on - Merchandise removal - Merchandise removal is turned off - Merchandise removal is turned on - Movie upsell removal - Movie upsell removal is turned off - Movie upsell removal is turned on - Emergency box removal - Emergency box removal is turned on - Emergency box removal is turned off - Info panel removal - Info panel removal is turned on - Info panel removal is turned off - Medical panel removal - Medical panel removal is turned on - Medical panel removal is turned off - Paid content removal - Paid content removal is turned on - Paid content removal is turned off - Suggested for you removal - Suggested for you removal is turned on - Suggested for you removal is turned off - General Suggestions removal - General Suggestions removal is turned on - General Suggestions removal is turned off - Latest posts removal - Latest posts removal is turned on - Latest posts removal is turned off - Channel guidelines removal - Channel guidelines removal is turned on - Channel guidelines removal is turned off - - Notification settings - "1. Google device registration and Cloud Messaging need to be enabled for notifications. - 2. ReVanced needs to be shown as registered under Cloud Messaging. - 3. Current State in Cloud Messaging must be Connected." - MicroG settings - ReVanced settings - - Seekbar Tapping - Seekbar Tapping (video progress bar) is disabled - Seekbar Tapping (video progress bar) is enabled - - Background playback - Background playback is disabled - Background playback is enabled - - Normal - - Shorts Shelf - Shorts Shelf removal is turned off - Shorts Shelf removal is turned on - - Create Button is hidden - Create Button is shown - Create Button - - Community Guidelines - Community Guidelines removal is turned off - Community Guidelines removal is turned on - - Copy Link Button is hidden from the player overlay - Copy Link Button is shown in the player overlay - Copy Link Button With Timestamp is hidden from the player overlay - Copy Link Button With Timestamp is shown in the player overlay - Copy Link Button With Timestamp - Copy Link Button - - Quality Settings style - Using default style video quality settings - Using old style video quality settings - - Video ad whitelisting - Video ad whitelisting is turned off - Video ad whitelisting is turned on. Use the ADS button under the player to whitelist a channel - ADS - SponsorBlock - Channel %s was added to the %s whitelist - Channel %s was removed from the %s whitelist - Failed to add channel %s to the %s whitelist - Failed to remove channel %s from the %s whitelist - Failed to retrieve channel details, received code %d - Hidden - In player - Under player - Both - Return YouTube Dislike settings - Uses the RYD API - SponsorBlock settings - Uses the sponsor.ajay.app API - Enable RYD - Switch this on to see the dislike counts again - Return YouTube Dislike Integration - This integration uses the RYD API from https://returnyoutubedislike.com. Tap to learn more - \ No newline at end of file diff --git a/src/main/resources/settings/host/xml/settings_fragment.xml b/src/main/resources/settings/host/xml/settings_fragment.xml deleted file mode 100644 index 2c8051292..000000000 --- a/src/main/resources/settings/host/xml/settings_fragment.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/src/main/resources/settings/layout/xsettings_toolbar.xml b/src/main/resources/settings/layout/revanced_settings_toolbar.xml similarity index 93% rename from src/main/resources/settings/layout/xsettings_toolbar.xml rename to src/main/resources/settings/layout/revanced_settings_toolbar.xml index d416e99b6..86c717712 100644 --- a/src/main/resources/settings/layout/xsettings_toolbar.xml +++ b/src/main/resources/settings/layout/revanced_settings_toolbar.xml @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/src/main/resources/settings/layout/revanced_settings_with_toolbar.xml b/src/main/resources/settings/layout/revanced_settings_with_toolbar.xml new file mode 100644 index 000000000..21ff59780 --- /dev/null +++ b/src/main/resources/settings/layout/revanced_settings_with_toolbar.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/main/resources/settings/layout/xsettings_with_toolbar_layout.xml b/src/main/resources/settings/layout/revanced_settings_with_toolbar_layout.xml similarity index 60% rename from src/main/resources/settings/layout/xsettings_with_toolbar_layout.xml rename to src/main/resources/settings/layout/revanced_settings_with_toolbar_layout.xml index 2f6ef13c8..31b20d945 100644 --- a/src/main/resources/settings/layout/xsettings_with_toolbar_layout.xml +++ b/src/main/resources/settings/layout/revanced_settings_with_toolbar_layout.xml @@ -1,5 +1,5 @@ - - + + \ No newline at end of file diff --git a/src/main/resources/settings/layout/xsettings_with_toolbar.xml b/src/main/resources/settings/layout/xsettings_with_toolbar.xml deleted file mode 100644 index 3043ff360..000000000 --- a/src/main/resources/settings/layout/xsettings_with_toolbar.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/src/main/resources/settings/xml/revanced_prefs.xml b/src/main/resources/settings/xml/revanced_prefs.xml index c821174b4..9562c0097 100644 --- a/src/main/resources/settings/xml/revanced_prefs.xml +++ b/src/main/resources/settings/xml/revanced_prefs.xml @@ -1,180 +1,4 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/main/resources/sponsorblock/drawable-xxxhdpi/quantum_ic_skip_next_white_24.png b/src/main/resources/sponsorblock/drawable-xxxhdpi/quantum_ic_skip_next_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..19c4929cca13b462dee093c2156ca904e52c4fad GIT binary patch literal 357 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD0wg^q?%&M7z^LQt;uuoF`1Y2e9%~|l>%&f$ zg_kt9Uio5{z#evh>jtB=g!P7|jSU+azGiEd&dOAqxOz`#SLZX8=YO~-=s(>1`@F;% z7^n-LS2W|H{Q2{3`{(M~f3OwLariW~{mo=X&rh?0%@iVwoLRR#m)Xd8(p_(5!?zjC zW(qf-&f)dAb|Q2qMDd?P2140PE}_?HYd-Es6#;R0aPwX z)}VoZ#>xFo*?A}HkL;c^(caDdlelD!m(LT!?N4UaF0@pP*L;66{M7c`=~eQpe$#u6{1-oD!M