mirror of
https://github.com/inotia00/revanced-patches.git
synced 2025-06-12 13:17:46 +02:00
feat: settings
patch framework (#266)
This commit is contained in:
@ -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
|
||||
|
@ -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!")
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
@ -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<String, Method>()
|
||||
@ -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
|
||||
|
@ -65,5 +65,4 @@ class SwipeControlsBytecodePatch : BytecodePatch(
|
||||
}
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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(
|
||||
|
@ -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;") }
|
||||
)
|
||||
)
|
@ -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;")
|
||||
}
|
||||
)
|
@ -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
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
@ -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()
|
||||
}
|
||||
}
|
@ -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") {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
@ -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.")
|
||||
|
@ -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")
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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.")
|
||||
|
@ -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!!
|
||||
|
||||
|
@ -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!")
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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(
|
||||
|
@ -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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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(
|
@ -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(
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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",
|
||||
|
@ -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<BasePreference> = 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)
|
||||
|
||||
}
|
@ -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
|
@ -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
|
||||
}
|
@ -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<StringResource>)
|
@ -0,0 +1,6 @@
|
||||
package app.revanced.patches.youtube.misc.settings.framework.components.impl
|
||||
|
||||
enum class InputType(val type: String) {
|
||||
STRING("text"),
|
||||
NUMBER("number"),
|
||||
}
|
@ -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)
|
||||
}
|
@ -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<BasePreference>,
|
||||
var summary: StringResource? = null
|
||||
) : BasePreference(key, title) {
|
||||
override val tag: String = "PreferenceScreen"
|
||||
}
|
@ -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)
|
@ -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"
|
||||
}
|
@ -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"
|
||||
}
|
@ -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<StringResource>()
|
||||
|
||||
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 <T> 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()
|
||||
}
|
||||
}
|
@ -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
|
||||
|
Reference in New Issue
Block a user