mirror of
https://github.com/inotia00/revanced-patches.git
synced 2025-06-12 05:07:41 +02:00
bump v2.147.0
This commit is contained in:
@ -1,14 +0,0 @@
|
||||
package app.revanced.patches.youtube.ad.general.annotation
|
||||
|
||||
import app.revanced.patcher.annotation.Compatibility
|
||||
import app.revanced.patcher.annotation.Package
|
||||
|
||||
@Compatibility(
|
||||
[Package(
|
||||
"com.google.android.youtube", arrayOf("17.49.37")
|
||||
)]
|
||||
)
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
internal annotation class GeneralAdsCompatibility
|
||||
|
@ -1,17 +0,0 @@
|
||||
package app.revanced.patches.youtube.ad.general.bytecode.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import app.revanced.patches.youtube.ad.general.resource.patch.GeneralAdsResourcePatch
|
||||
import org.jf.dexlib2.Opcode
|
||||
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
|
||||
|
||||
object ReelConstructorFingerprint : MethodFingerprint(
|
||||
opcodes = listOf(
|
||||
Opcode.INVOKE_VIRTUAL
|
||||
),
|
||||
customFingerprint = { method ->
|
||||
method.implementation?.instructions?.any {
|
||||
it.opcode == Opcode.CONST && (it as WideLiteralInstruction).wideLiteral == GeneralAdsResourcePatch.reelMultipleItemShelfId
|
||||
} ?: false
|
||||
}
|
||||
)
|
@ -1,91 +0,0 @@
|
||||
package app.revanced.patches.youtube.ad.general.bytecode.patch
|
||||
|
||||
import app.revanced.extensions.findMutableMethodOf
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.addInstruction
|
||||
import app.revanced.patcher.extensions.instruction
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultError
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patches.youtube.ad.general.annotation.GeneralAdsCompatibility
|
||||
import app.revanced.patches.youtube.ad.general.bytecode.fingerprints.ReelConstructorFingerprint
|
||||
import app.revanced.patches.youtube.ad.general.resource.patch.GeneralAdsResourcePatch
|
||||
import app.revanced.patches.youtube.misc.fix.verticalscroll.patch.VerticalScrollPatch
|
||||
import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||
import org.jf.dexlib2.iface.instruction.formats.Instruction31i
|
||||
import org.jf.dexlib2.iface.instruction.formats.Instruction35c
|
||||
|
||||
|
||||
@Patch
|
||||
@DependsOn([GeneralAdsResourcePatch::class, VerticalScrollPatch::class])
|
||||
@Name("general-ads")
|
||||
@Description("Removes general ads.")
|
||||
@GeneralAdsCompatibility
|
||||
@Version("0.0.1")
|
||||
class GeneralAdsPatch : BytecodePatch(
|
||||
listOf(ReelConstructorFingerprint)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
fun String.buildHideCall(viewRegister: Int) = "invoke-static { v$viewRegister }, " +
|
||||
"Lapp/revanced/integrations/patches/GeneralAdsPatch;" +
|
||||
"->" +
|
||||
"$this(Landroid/view/View;)V"
|
||||
|
||||
fun MutableMethod.injectHideCall(insertIndex: Int, viewRegister: Int, method: String) =
|
||||
this.addInstruction(insertIndex, method.buildHideCall(viewRegister))
|
||||
|
||||
context.classes.forEach { classDef ->
|
||||
classDef.methods.forEach { method ->
|
||||
with(method.implementation) {
|
||||
this?.instructions?.forEachIndexed { index, instruction ->
|
||||
if (instruction.opcode != org.jf.dexlib2.Opcode.CONST)
|
||||
return@forEachIndexed
|
||||
// Instruction to store the id adAttribution into a register
|
||||
if ((instruction as Instruction31i).wideLiteral != GeneralAdsResourcePatch.adAttributionId)
|
||||
return@forEachIndexed
|
||||
|
||||
val insertIndex = index + 1
|
||||
|
||||
// Call to get the view with the id adAttribution
|
||||
with(instructions.elementAt(insertIndex)) {
|
||||
if (opcode != org.jf.dexlib2.Opcode.INVOKE_VIRTUAL)
|
||||
return@forEachIndexed
|
||||
|
||||
// Hide the view
|
||||
val viewRegister = (this as Instruction35c).registerC
|
||||
context.proxy(classDef)
|
||||
.mutableClass
|
||||
.findMutableMethodOf(method)
|
||||
.injectHideCall(insertIndex, viewRegister, "hideAdAttributionView")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
with(
|
||||
ReelConstructorFingerprint.result
|
||||
?: return PatchResultError("Could not resolve fingerprint")
|
||||
) {
|
||||
// iput-object v$viewRegister, ...
|
||||
val insertIndex = this.scanResult.patternScanResult!!.startIndex + 2
|
||||
|
||||
with(this.mutableMethod) {
|
||||
val viewRegister = (instruction(insertIndex) as TwoRegisterInstruction).registerA
|
||||
|
||||
injectHideCall(insertIndex, viewRegister, "hideReelView")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
|
||||
}
|
@ -1,232 +0,0 @@
|
||||
package app.revanced.patches.youtube.ad.general.resource.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch
|
||||
import app.revanced.patches.shared.settings.preference.impl.InputType
|
||||
import app.revanced.patches.shared.settings.preference.impl.StringResource
|
||||
import app.revanced.patches.shared.settings.preference.impl.SwitchPreference
|
||||
import app.revanced.patches.shared.settings.preference.impl.TextPreference
|
||||
import app.revanced.patches.youtube.ad.general.annotation.GeneralAdsCompatibility
|
||||
import app.revanced.patches.youtube.misc.litho.filter.patch.LithoFilterPatch
|
||||
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.bytecode.patch.SettingsPatch.PreferenceScreen
|
||||
|
||||
@DependsOn(dependencies = [
|
||||
FixLocaleConfigErrorPatch::class,
|
||||
LithoFilterPatch::class,
|
||||
SettingsPatch::class,
|
||||
ResourceMappingPatch::class
|
||||
])
|
||||
@GeneralAdsCompatibility
|
||||
@Version("0.0.1")
|
||||
class GeneralAdsResourcePatch : ResourcePatch {
|
||||
internal companion object {
|
||||
var adAttributionId: Long = -1
|
||||
var reelMultipleItemShelfId: Long = -1
|
||||
}
|
||||
|
||||
override fun execute(context: ResourceContext): PatchResult {
|
||||
PreferenceScreen.ADS.addPreferences(
|
||||
SwitchPreference(
|
||||
"revanced_adremover_ad_removal",
|
||||
StringResource("revanced_adremover_ad_removal_enabled_title", "Hide 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_buttoned",
|
||||
StringResource("revanced_adremover_buttoned_enabled_title", "Hide buttoned ad"),
|
||||
true,
|
||||
StringResource("revanced_adremover_buttoned_enabled_summary_on", "Buttoned ads are hidden"),
|
||||
StringResource("revanced_adremover_buttoned_enabled_summary_off", "Buttoned ads are shown")
|
||||
),
|
||||
SwitchPreference(
|
||||
"revanced_adremover_merchandise",
|
||||
StringResource("revanced_adremover_merchandise_enabled_title", "Hide 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", "Hide community posts"),
|
||||
false,
|
||||
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", "Hide 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_movie",
|
||||
StringResource("revanced_adremover_movie_enabled_title", "Hide 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", "Hide 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",
|
||||
StringResource("revanced_adremover_shorts_enabled_title", "Hide shorts"),
|
||||
true,
|
||||
StringResource("revanced_adremover_shorts_enabled_summary_on", "Shorts are hidden"),
|
||||
StringResource("revanced_adremover_shorts_enabled_summary_off", "Shorts are shown")
|
||||
),
|
||||
SwitchPreference(
|
||||
"revanced_adremover_community_guidelines",
|
||||
StringResource("revanced_adremover_community_guidelines_enabled_title", "Hide 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", "Hide 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", "Hide info panels"),
|
||||
true,
|
||||
StringResource("revanced_adremover_info_panel_enabled_summary_on", "Info panels are hidden"),
|
||||
StringResource("revanced_adremover_info_panel_enabled_summary_off", "Info panels are shown")
|
||||
),
|
||||
SwitchPreference(
|
||||
"revanced_adremover_medical_panel",
|
||||
StringResource("revanced_adremover_medical_panel_enabled_title", "Hide 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", "Hide 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_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"
|
||||
)
|
||||
),
|
||||
SwitchPreference(
|
||||
"revanced_adremover_self_sponsor",
|
||||
StringResource("revanced_adremover_self_sponsor_enabled_title", "Hide self sponsored cards"),
|
||||
true,
|
||||
StringResource("revanced_adremover_self_sponsor_enabled_summary_on", "Self sponsored cards are hidden"),
|
||||
StringResource("revanced_adremover_self_sponsor_enabled_summary_off", "Self sponsored cards are shown")
|
||||
),
|
||||
SwitchPreference(
|
||||
"revanced_adremover_separator",
|
||||
StringResource("revanced_adremover_separator_title", "Hide gray separator"),
|
||||
true,
|
||||
StringResource("revanced_adremover_separator_summary_on", "Gray separators are hidden"),
|
||||
StringResource("revanced_adremover_separator_summary_off", "Gray separators are shown")
|
||||
),
|
||||
SwitchPreference(
|
||||
"revanced_adremover_chapter_teaser",
|
||||
StringResource(
|
||||
"revanced_adremover_chapter_teaser_enabled_title",
|
||||
"Hide chapter teaser under videos"
|
||||
),
|
||||
true,
|
||||
StringResource(
|
||||
"revanced_adremover_chapter_teaser_enabled_summary_on",
|
||||
"Chapter teasers are hidden"
|
||||
),
|
||||
StringResource(
|
||||
"revanced_adremover_chapter_teaser_enabled_summary_off",
|
||||
"Chapter teasers are shown"
|
||||
)
|
||||
),
|
||||
app.revanced.patches.shared.settings.preference.impl.PreferenceScreen(
|
||||
"revanced_adremover_custom",
|
||||
StringResource("revanced_adremover_custom_title", "Custom filter"),
|
||||
listOf(
|
||||
SwitchPreference(
|
||||
"revanced_adremover_custom_enabled",
|
||||
StringResource(
|
||||
"revanced_adremover_custom_enabled_title",
|
||||
"Enable custom filter"
|
||||
),
|
||||
false,
|
||||
StringResource(
|
||||
"revanced_adremover_custom_enabled_summary_on",
|
||||
"Custom filter is enabled"
|
||||
),
|
||||
StringResource(
|
||||
"revanced_adremover_custom_enabled_summary_off",
|
||||
"Custom filter is disabled"
|
||||
)
|
||||
),
|
||||
// TODO: This should be a ListPreference, which does not exist yet
|
||||
TextPreference(
|
||||
"revanced_adremover_custom_strings",
|
||||
StringResource("revanced_adremover_custom_strings_title", "Custom filter"),
|
||||
InputType.STRING,
|
||||
"",
|
||||
StringResource(
|
||||
"revanced_adremover_custom_strings_summary",
|
||||
"Filter components by their name separated by a comma"
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
fun String.getId() = ResourceMappingPatch.resourceMappings.single { it.name == this }.id
|
||||
|
||||
adAttributionId = "ad_attribution".getId()
|
||||
reelMultipleItemShelfId = "reel_multiple_items_shelf".getId()
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
package app.revanced.patches.youtube.ad.video.annotations
|
||||
|
||||
import app.revanced.patcher.annotation.Compatibility
|
||||
import app.revanced.patcher.annotation.Package
|
||||
|
||||
@Compatibility(
|
||||
[Package(
|
||||
"com.google.android.youtube", arrayOf("17.49.37")
|
||||
)]
|
||||
)
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
internal annotation class VideoAdsCompatibility
|
||||
|
@ -1,12 +0,0 @@
|
||||
package app.revanced.patches.youtube.ad.video.fingerprints
|
||||
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
|
||||
object LoadVideoAdsFingerprint : MethodFingerprint(
|
||||
strings = listOf(
|
||||
"TriggerBundle doesn't have the required metadata specified by the trigger ",
|
||||
"Tried to enter slot with no assigned slotAdapter",
|
||||
"Trying to enter a slot when a slot of same type and physical position is already active. Its status: ",
|
||||
)
|
||||
)
|
@ -1,58 +0,0 @@
|
||||
package app.revanced.patches.youtube.ad.video.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.addInstructions
|
||||
import app.revanced.patcher.extensions.instruction
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
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.util.smali.ExternalLabel
|
||||
import app.revanced.patches.shared.settings.preference.impl.StringResource
|
||||
import app.revanced.patches.shared.settings.preference.impl.SwitchPreference
|
||||
import app.revanced.patches.youtube.ad.video.annotations.VideoAdsCompatibility
|
||||
import app.revanced.patches.youtube.ad.video.fingerprints.LoadVideoAdsFingerprint
|
||||
import app.revanced.patches.youtube.misc.fix.playback.patch.FixPlaybackPatch
|
||||
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
||||
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
|
||||
|
||||
@Patch
|
||||
@DependsOn([IntegrationsPatch::class, SettingsPatch::class, FixPlaybackPatch::class])
|
||||
@Name("video-ads")
|
||||
@Description("Removes ads in the video player.")
|
||||
@VideoAdsCompatibility
|
||||
@Version("0.0.1")
|
||||
class VideoAdsPatch : BytecodePatch(
|
||||
listOf(
|
||||
LoadVideoAdsFingerprint,
|
||||
)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
SettingsPatch.PreferenceScreen.ADS.addPreferences(
|
||||
SwitchPreference(
|
||||
"revanced_video_ads_removal",
|
||||
StringResource("revanced_video_ads_removal_title", "Hide video ads"),
|
||||
true,
|
||||
StringResource("revanced_video_ads_removal_summary_on", "Video ads are hidden"),
|
||||
StringResource("revanced_video_ads_removal_summary_off", "Video ads are shown")
|
||||
)
|
||||
)
|
||||
|
||||
val loadVideoAdsFingerprintMethod = LoadVideoAdsFingerprint.result!!.mutableMethod
|
||||
|
||||
loadVideoAdsFingerprintMethod.addInstructions(
|
||||
0, """
|
||||
invoke-static { }, Lapp/revanced/integrations/patches/VideoAdsPatch;->shouldShowAds()Z
|
||||
move-result v0
|
||||
if-nez v0, :show_video_ads
|
||||
return-void
|
||||
""", listOf(ExternalLabel("show_video_ads", loadVideoAdsFingerprintMethod.instruction(0)))
|
||||
)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package app.revanced.patches.youtube.misc.litho.filter.fingerprints
|
||||
package app.revanced.patches.youtube.ads.general.bytecode.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.Opcode
|
@ -1,4 +1,4 @@
|
||||
package app.revanced.patches.youtube.misc.litho.filter.fingerprints
|
||||
package app.revanced.patches.youtube.ads.general.bytecode.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.Opcode
|
@ -0,0 +1,99 @@
|
||||
package app.revanced.patches.youtube.ads.general.bytecode.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.addInstruction
|
||||
import app.revanced.patcher.extensions.addInstructions
|
||||
import app.revanced.patcher.extensions.instruction
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultError
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableClass
|
||||
import app.revanced.patcher.util.smali.ExternalLabel
|
||||
import app.revanced.patches.youtube.ads.general.bytecode.fingerprints.ComponentContextParserFingerprint
|
||||
import app.revanced.patches.youtube.ads.general.bytecode.fingerprints.EmptyComponentBuilderFingerprint
|
||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.shared.patches.mapping.ResourceMappingPatch
|
||||
import app.revanced.shared.util.bytecode.BytecodeHelper
|
||||
import app.revanced.shared.util.integrations.Constants.ADS_PATH
|
||||
import org.jf.dexlib2.builder.instruction.BuilderInstruction21s
|
||||
import org.jf.dexlib2.iface.instruction.formats.Instruction31i
|
||||
import org.jf.dexlib2.iface.instruction.Instruction
|
||||
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
|
||||
import org.jf.dexlib2.iface.reference.FieldReference
|
||||
import org.jf.dexlib2.iface.reference.MethodReference
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
@DependsOn([ResourceMappingPatch::class])
|
||||
@Name("hide-general-ads-bytecode-patch")
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class GeneralAdsBytecodePatch : BytecodePatch(
|
||||
listOf(ComponentContextParserFingerprint)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
ComponentContextParserFingerprint.result?.let { result ->
|
||||
val builderMethodIndex = EmptyComponentBuilderFingerprint
|
||||
.also { it.resolve(context, result.mutableMethod, result.mutableClass) }
|
||||
.let { it.result!!.scanResult.patternScanResult!!.startIndex }
|
||||
|
||||
val emptyComponentFieldIndex = builderMethodIndex + 2
|
||||
|
||||
with(result.mutableMethod) {
|
||||
val insertHookIndex = implementation!!.instructions.indexOfFirst {
|
||||
it.opcode == Opcode.CONST_16 &&
|
||||
(it as BuilderInstruction21s).narrowLiteral == 124
|
||||
} + 3
|
||||
|
||||
val stringBuilderRegister = (instruction(insertHookIndex) as OneRegisterInstruction).registerA
|
||||
val clobberedRegister = (instruction(insertHookIndex - 3) as OneRegisterInstruction).registerA
|
||||
|
||||
val bufferIndex = implementation!!.instructions.indexOfFirst {
|
||||
it.opcode == Opcode.CONST &&
|
||||
(it as Instruction31i).narrowLiteral == 183314536
|
||||
} - 1
|
||||
|
||||
val bufferRegister = (instruction(bufferIndex) as OneRegisterInstruction).registerA
|
||||
|
||||
val builderMethodDescriptor = instruction(builderMethodIndex).toDescriptor()
|
||||
val emptyComponentFieldDescriptor = instruction(emptyComponentFieldIndex).toDescriptor()
|
||||
|
||||
addInstructions(
|
||||
insertHookIndex, // right after setting the component.pathBuilder field,
|
||||
"""
|
||||
invoke-static {v$stringBuilderRegister, v$bufferRegister}, $ADS_PATH/LithoFilterPatch;->filter(Ljava/lang/StringBuilder;Ljava/lang/String;)Z
|
||||
move-result v$clobberedRegister
|
||||
if-eqz v$clobberedRegister, :not_an_ad
|
||||
move-object/from16 v$bufferRegister, p1
|
||||
invoke-static {v$bufferRegister}, $builderMethodDescriptor
|
||||
move-result-object v0
|
||||
iget-object v0, v0, $emptyComponentFieldDescriptor
|
||||
return-object v0
|
||||
""",
|
||||
listOf(ExternalLabel("not_an_ad", instruction(insertHookIndex)))
|
||||
)
|
||||
}
|
||||
} ?: return PatchResultError("Could not find the method to hook.")
|
||||
|
||||
BytecodeHelper.patchStatus(context, "GeneralAds")
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
|
||||
private companion object {
|
||||
fun Instruction.toDescriptor() = when (val reference = (this as? ReferenceInstruction)?.reference) {
|
||||
is MethodReference -> "${reference.definingClass}->${reference.name}(${
|
||||
reference.parameterTypes.joinToString(
|
||||
""
|
||||
) { it }
|
||||
})${reference.returnType}"
|
||||
is FieldReference -> "${reference.definingClass}->${reference.name}:${reference.type}"
|
||||
else -> throw PatchResultError("Unsupported reference type")
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
package app.revanced.patches.youtube.ads.general.bytecode.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.shared.extensions.findMutableMethodOf
|
||||
import app.revanced.shared.extensions.injectHideCall
|
||||
import app.revanced.shared.patches.mapping.ResourceMappingPatch
|
||||
import org.jf.dexlib2.iface.instruction.formats.*
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
@Name("hide-general-ads-secondary-bytecode-patch")
|
||||
@DependsOn([ResourceMappingPatch::class])
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class GeneralAdsSecondaryBytecodePatch : BytecodePatch() {
|
||||
private val resourceIds = arrayOf(
|
||||
"ad_attribution",
|
||||
"horizontal_card_list",
|
||||
"album_card"
|
||||
).map { name ->
|
||||
ResourceMappingPatch.resourceMappings.single { it.name == name }.id
|
||||
}
|
||||
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
context.classes.forEach { classDef ->
|
||||
classDef.methods.forEach { method ->
|
||||
with(method.implementation) {
|
||||
this?.instructions?.forEachIndexed { index, instruction ->
|
||||
when (instruction.opcode) {
|
||||
Opcode.CONST -> {
|
||||
when ((instruction as Instruction31i).wideLiteral) {
|
||||
resourceIds[0] -> { // general ads
|
||||
val insertIndex = index + 1
|
||||
val invokeInstruction = instructions.elementAt(insertIndex)
|
||||
if (invokeInstruction.opcode != Opcode.INVOKE_VIRTUAL) return@forEachIndexed
|
||||
|
||||
val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method)
|
||||
|
||||
val viewRegister = (invokeInstruction as Instruction35c).registerC
|
||||
mutableMethod.implementation!!.injectHideCall(insertIndex, viewRegister, "ads/GeneralAdsPatch", "hideAdAttributionView")
|
||||
}
|
||||
|
||||
resourceIds[1] -> { // breaking news
|
||||
val insertIndex = index + 4
|
||||
val invokeInstruction = instructions.elementAt(insertIndex)
|
||||
if (invokeInstruction.opcode != Opcode.CHECK_CAST) return@forEachIndexed
|
||||
|
||||
val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method)
|
||||
|
||||
val viewRegister = (invokeInstruction as Instruction21c).registerA
|
||||
mutableMethod.implementation!!.injectHideCall(insertIndex, viewRegister, "ads/GeneralAdsPatch", "hideBreakingNewsShelf")
|
||||
}
|
||||
|
||||
resourceIds[2] -> { // album cards
|
||||
val insertIndex = index + 4
|
||||
val invokeInstruction = instructions.elementAt(insertIndex)
|
||||
if (invokeInstruction.opcode != Opcode.CHECK_CAST) return@forEachIndexed
|
||||
|
||||
val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method)
|
||||
|
||||
val viewRegister = (invokeInstruction as Instruction21c).registerA
|
||||
mutableMethod.implementation!!.injectHideCall(insertIndex, viewRegister, "ads/GeneralAdsPatch", "hideAlbumCards")
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> return@forEachIndexed
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
package app.revanced.patches.youtube.ads.general.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.ResourceContext
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patches.youtube.ads.general.bytecode.patch.GeneralAdsBytecodePatch
|
||||
import app.revanced.patches.youtube.ads.general.bytecode.patch.GeneralAdsSecondaryBytecodePatch
|
||||
import app.revanced.patches.youtube.misc.litho.filter.patch.LithoFilterPatch
|
||||
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.shared.extensions.doRecursively
|
||||
import app.revanced.shared.extensions.startsWithAny
|
||||
import app.revanced.shared.util.resources.ResourceHelper
|
||||
import org.w3c.dom.Element
|
||||
|
||||
@Patch
|
||||
@Name("hide-general-ads")
|
||||
@Description("Hooks the method which parses the bytes into a ComponentContext to filter components.")
|
||||
@DependsOn(
|
||||
[
|
||||
GeneralAdsBytecodePatch::class,
|
||||
GeneralAdsSecondaryBytecodePatch::class,
|
||||
LithoFilterPatch::class,
|
||||
SettingsPatch::class
|
||||
]
|
||||
)
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class GeneralAdsPatch : ResourcePatch {
|
||||
private val resourceFileNames = arrayOf(
|
||||
"promoted_",
|
||||
"promotion_",
|
||||
"compact_premium_",
|
||||
"compact_promoted_",
|
||||
)
|
||||
|
||||
private val replacements = arrayOf(
|
||||
"height",
|
||||
"width",
|
||||
"marginTop"
|
||||
)
|
||||
|
||||
override fun execute(context: ResourceContext): PatchResult {
|
||||
context.forEach {
|
||||
|
||||
if (!it.name.startsWithAny(*resourceFileNames)) return@forEach
|
||||
|
||||
// for each file in the "layouts" directory replace all necessary attributes content
|
||||
context.xmlEditor[it.absolutePath].use { editor ->
|
||||
editor.file.doRecursively { node ->
|
||||
replacements.forEach replacement@{ replacement ->
|
||||
if (node !is Element) return@replacement
|
||||
|
||||
node.getAttributeNode("android:layout_$replacement")?.let { attribute ->
|
||||
attribute.textContent = "0.0dip"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
add settings
|
||||
*/
|
||||
ResourceHelper.addSettings(
|
||||
context,
|
||||
"PREFERENCE_CATEGORY: REVANCED_SETTINGS",
|
||||
"PREFERENCE: ADS_SETTINGS",
|
||||
"SETTINGS: HIDE_GENERAL_ADS"
|
||||
)
|
||||
|
||||
ResourceHelper.patchSuccess(
|
||||
context,
|
||||
"hide-general-ads"
|
||||
)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package app.revanced.patches.youtube.ads.video.bytecode.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patches.youtube.misc.videoid.mainstream.patch.MainstreamVideoIdPatch
|
||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.shared.patches.videoads.GeneralVideoAdsPatch
|
||||
import app.revanced.shared.util.bytecode.BytecodeHelper
|
||||
import app.revanced.shared.util.integrations.Constants.ADS_PATH
|
||||
|
||||
@DependsOn(
|
||||
[
|
||||
GeneralVideoAdsPatch::class,
|
||||
MainstreamVideoIdPatch::class
|
||||
]
|
||||
)
|
||||
@Name("hide-video-ads-bytecode-patch")
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class VideoAdsBytecodePatch : BytecodePatch() {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
val INTEGRATIONS_CLASS_DESCRIPTOR = "$ADS_PATH/HideVideoAdsPatch;->hideVideoAds()Z"
|
||||
|
||||
GeneralVideoAdsPatch.injectLegacyAds(INTEGRATIONS_CLASS_DESCRIPTOR)
|
||||
|
||||
GeneralVideoAdsPatch.injectMainstreamAds(INTEGRATIONS_CLASS_DESCRIPTOR)
|
||||
|
||||
BytecodeHelper.patchStatus(context, "VideoAds")
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
package app.revanced.patches.youtube.ads.video.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.ResourceContext
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patches.youtube.ads.video.bytecode.patch.VideoAdsBytecodePatch
|
||||
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.shared.util.resources.ResourceHelper
|
||||
|
||||
@Patch
|
||||
@Name("hide-video-ads")
|
||||
@Description("Removes ads in the video player.")
|
||||
@DependsOn(
|
||||
[
|
||||
VideoAdsBytecodePatch::class,
|
||||
SettingsPatch::class
|
||||
]
|
||||
)
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class VideoAdsPatch : ResourcePatch {
|
||||
override fun execute(context: ResourceContext): PatchResult {
|
||||
|
||||
/*
|
||||
add settings
|
||||
*/
|
||||
ResourceHelper.addSettings(
|
||||
context,
|
||||
"PREFERENCE_CATEGORY: REVANCED_SETTINGS",
|
||||
"PREFERENCE: ADS_SETTINGS",
|
||||
"SETTINGS: HIDE_VIDEO_ADS"
|
||||
)
|
||||
|
||||
ResourceHelper.addSettings2(
|
||||
context,
|
||||
"PREFERENCE_CATEGORY: REVANCED_EXTENDED_SETTINGS",
|
||||
"PREFERENCE: EXTENDED_SETTINGS",
|
||||
"SETTINGS: EXPERIMENTAL_FLAGS",
|
||||
"SETTINGS: FIX_VIDEO_PLAYBACK"
|
||||
)
|
||||
|
||||
ResourceHelper.patchSuccess(
|
||||
context,
|
||||
"hide-video-ads"
|
||||
)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package app.revanced.patches.youtube.layout.autoplaybutton.fingerprints
|
||||
package app.revanced.patches.youtube.button.autorepeat.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
@ -1,4 +1,4 @@
|
||||
package app.revanced.patches.youtube.misc.autorepeat.fingerprints
|
||||
package app.revanced.patches.youtube.button.autorepeat.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
@ -1,4 +1,4 @@
|
||||
package app.revanced.patches.youtube.misc.autorepeat.fingerprints
|
||||
package app.revanced.patches.youtube.button.autorepeat.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
@ -0,0 +1,57 @@
|
||||
package app.revanced.patches.youtube.button.autorepeat.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.addInstructions
|
||||
import app.revanced.patcher.extensions.instruction
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.util.smali.ExternalLabel
|
||||
import app.revanced.patches.youtube.button.autorepeat.fingerprints.AutoNavInformerFingerprint
|
||||
import app.revanced.patches.youtube.button.autorepeat.fingerprints.AutoRepeatFingerprint
|
||||
import app.revanced.patches.youtube.button.autorepeat.fingerprints.AutoRepeatParentFingerprint
|
||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.shared.util.integrations.Constants.UTILS_PATH
|
||||
import app.revanced.shared.util.integrations.Constants.VIDEO_PATH
|
||||
|
||||
@Name("always-autorepeat")
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class AutoRepeatPatch : BytecodePatch(
|
||||
listOf(
|
||||
AutoRepeatParentFingerprint,
|
||||
AutoNavInformerFingerprint
|
||||
)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
with(AutoRepeatFingerprint.also {
|
||||
it.resolve(context, AutoRepeatParentFingerprint.result!!.classDef)
|
||||
}.result!!.mutableMethod) {
|
||||
addInstructions(
|
||||
0, """
|
||||
invoke-static {}, $VIDEO_PATH/VideoInformation;->videoEnded()Z
|
||||
move-result v0
|
||||
if-eqz v0, :noautorepeat
|
||||
return-void
|
||||
""", listOf(ExternalLabel("noautorepeat", instruction(0)))
|
||||
)
|
||||
}
|
||||
|
||||
with(AutoNavInformerFingerprint.result!!.mutableMethod) {
|
||||
addInstructions(
|
||||
0, """
|
||||
invoke-static {}, $UTILS_PATH/EnableAutoRepeatPatch;->enableAutoRepeat()Z
|
||||
move-result v0
|
||||
if-eqz v0, :hidden
|
||||
const/4 v0, 0x0
|
||||
return v0
|
||||
""", listOf(ExternalLabel("hidden", instruction(0)))
|
||||
)
|
||||
}
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package app.revanced.patches.youtube.button.overlaybuttons.bytecode.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.data.toMethodWalker
|
||||
import app.revanced.patcher.extensions.addInstruction
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patches.youtube.misc.playercontrols.bytecode.patch.PlayerControlsBytecodePatch
|
||||
import app.revanced.patches.youtube.misc.videoid.mainstream.patch.MainstreamVideoIdPatch
|
||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.shared.util.integrations.Constants.BUTTON_PATH
|
||||
|
||||
@Name("overlay-buttons-bytecode-patch")
|
||||
@DependsOn(
|
||||
dependencies = [
|
||||
PlayerControlsBytecodePatch::class,
|
||||
MainstreamVideoIdPatch::class
|
||||
]
|
||||
)
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class OverlayButtonsBytecodePatch : BytecodePatch() {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
val AutoRepeat = "$BUTTON_PATH/AutoRepeat;"
|
||||
val Copy = "$BUTTON_PATH/Copy;"
|
||||
val CopyWithTimeStamp = "$BUTTON_PATH/CopyWithTimeStamp;"
|
||||
val Download = "$BUTTON_PATH/Download;"
|
||||
val Whitelists = "$BUTTON_PATH/Whitelists;"
|
||||
|
||||
arrayOf(
|
||||
Download,
|
||||
AutoRepeat,
|
||||
CopyWithTimeStamp,
|
||||
Copy,
|
||||
Whitelists
|
||||
).forEach { descriptor ->
|
||||
PlayerControlsBytecodePatch.initializeControl(descriptor)
|
||||
PlayerControlsBytecodePatch.injectVisibility(descriptor)
|
||||
}
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -0,0 +1,122 @@
|
||||
package app.revanced.patches.youtube.button.overlaybuttons.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.ResourceContext
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patches.youtube.button.overlaybuttons.bytecode.patch.OverlayButtonsBytecodePatch
|
||||
import app.revanced.patches.youtube.button.autorepeat.patch.AutoRepeatPatch
|
||||
import app.revanced.patches.youtube.button.whitelist.patch.WhitelistPatch
|
||||
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.shared.patches.options.PatchOptions
|
||||
import app.revanced.shared.util.resources.ResourceHelper
|
||||
import app.revanced.shared.util.resources.ResourceUtils
|
||||
import app.revanced.shared.util.resources.ResourceUtils.copyResources
|
||||
import app.revanced.shared.util.resources.ResourceUtils.copyXmlNode
|
||||
|
||||
@Patch
|
||||
@Name("overlay-buttons")
|
||||
@Description("Add overlay buttons for ReVanced Extended.")
|
||||
@DependsOn(
|
||||
[
|
||||
AutoRepeatPatch::class,
|
||||
OverlayButtonsBytecodePatch::class,
|
||||
PatchOptions::class,
|
||||
SettingsPatch::class,
|
||||
WhitelistPatch::class
|
||||
]
|
||||
)
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class OverlayButtonsResourcePatch : ResourcePatch {
|
||||
override fun execute(context: ResourceContext): PatchResult {
|
||||
|
||||
var icon = PatchOptions.Overlay_Buttons_Icon
|
||||
|
||||
/*
|
||||
* Copy resources
|
||||
*/
|
||||
arrayOf(
|
||||
ResourceUtils.ResourceGroup(
|
||||
"drawable",
|
||||
"playlist_repeat_button.xml",
|
||||
"playlist_shuffle_button.xml",
|
||||
"revanced_repeat_icon.xml"
|
||||
)
|
||||
).forEach { resourceGroup ->
|
||||
context.copyResources("youtube/overlaybuttons", resourceGroup)
|
||||
}
|
||||
|
||||
arrayOf(
|
||||
ResourceUtils.ResourceGroup(
|
||||
"drawable-xxhdpi",
|
||||
"ic_fullscreen_vertical_button.png",
|
||||
"ic_vr.png",
|
||||
"quantum_ic_fullscreen_exit_grey600_24.png",
|
||||
"quantum_ic_fullscreen_exit_white_24.png",
|
||||
"quantum_ic_fullscreen_grey600_24.png",
|
||||
"quantum_ic_fullscreen_white_24.png",
|
||||
"revanced_copy_icon.png",
|
||||
"revanced_copy_icon_with_time.png",
|
||||
"revanced_download_icon.png",
|
||||
"revanced_whitelist_icon.png",
|
||||
"yt_outline_arrow_repeat_1_white_24.png",
|
||||
"yt_outline_arrow_shuffle_1_white_24.png",
|
||||
"yt_outline_screen_full_exit_white_24.png",
|
||||
"yt_outline_screen_full_white_24.png"
|
||||
)
|
||||
).forEach { resourceGroup ->
|
||||
context.copyResources("youtube/overlaybuttons/$icon", resourceGroup)
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy preference fragments
|
||||
*/
|
||||
|
||||
context.copyXmlNode("youtube/overlaybuttons/host", "layout/youtube_controls_bottom_ui_container.xml", "android.support.constraint.ConstraintLayout")
|
||||
|
||||
val container = context["res/layout/youtube_controls_bottom_ui_container.xml"]
|
||||
container.writeText(
|
||||
container.readText()
|
||||
.replace(
|
||||
"yt:layout_constraintRight_toLeftOf=\"@id/fullscreen_button",
|
||||
"yt:layout_constraintRight_toLeftOf=\"@+id/whitelist_button"
|
||||
).replace(
|
||||
"60",
|
||||
"48"
|
||||
).replace(
|
||||
"paddingBottom=\"16",
|
||||
"paddingBottom=\"28"
|
||||
).replace(
|
||||
"paddingLeft=\"12",
|
||||
"paddingLeft=\"0"
|
||||
).replace(
|
||||
"paddingRight=\"12",
|
||||
"paddingRight=\"0"
|
||||
)
|
||||
)
|
||||
|
||||
/*
|
||||
add settings
|
||||
*/
|
||||
ResourceHelper.addSettings(
|
||||
context,
|
||||
"PREFERENCE_CATEGORY: REVANCED_EXTENDED_SETTINGS",
|
||||
"PREFERENCE: OVERLAY_BUTTONS",
|
||||
"SETTINGS: OVERLAY_BUTTONS"
|
||||
)
|
||||
|
||||
ResourceHelper.patchSuccess(
|
||||
context,
|
||||
"overlay-buttons"
|
||||
)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package app.revanced.patches.youtube.button.whitelist.fingerprint
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
|
||||
object PlayerResponseModelFingerprint : MethodFingerprint(
|
||||
returnType = "Z",
|
||||
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = listOf("J", "L"),
|
||||
strings = listOf(
|
||||
"Attempting to seek during an ad",
|
||||
"currentPositionMs.",
|
||||
)
|
||||
)
|
||||
|
@ -0,0 +1,14 @@
|
||||
package app.revanced.patches.youtube.button.whitelist.fingerprint
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
|
||||
object PlayerResponseModelParentFingerprint : MethodFingerprint(
|
||||
"V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L"),
|
||||
strings = listOf(
|
||||
"setMetadata may only be called once",
|
||||
"Person",
|
||||
)
|
||||
)
|
||||
|
@ -0,0 +1,23 @@
|
||||
package app.revanced.patches.youtube.button.whitelist.fingerprint
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
object PrimaryInjectFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = listOf(),
|
||||
opcodes = listOf(
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.RETURN_VOID,
|
||||
Opcode.IGET_OBJECT
|
||||
),
|
||||
strings = listOf(
|
||||
"play() called when the player wasn\'t loaded.",
|
||||
)
|
||||
)
|
||||
|
@ -0,0 +1,26 @@
|
||||
package app.revanced.patches.youtube.button.whitelist.fingerprint
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
object SecondaryInjectFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = listOf("L"),
|
||||
opcodes = listOf(
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.GOTO,
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.IGET_OBJECT
|
||||
)
|
||||
)
|
||||
|
@ -0,0 +1,109 @@
|
||||
package app.revanced.patches.youtube.button.whitelist.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.addInstruction
|
||||
import app.revanced.patcher.extensions.MethodFingerprintExtensions.name
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultError
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
|
||||
import app.revanced.patcher.util.smali.toInstructions
|
||||
import app.revanced.patches.youtube.button.whitelist.fingerprint.*
|
||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.shared.util.integrations.Constants.VIDEO_PATH
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.builder.instruction.BuilderInstruction21c
|
||||
import org.jf.dexlib2.dexbacked.reference.DexBackedMethodReference
|
||||
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
|
||||
import org.jf.dexlib2.iface.reference.FieldReference
|
||||
import org.jf.dexlib2.iface.reference.MethodReference
|
||||
import org.jf.dexlib2.immutable.ImmutableMethod
|
||||
import org.jf.dexlib2.immutable.ImmutableMethodImplementation
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
@Name("channel-whitelist")
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class WhitelistPatch : BytecodePatch(
|
||||
listOf(
|
||||
PlayerResponseModelFingerprint,
|
||||
PlayerResponseModelParentFingerprint,
|
||||
PrimaryInjectFingerprint,
|
||||
SecondaryInjectFingerprint
|
||||
)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
val PlayerResponseModelParentResult = PlayerResponseModelParentFingerprint.result!!
|
||||
val PlayerResponseModelParentInstructions = PlayerResponseModelParentResult.mutableMethod.implementation!!.instructions
|
||||
|
||||
val injectIndex = PlayerResponseModelParentInstructions.indexOfFirst {
|
||||
it.opcode == Opcode.CONST_STRING &&
|
||||
(it as BuilderInstruction21c).reference.toString() == "Person"
|
||||
} + 2
|
||||
|
||||
val PlayerResponseModelReference =
|
||||
PlayerResponseModelParentResult.method.let { method ->
|
||||
(method.implementation!!.instructions.elementAt(injectIndex) as ReferenceInstruction).reference as DexBackedMethodReference
|
||||
}
|
||||
|
||||
val PlayerResponseModelResult = PlayerResponseModelFingerprint.result!!
|
||||
|
||||
val PrimaryReference =
|
||||
PlayerResponseModelResult.method.let { method ->
|
||||
(method.implementation!!.instructions.elementAt(2) as ReferenceInstruction).reference as FieldReference
|
||||
}
|
||||
val SecondaryReference =
|
||||
PlayerResponseModelResult.method.let { method ->
|
||||
(method.implementation!!.instructions.elementAt(3) as ReferenceInstruction).reference as FieldReference
|
||||
}
|
||||
val TertiaryReference =
|
||||
PlayerResponseModelResult.method.let { method ->
|
||||
(method.implementation!!.instructions.elementAt(4) as ReferenceInstruction).reference as MethodReference
|
||||
}
|
||||
|
||||
val classDef = PlayerResponseModelResult.mutableClass
|
||||
classDef.methods.add(
|
||||
ImmutableMethod(
|
||||
classDef.type,
|
||||
"setCurrentVideoInformation",
|
||||
listOf(),
|
||||
"V",
|
||||
AccessFlags.PRIVATE or AccessFlags.FINAL,
|
||||
null,
|
||||
null,
|
||||
ImmutableMethodImplementation(
|
||||
2, """
|
||||
iget-object v0, v1, ${PlayerResponseModelResult.classDef.type}->${PrimaryReference.name}:${PrimaryReference.type}
|
||||
iget-object v0, v0, ${PrimaryReference.type}->${SecondaryReference.name}:${SecondaryReference.type}
|
||||
invoke-interface {v0}, $TertiaryReference
|
||||
move-result-object v0
|
||||
invoke-interface {v0}, $PlayerResponseModelReference
|
||||
move-result-object v0
|
||||
invoke-static {v0}, $VIDEO_PATH/VideoInformation;->setChannelName(Ljava/lang/String;)V
|
||||
return-void
|
||||
""".toInstructions(), null, null
|
||||
)
|
||||
).toMutable()
|
||||
)
|
||||
|
||||
|
||||
listOf(
|
||||
PrimaryInjectFingerprint,
|
||||
SecondaryInjectFingerprint
|
||||
).forEach { fingerprint ->
|
||||
val result = fingerprint.result ?: return PatchResultError("${fingerprint.name} not found")
|
||||
val method = result.mutableMethod
|
||||
val index = result.scanResult.patternScanResult!!.endIndex + 1
|
||||
method.addInstruction(
|
||||
index,
|
||||
"invoke-direct {p0}, ${PlayerResponseModelResult.classDef.type}->setCurrentVideoInformation()V"
|
||||
)
|
||||
}
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package app.revanced.patches.youtube.extended.layoutswitch.bytecode.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
object LayoutSwitchFingerprint : MethodFingerprint(
|
||||
"I", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L"), listOf(
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.CONST_4,
|
||||
Opcode.RETURN,
|
||||
Opcode.CONST_16,
|
||||
Opcode.IF_GE,
|
||||
Opcode.CONST_4,
|
||||
Opcode.RETURN,
|
||||
Opcode.CONST_16,
|
||||
Opcode.IF_GE,
|
||||
Opcode.CONST_4,
|
||||
Opcode.RETURN,
|
||||
Opcode.CONST_16,
|
||||
Opcode.IF_GE,
|
||||
Opcode.CONST_4,
|
||||
Opcode.RETURN,
|
||||
Opcode.CONST_4,
|
||||
Opcode.RETURN
|
||||
)
|
||||
)
|
@ -0,0 +1,33 @@
|
||||
package app.revanced.patches.youtube.extended.layoutswitch.bytecode.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.addInstructions
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patches.youtube.extended.layoutswitch.bytecode.fingerprints.LayoutSwitchFingerprint
|
||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.shared.util.integrations.Constants.EXTENDED_PATH
|
||||
|
||||
@Name("layout-switch-bytecode-patch")
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class LayoutSwitchBytecodePatch : BytecodePatch(
|
||||
listOf(
|
||||
LayoutSwitchFingerprint
|
||||
)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
|
||||
LayoutSwitchFingerprint.result!!.mutableMethod.addInstructions(
|
||||
4, """
|
||||
invoke-static {p0}, $EXTENDED_PATH/LayoutOverridePatch;->getLayoutOverride(I)I
|
||||
move-result p0
|
||||
"""
|
||||
)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package app.revanced.patches.youtube.extended.layoutswitch.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.ResourceContext
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patches.youtube.extended.layoutswitch.bytecode.patch.LayoutSwitchBytecodePatch
|
||||
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.shared.util.resources.ResourceHelper
|
||||
|
||||
@Patch
|
||||
@Name("layout-switch")
|
||||
@Description("Tricks the dpi to use some tablet/phone layouts.")
|
||||
@DependsOn(
|
||||
[
|
||||
LayoutSwitchBytecodePatch::class,
|
||||
SettingsPatch::class
|
||||
]
|
||||
)
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class LayoutSwitchPatch : ResourcePatch {
|
||||
override fun execute(context: ResourceContext): PatchResult {
|
||||
|
||||
/*
|
||||
add settings
|
||||
*/
|
||||
ResourceHelper.addSettings2(
|
||||
context,
|
||||
"PREFERENCE_CATEGORY: REVANCED_EXTENDED_SETTINGS",
|
||||
"PREFERENCE: EXTENDED_SETTINGS",
|
||||
"SETTINGS: EXPERIMENTAL_FLAGS",
|
||||
"SETTINGS: LAYOUT_SWITCH"
|
||||
)
|
||||
|
||||
ResourceHelper.patchSuccess(
|
||||
context,
|
||||
"layout-switch"
|
||||
)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package app.revanced.patches.youtube.extended.oldlayout.bytecode.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
object OldLayoutFingerprint : MethodFingerprint(
|
||||
"L", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L"), listOf(
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.GOTO,
|
||||
Opcode.CONST_STRING,
|
||||
),
|
||||
strings = listOf("Unset")
|
||||
)
|
@ -0,0 +1,42 @@
|
||||
package app.revanced.patches.youtube.extended.oldlayout.bytecode.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.addInstructions
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultError
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patches.youtube.extended.oldlayout.bytecode.fingerprints.OldLayoutFingerprint
|
||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.shared.util.integrations.Constants.EXTENDED_PATH
|
||||
import app.revanced.shared.util.integrations.Constants.UTILS_PATH
|
||||
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
|
||||
@Name("enable-old-layout-bytecode-patch")
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class OldLayoutBytecodePatch : BytecodePatch(
|
||||
listOf(
|
||||
OldLayoutFingerprint
|
||||
)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
|
||||
val result = OldLayoutFingerprint.result!!
|
||||
val method = result.mutableMethod
|
||||
val index = result.scanResult.patternScanResult!!.startIndex
|
||||
val register = (method.implementation!!.instructions[index] as OneRegisterInstruction).registerA
|
||||
|
||||
method.addInstructions(
|
||||
index + 1, """
|
||||
invoke-static {v$register}, $EXTENDED_PATH/VersionOverridePatch;->getVersionOverride(Ljava/lang/String;)Ljava/lang/String;
|
||||
move-result-object v$register
|
||||
"""
|
||||
)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package app.revanced.patches.youtube.extended.oldlayout.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.ResourceContext
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patches.youtube.extended.oldlayout.bytecode.patch.OldLayoutBytecodePatch
|
||||
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.shared.util.resources.ResourceHelper
|
||||
|
||||
@Patch
|
||||
@Name("enable-old-layout")
|
||||
@Description("Spoof the YouTube client version to use the old layout.")
|
||||
@DependsOn(
|
||||
[
|
||||
OldLayoutBytecodePatch::class,
|
||||
SettingsPatch::class
|
||||
]
|
||||
)
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class OldLayoutPatch : ResourcePatch {
|
||||
override fun execute(context: ResourceContext): PatchResult {
|
||||
|
||||
/*
|
||||
add settings
|
||||
*/
|
||||
ResourceHelper.addSettings2(
|
||||
context,
|
||||
"PREFERENCE_CATEGORY: REVANCED_EXTENDED_SETTINGS",
|
||||
"PREFERENCE: EXTENDED_SETTINGS",
|
||||
"SETTINGS: EXPERIMENTAL_FLAGS",
|
||||
"SETTINGS: ENABLE_OLD_LAYOUT"
|
||||
)
|
||||
|
||||
ResourceHelper.patchSuccess(
|
||||
context,
|
||||
"enable-old-layout"
|
||||
)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
package app.revanced.patches.youtube.interaction.downloads.annotation
|
||||
|
||||
import app.revanced.patcher.annotation.Compatibility
|
||||
import app.revanced.patcher.annotation.Package
|
||||
|
||||
@Compatibility(
|
||||
[Package(
|
||||
"com.google.android.youtube", arrayOf("17.49.37")
|
||||
)]
|
||||
)
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
internal annotation class DownloadsCompatibility
|
||||
|
@ -1,52 +0,0 @@
|
||||
package app.revanced.patches.youtube.interaction.downloads.bytecode.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
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.patches.youtube.interaction.downloads.annotation.DownloadsCompatibility
|
||||
import app.revanced.patches.youtube.interaction.downloads.resource.patch.DownloadsResourcePatch
|
||||
import app.revanced.patches.youtube.misc.playercontrols.bytecode.patch.PlayerControlsBytecodePatch
|
||||
import app.revanced.patches.youtube.misc.video.videoid.patch.VideoIdPatch
|
||||
|
||||
@Patch
|
||||
@Name("downloads")
|
||||
@DependsOn([DownloadsResourcePatch::class, PlayerControlsBytecodePatch::class, VideoIdPatch::class])
|
||||
@Description("Enables downloading music and videos from YouTube.")
|
||||
@DownloadsCompatibility
|
||||
@Version("0.0.1")
|
||||
class DownloadsBytecodePatch : BytecodePatch() {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
val integrationsPackage = "app/revanced/integrations"
|
||||
val classDescriptor = "L$integrationsPackage/videoplayer/DownloadButton;"
|
||||
|
||||
/*
|
||||
initialize the control
|
||||
*/
|
||||
|
||||
val initializeDownloadsDescriptor = "$classDescriptor->initializeDownloadButton(Ljava/lang/Object;)V"
|
||||
PlayerControlsBytecodePatch.initializeControl(initializeDownloadsDescriptor)
|
||||
|
||||
/*
|
||||
add code to change the visibility of the control
|
||||
*/
|
||||
|
||||
val changeVisibilityDescriptor = "$classDescriptor->changeVisibility(Z)V"
|
||||
PlayerControlsBytecodePatch.injectVisibilityCheckCall(changeVisibilityDescriptor)
|
||||
|
||||
/*
|
||||
add code to change to update the video id
|
||||
*/
|
||||
|
||||
val setVideoIdDescriptor =
|
||||
"L$integrationsPackage/patches/downloads/DownloadsPatch;->setVideoId(Ljava/lang/String;)V"
|
||||
VideoIdPatch.injectCall(setVideoIdDescriptor)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -1,72 +0,0 @@
|
||||
package app.revanced.patches.youtube.interaction.downloads.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.ResourceContext
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patches.shared.settings.preference.impl.*
|
||||
import app.revanced.patches.youtube.interaction.downloads.annotation.DownloadsCompatibility
|
||||
import app.revanced.patches.youtube.misc.manifest.patch.FixLocaleConfigErrorPatch
|
||||
import app.revanced.patches.youtube.misc.playercontrols.resource.patch.BottomControlsResourcePatch
|
||||
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
|
||||
import app.revanced.util.resources.ResourceUtils
|
||||
import app.revanced.util.resources.ResourceUtils.copyResources
|
||||
import app.revanced.util.resources.ResourceUtils.mergeStrings
|
||||
|
||||
@Name("downloads-resource-patch")
|
||||
@DependsOn([BottomControlsResourcePatch::class, FixLocaleConfigErrorPatch::class, SettingsPatch::class])
|
||||
@Description("Makes necessary changes to resources for the download button.")
|
||||
@DownloadsCompatibility
|
||||
@Version("0.0.1")
|
||||
class DownloadsResourcePatch : ResourcePatch {
|
||||
override fun execute(context: ResourceContext): PatchResult {
|
||||
SettingsPatch.PreferenceScreen.INTERACTIONS.addPreferences(
|
||||
PreferenceScreen(
|
||||
"revanced_downloads",
|
||||
StringResource("revanced_downloads_title", "Download settings"),
|
||||
listOf(
|
||||
SwitchPreference(
|
||||
"revanced_downloads",
|
||||
StringResource("revanced_downloads_enabled_title", "Show download button"),
|
||||
true,
|
||||
StringResource("revanced_downloads_enabled_summary_on", "Download button is shown"),
|
||||
StringResource("revanced_downloads_enabled_summary_off", "Download button is not shown")
|
||||
),
|
||||
TextPreference(
|
||||
"revanced_downloads_package_name",
|
||||
StringResource("revanced_downloads_package_name_title", "Downloader package name"),
|
||||
InputType.STRING,
|
||||
"org.schabi.newpipe" /* NewPipe */,
|
||||
StringResource("revanced_downloads_package_name_summary", "Package name of the downloader app such as NewPipe\\'s or PowerTube\\'s")
|
||||
)
|
||||
),
|
||||
StringResource("revanced_downloads_summary", "Settings related to downloads")
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
/*
|
||||
* Copy strings
|
||||
*/
|
||||
|
||||
context.mergeStrings("downloads/host/values/strings.xml")
|
||||
|
||||
/*
|
||||
* Copy resources
|
||||
*/
|
||||
|
||||
context.copyResources("downloads", ResourceUtils.ResourceGroup("drawable", "revanced_yt_download_button.xml"))
|
||||
|
||||
/*
|
||||
* Add download button node
|
||||
*/
|
||||
|
||||
BottomControlsResourcePatch.addControls("downloads/host/layout/${BottomControlsResourcePatch.TARGET_RESOURCE_NAME}")
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
package app.revanced.patches.youtube.interaction.seekbar.annotation
|
||||
|
||||
import app.revanced.patcher.annotation.Compatibility
|
||||
import app.revanced.patcher.annotation.Package
|
||||
|
||||
@Compatibility(
|
||||
[Package(
|
||||
"com.google.android.youtube", arrayOf("17.49.37")
|
||||
)]
|
||||
)
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
internal annotation class SeekbarTappingCompatibility
|
||||
|
@ -1,13 +0,0 @@
|
||||
package app.revanced.patches.youtube.interaction.swipecontrols.annotation
|
||||
|
||||
import app.revanced.patcher.annotation.Compatibility
|
||||
import app.revanced.patcher.annotation.Package
|
||||
|
||||
@Compatibility(
|
||||
[Package(
|
||||
"com.google.android.youtube", arrayOf("17.49.37")
|
||||
)]
|
||||
)
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
internal annotation class SwipeControlsCompatibility
|
@ -1,111 +0,0 @@
|
||||
package app.revanced.patches.youtube.interaction.swipecontrols.patch.resource
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patches.shared.settings.preference.impl.PreferenceScreen
|
||||
import app.revanced.patches.shared.settings.preference.impl.StringResource
|
||||
import app.revanced.patches.shared.settings.preference.impl.SwitchPreference
|
||||
import app.revanced.patches.shared.settings.preference.impl.TextPreference
|
||||
import app.revanced.patches.shared.settings.preference.impl.InputType
|
||||
import app.revanced.patches.youtube.interaction.swipecontrols.annotation.SwipeControlsCompatibility
|
||||
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
|
||||
import app.revanced.util.resources.ResourceUtils
|
||||
import app.revanced.util.resources.ResourceUtils.copyResources
|
||||
|
||||
@Name("swipe-controls-resource-patch")
|
||||
@DependsOn([SettingsPatch::class])
|
||||
@SwipeControlsCompatibility
|
||||
@Version("0.0.1")
|
||||
class SwipeControlsResourcePatch : ResourcePatch {
|
||||
override fun execute(context: ResourceContext): 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")
|
||||
)
|
||||
)
|
||||
|
||||
context.copyResources(
|
||||
"swipecontrols",
|
||||
ResourceUtils.ResourceGroup(
|
||||
"drawable",
|
||||
"ic_sc_brightness_auto.xml",
|
||||
"ic_sc_brightness_manual.xml",
|
||||
"ic_sc_volume_mute.xml",
|
||||
"ic_sc_volume_normal.xml"
|
||||
)
|
||||
)
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
package app.revanced.patches.youtube.layout.autocaptions.annotations
|
||||
|
||||
import app.revanced.patcher.annotation.Compatibility
|
||||
import app.revanced.patcher.annotation.Package
|
||||
|
||||
@Compatibility(
|
||||
[Package(
|
||||
"com.google.android.youtube", arrayOf("17.49.37")
|
||||
)]
|
||||
)
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
internal annotation class AutoCaptionsCompatibility
|
@ -1,20 +0,0 @@
|
||||
package app.revanced.patches.youtube.layout.autocaptions.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
object SubtitleButtonControllerFingerprint : MethodFingerprint(
|
||||
"V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L"), listOf(
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.RETURN_VOID,
|
||||
Opcode.IGET_BOOLEAN,
|
||||
Opcode.CONST_4,
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.CONST,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.IGET_OBJECT,
|
||||
)
|
||||
)
|
@ -1,80 +0,0 @@
|
||||
package app.revanced.patches.youtube.layout.autocaptions.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.addInstructions
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
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.patches.youtube.layout.autocaptions.annotations.AutoCaptionsCompatibility
|
||||
import app.revanced.patches.youtube.layout.autocaptions.fingerprints.StartVideoInformerFingerprint
|
||||
import app.revanced.patches.youtube.layout.autocaptions.fingerprints.SubtitleButtonControllerFingerprint
|
||||
import app.revanced.patches.youtube.layout.autocaptions.fingerprints.SubtitleTrackFingerprint
|
||||
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
||||
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
|
||||
import app.revanced.patches.shared.settings.preference.impl.StringResource
|
||||
import app.revanced.patches.shared.settings.preference.impl.SwitchPreference
|
||||
|
||||
@Patch
|
||||
@DependsOn([IntegrationsPatch::class, SettingsPatch::class])
|
||||
@Name("disable-auto-captions")
|
||||
@Description("Disable forced captions from being automatically enabled.")
|
||||
@AutoCaptionsCompatibility
|
||||
@Version("0.0.1")
|
||||
class AutoCaptionsPatch : BytecodePatch(
|
||||
listOf(
|
||||
StartVideoInformerFingerprint, SubtitleButtonControllerFingerprint, SubtitleTrackFingerprint
|
||||
)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(
|
||||
SwitchPreference(
|
||||
"revanced_autocaptions_enabled",
|
||||
StringResource("revanced_autocaptions_enabled_title", "Disable auto-captions"),
|
||||
false,
|
||||
StringResource("revanced_autocaptions_summary_on", "Auto-captions are disabled"),
|
||||
StringResource("revanced_autocaptions_summary_off", "Auto-captions are enabled")
|
||||
)
|
||||
)
|
||||
|
||||
val startVideoInformerMethod = StartVideoInformerFingerprint.result!!.mutableMethod
|
||||
|
||||
startVideoInformerMethod.addInstructions(
|
||||
0, """
|
||||
const/4 v0, 0x0
|
||||
sput-boolean v0, Lapp/revanced/integrations/patches/DisableAutoCaptionsPatch;->captionsButtonDisabled:Z
|
||||
"""
|
||||
)
|
||||
|
||||
val subtitleButtonControllerMethod = SubtitleButtonControllerFingerprint.result!!.mutableMethod
|
||||
|
||||
subtitleButtonControllerMethod.addInstructions(
|
||||
0, """
|
||||
const/4 v0, 0x1
|
||||
sput-boolean v0, Lapp/revanced/integrations/patches/DisableAutoCaptionsPatch;->captionsButtonDisabled:Z
|
||||
"""
|
||||
)
|
||||
|
||||
val subtitleTrackMethod = SubtitleTrackFingerprint.result!!.mutableMethod
|
||||
|
||||
subtitleTrackMethod.addInstructions(
|
||||
0, """
|
||||
invoke-static {}, Lapp/revanced/integrations/patches/DisableAutoCaptionsPatch;->autoCaptionsEnabled()Z
|
||||
move-result v0
|
||||
if-eqz v0, :auto_captions_enabled
|
||||
sget-boolean v0, Lapp/revanced/integrations/patches/DisableAutoCaptionsPatch;->captionsButtonDisabled:Z
|
||||
if-nez v0, :auto_captions_enabled
|
||||
const/4 v0, 0x1
|
||||
return v0
|
||||
:auto_captions_enabled
|
||||
nop
|
||||
"""
|
||||
)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
package app.revanced.patches.youtube.layout.autoplaybutton.annotations
|
||||
|
||||
import app.revanced.patcher.annotation.Compatibility
|
||||
import app.revanced.patcher.annotation.Package
|
||||
|
||||
@Compatibility(
|
||||
[Package(
|
||||
"com.google.android.youtube", arrayOf("17.49.37")
|
||||
)]
|
||||
)
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
internal annotation class AutoplayButtonCompatibility
|
@ -1,92 +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.BytecodeContext
|
||||
import app.revanced.patcher.extensions.addInstructions
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
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.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.shared.mapping.misc.patch.ResourceMappingPatch
|
||||
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
|
||||
import app.revanced.patches.shared.settings.preference.impl.StringResource
|
||||
import app.revanced.patches.shared.settings.preference.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, ResourceMappingPatch::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(context: BytecodeContext): PatchResult {
|
||||
SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(
|
||||
SwitchPreference(
|
||||
"revanced_hide_autoplay_button",
|
||||
StringResource("revanced_hide_autoplay_button_title", "Hide autoplay button"),
|
||||
true,
|
||||
StringResource("revanced_hide_autoplay_button_summary_on", "Autoplay button is hidden"),
|
||||
StringResource("revanced_hide_autoplay_button_summary_off", "Autoplay button is shown")
|
||||
)
|
||||
)
|
||||
|
||||
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 = ResourceMappingPatch.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()
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
package app.revanced.patches.youtube.layout.branding.header.annotations
|
||||
|
||||
import app.revanced.patcher.annotation.Compatibility
|
||||
import app.revanced.patcher.annotation.Package
|
||||
|
||||
@Compatibility([Package("com.google.android.youtube")])
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
internal annotation class PremiumHeadingCompatibility
|
@ -1,9 +0,0 @@
|
||||
package app.revanced.patches.youtube.layout.branding.icon.annotations
|
||||
|
||||
import app.revanced.patcher.annotation.Compatibility
|
||||
import app.revanced.patcher.annotation.Package
|
||||
|
||||
@Compatibility([Package("com.google.android.youtube")])
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
internal annotation class CustomBrandingCompatibility
|
@ -1,94 +0,0 @@
|
||||
package app.revanced.patches.youtube.layout.branding.icon.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patcher.patch.*
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patches.youtube.layout.branding.icon.annotations.CustomBrandingCompatibility
|
||||
import app.revanced.patches.youtube.misc.manifest.patch.FixLocaleConfigErrorPatch
|
||||
import app.revanced.util.resources.ResourceUtils
|
||||
import app.revanced.util.resources.ResourceUtils.copyResources
|
||||
import java.io.File
|
||||
import java.nio.file.Files
|
||||
|
||||
@Patch
|
||||
@DependsOn([FixLocaleConfigErrorPatch::class])
|
||||
@Name("custom-branding")
|
||||
@Description("Changes the YouTube launcher icon and name to your choice (defaults to ReVanced).")
|
||||
@CustomBrandingCompatibility
|
||||
@Version("0.0.1")
|
||||
class CustomBrandingPatch : ResourcePatch {
|
||||
override fun execute(context: ResourceContext): PatchResult {
|
||||
fun copyResources(resourceGroups: List<ResourceUtils.ResourceGroup>) {
|
||||
iconPath?.let { iconPathString ->
|
||||
val iconPath = File(iconPathString)
|
||||
val resourceDirectory = context["res"]
|
||||
|
||||
resourceGroups.forEach { group ->
|
||||
val fromDirectory = iconPath.resolve(group.resourceDirectoryName)
|
||||
val toDirectory = resourceDirectory.resolve(group.resourceDirectoryName)
|
||||
|
||||
group.resources.forEach { iconFileName ->
|
||||
Files.write(
|
||||
toDirectory.resolve(iconFileName).toPath(),
|
||||
fromDirectory.resolve(iconFileName).readBytes()
|
||||
)
|
||||
}
|
||||
}
|
||||
} ?: resourceGroups.forEach { context.copyResources("branding", it) }
|
||||
}
|
||||
|
||||
val iconResourceFileNames = arrayOf(
|
||||
"adaptiveproduct_youtube_background_color_108",
|
||||
"adaptiveproduct_youtube_foreground_color_108",
|
||||
"ic_launcher",
|
||||
"ic_launcher_round"
|
||||
).map { "$it.png" }.toTypedArray()
|
||||
|
||||
fun createGroup(directory: String) = ResourceUtils.ResourceGroup(
|
||||
directory, *iconResourceFileNames
|
||||
)
|
||||
|
||||
// change the app icon
|
||||
arrayOf("xxxhdpi", "xxhdpi", "xhdpi", "hdpi", "mdpi")
|
||||
.map { "mipmap-$it" }
|
||||
.map(::createGroup)
|
||||
.let(::copyResources)
|
||||
|
||||
// change the name of the app
|
||||
val manifest = context["AndroidManifest.xml"]
|
||||
manifest.writeText(
|
||||
manifest.readText()
|
||||
.replace(
|
||||
"android:label=\"@string/application_name",
|
||||
"android:label=\"$appName"
|
||||
)
|
||||
)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
|
||||
companion object : OptionsContainer() {
|
||||
private var appName: String? by option(
|
||||
PatchOption.StringOption(
|
||||
key = "appName",
|
||||
default = "YouTube ReVanced",
|
||||
title = "Application Name",
|
||||
description = "The name of the application it will show on your home screen.",
|
||||
required = true
|
||||
)
|
||||
)
|
||||
|
||||
private var iconPath: String? by option(
|
||||
PatchOption.StringOption(
|
||||
key = "iconPath",
|
||||
default = null,
|
||||
title = "App Icon Path",
|
||||
description = "A path containing mipmap resource folders with icons."
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package app.revanced.patches.youtube.layout.buttomplayer.buttoncontainer.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patches.youtube.misc.litho.filter.patch.LithoFilterPatch
|
||||
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.shared.util.resources.ResourceHelper
|
||||
|
||||
@Patch
|
||||
@Name("hide-button-container")
|
||||
@Description("Adds options to hide action buttons under a video.")
|
||||
@DependsOn(
|
||||
[
|
||||
LithoFilterPatch::class,
|
||||
SettingsPatch::class
|
||||
]
|
||||
)
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class ButtonContainerPatch : ResourcePatch {
|
||||
override fun execute(context: ResourceContext): PatchResult {
|
||||
|
||||
/*
|
||||
add settings
|
||||
*/
|
||||
ResourceHelper.addSettings2(
|
||||
context,
|
||||
"PREFERENCE_CATEGORY: REVANCED_SETTINGS",
|
||||
"PREFERENCE: LAYOUT_SETTINGS",
|
||||
"PREFERENCE_HEADER: BOTTOM_PLAYER",
|
||||
"SETTINGS: BUTTON_CONTAINER"
|
||||
)
|
||||
|
||||
ResourceHelper.patchSuccess(
|
||||
context,
|
||||
"hide-button-container"
|
||||
)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package app.revanced.patches.youtube.layout.buttomplayer.comment.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patches.youtube.ads.general.bytecode.patch.GeneralAdsBytecodePatch
|
||||
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.shared.util.resources.ResourceHelper
|
||||
|
||||
@Patch
|
||||
@Name("hide-comment-component")
|
||||
@Description("Adds options to hide comment component under a video.")
|
||||
@DependsOn(
|
||||
[
|
||||
GeneralAdsBytecodePatch::class,
|
||||
SettingsPatch::class
|
||||
]
|
||||
)
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class CommentComponentPatch : ResourcePatch {
|
||||
override fun execute(context: ResourceContext): PatchResult {
|
||||
|
||||
/*
|
||||
add settings
|
||||
*/
|
||||
ResourceHelper.addSettings2(
|
||||
context,
|
||||
"PREFERENCE_CATEGORY: REVANCED_SETTINGS",
|
||||
"PREFERENCE: LAYOUT_SETTINGS",
|
||||
"PREFERENCE_HEADER: BOTTOM_PLAYER",
|
||||
"SETTINGS: COMMENT_COMPONENT"
|
||||
)
|
||||
|
||||
ResourceHelper.patchSuccess(
|
||||
context,
|
||||
"hide-comment-component"
|
||||
)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
package app.revanced.patches.youtube.layout.buttons.annotations
|
||||
|
||||
import app.revanced.patcher.annotation.Compatibility
|
||||
import app.revanced.patcher.annotation.Package
|
||||
|
||||
@Compatibility(
|
||||
[Package(
|
||||
"com.google.android.youtube", arrayOf("17.49.37")
|
||||
)]
|
||||
)
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
internal annotation class HideButtonsCompatibility
|
@ -1,81 +0,0 @@
|
||||
package app.revanced.patches.youtube.layout.buttons.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patches.youtube.misc.litho.filter.patch.LithoFilterPatch
|
||||
import app.revanced.patches.youtube.layout.buttons.annotations.HideButtonsCompatibility
|
||||
import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch
|
||||
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
|
||||
import app.revanced.patches.shared.settings.preference.impl.PreferenceScreen
|
||||
import app.revanced.patches.shared.settings.preference.impl.StringResource
|
||||
import app.revanced.patches.shared.settings.preference.impl.SwitchPreference
|
||||
|
||||
@Patch
|
||||
@DependsOn([ResourceMappingPatch::class, LithoFilterPatch::class])
|
||||
@Name("hide-video-buttons")
|
||||
@Description("Adds options to hide action buttons under a video.")
|
||||
@HideButtonsCompatibility
|
||||
@Version("0.0.1")
|
||||
class HideButtonsPatch : ResourcePatch {
|
||||
override fun execute(context: ResourceContext): PatchResult {
|
||||
SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(
|
||||
PreferenceScreen(
|
||||
"revanced_hide_buttons",
|
||||
StringResource("revanced_hide_buttons_title", "Hide action buttons"),
|
||||
listOf(
|
||||
SwitchPreference(
|
||||
"revanced_hide_like_button",
|
||||
StringResource("revanced_hide_like_button_title", "Hide like button"),
|
||||
false,
|
||||
StringResource("revanced_hide_like_button_summary_on", "Like button is hidden"),
|
||||
StringResource("revanced_hide_like_button_summary_off", "Like button is shown")
|
||||
),
|
||||
SwitchPreference(
|
||||
"revanced_hide_dislike_button",
|
||||
StringResource("revanced_hide_dislike_button_title", "Hide dislike button"),
|
||||
false,
|
||||
StringResource("revanced_hide_dislike_button_summary_on", "Dislike button is hidden"),
|
||||
StringResource("revanced_hide_dislike_button_summary_off", "Dislike button is shown")
|
||||
),
|
||||
SwitchPreference(
|
||||
"revanced_hide_download_button",
|
||||
StringResource("revanced_hide_download_button_title", "Hide download button"),
|
||||
false,
|
||||
StringResource("revanced_hide_download_button_summary_on", "Download button is hidden"),
|
||||
StringResource("revanced_hide_download_button_summary_off", "Download button is shown")
|
||||
),
|
||||
SwitchPreference(
|
||||
"revanced_hide_playlist_button",
|
||||
StringResource("revanced_hide_playlist_button_title", "Hide playlist button"),
|
||||
false,
|
||||
StringResource("revanced_hide_playlist_button_summary_on", "Playlist button is hidden"),
|
||||
StringResource("revanced_hide_playlist_button_summary_off", "Playlist button is shown")
|
||||
),
|
||||
SwitchPreference(
|
||||
"revanced_hide_action_button",
|
||||
StringResource("revanced_hide_action_button_title", "Hide create, clip and thanks buttons"),
|
||||
true,
|
||||
StringResource("revanced_hide_action_button_summary_on", "Buttons are hidden"),
|
||||
StringResource("revanced_hide_action_button_summary_off", "Buttons are shown")
|
||||
),
|
||||
SwitchPreference(
|
||||
"revanced_hide_share_button",
|
||||
StringResource("revanced_hide_share_button_title", "Hide share button"),
|
||||
false,
|
||||
StringResource("revanced_hide_share_button_summary_on", "Share button is hidden"),
|
||||
StringResource("revanced_hide_share_button_summaryoff", "Share button is shown")
|
||||
),
|
||||
),
|
||||
StringResource("revanced_hide_buttons_summary", "Hide or show buttons under videos")
|
||||
)
|
||||
)
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
package app.revanced.patches.youtube.layout.castbutton.annotations
|
||||
|
||||
import app.revanced.patcher.annotation.Compatibility
|
||||
import app.revanced.patcher.annotation.Package
|
||||
|
||||
@Compatibility([Package("com.google.android.youtube")])
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
internal annotation class CastButtonCompatibility
|
@ -1,57 +0,0 @@
|
||||
package app.revanced.patches.youtube.layout.castbutton.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.addInstructions
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultError
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
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.shared.settings.preference.impl.StringResource
|
||||
import app.revanced.patches.shared.settings.preference.impl.SwitchPreference
|
||||
|
||||
@Patch
|
||||
@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(context: BytecodeContext): PatchResult {
|
||||
SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(
|
||||
SwitchPreference(
|
||||
"revanced_hide_cast_button",
|
||||
StringResource("revanced_hide_cast_button_title", "Hide cast button"),
|
||||
true,
|
||||
StringResource("revanced_hide_cast_button_summary_on", "Cast button is hidden"),
|
||||
StringResource("revanced_hide_cast_button_summary_off", "Cast button is shown")
|
||||
)
|
||||
)
|
||||
|
||||
with(
|
||||
context.findClass("MediaRouteButton")
|
||||
?: return PatchResultError("MediaRouteButton class not found.")
|
||||
) {
|
||||
with(
|
||||
mutableClass.methods.find { it.name == "setVisibility" }
|
||||
?: return PatchResultError("setVisibility method not found.")
|
||||
) {
|
||||
addInstructions(
|
||||
0, """
|
||||
invoke-static {p1}, Lapp/revanced/integrations/patches/HideCastButtonPatch;->getCastButtonOverrideV2(I)I
|
||||
move-result p1
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
package app.revanced.patches.youtube.layout.comments.annotations
|
||||
|
||||
import app.revanced.patcher.annotation.Compatibility
|
||||
import app.revanced.patcher.annotation.Package
|
||||
|
||||
@Compatibility(
|
||||
[Package(
|
||||
"com.google.android.youtube", arrayOf("17.49.37")
|
||||
)]
|
||||
)
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
internal annotation class CommentsCompatibility
|
@ -1,17 +0,0 @@
|
||||
package app.revanced.patches.youtube.layout.comments.bytecode.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import app.revanced.patches.youtube.layout.comments.resource.patch.CommentsResourcePatch
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
|
||||
|
||||
object ShortsCommentsButtonFingerprint : MethodFingerprint(
|
||||
"V", AccessFlags.PRIVATE or AccessFlags.FINAL, listOf("Z", "Z", "L"),
|
||||
customFingerprint = { methodDef ->
|
||||
methodDef.implementation?.instructions?.any {
|
||||
it.opcode.ordinal == Opcode.CONST.ordinal && (it as WideLiteralInstruction).wideLiteral == CommentsResourcePatch.shortsCommentsButtonId
|
||||
} == true
|
||||
}
|
||||
)
|
@ -1,62 +0,0 @@
|
||||
package app.revanced.patches.youtube.layout.comments.bytecode.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.addInstructions
|
||||
import app.revanced.patcher.extensions.instruction
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
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.patches.youtube.layout.comments.annotations.CommentsCompatibility
|
||||
import app.revanced.patches.youtube.layout.comments.bytecode.fingerprints.ShortsCommentsButtonFingerprint
|
||||
import app.revanced.patches.youtube.layout.comments.resource.patch.CommentsResourcePatch
|
||||
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
||||
import org.jf.dexlib2.Opcode
|
||||
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
|
||||
@Patch
|
||||
@DependsOn([IntegrationsPatch::class, CommentsResourcePatch::class])
|
||||
@Name("comments")
|
||||
@Description("Hides components related to comments.")
|
||||
@CommentsCompatibility
|
||||
@Version("0.0.1")
|
||||
class CommentsPatch : BytecodePatch(
|
||||
listOf(
|
||||
ShortsCommentsButtonFingerprint
|
||||
)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
val shortsCommentsButtonResult = ShortsCommentsButtonFingerprint.result!!
|
||||
val shortsCommentsButtonMethod = shortsCommentsButtonResult.mutableMethod
|
||||
|
||||
val checkCastAnchorFingerprint = object : MethodFingerprint(
|
||||
opcodes = listOf(
|
||||
Opcode.CONST,
|
||||
Opcode.CONST_HIGH16,
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.CONST,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.CHECK_CAST,
|
||||
)
|
||||
) {}
|
||||
|
||||
val checkCastAnchorIndex = checkCastAnchorFingerprint.also {
|
||||
it.resolve(context, shortsCommentsButtonMethod, shortsCommentsButtonResult.classDef)
|
||||
}.result!!.scanResult.patternScanResult!!.endIndex
|
||||
|
||||
shortsCommentsButtonMethod.addInstructions(
|
||||
checkCastAnchorIndex + 1, """
|
||||
invoke-static {v${(shortsCommentsButtonMethod.instruction(checkCastAnchorIndex) as OneRegisterInstruction).registerA}}, Lapp/revanced/integrations/patches/HideShortsCommentsButtonPatch;->hideShortsCommentsButton(Landroid/view/View;)V
|
||||
"""
|
||||
)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
package app.revanced.patches.youtube.layout.comments.resource.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patches.youtube.layout.comments.annotations.CommentsCompatibility
|
||||
import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch
|
||||
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
|
||||
import app.revanced.patches.shared.settings.preference.impl.PreferenceScreen
|
||||
import app.revanced.patches.shared.settings.preference.impl.StringResource
|
||||
import app.revanced.patches.shared.settings.preference.impl.SwitchPreference
|
||||
|
||||
@Name("comments-resource-patch")
|
||||
@CommentsCompatibility
|
||||
@DependsOn([SettingsPatch::class, ResourceMappingPatch::class])
|
||||
@Version("0.0.1")
|
||||
class CommentsResourcePatch : ResourcePatch {
|
||||
companion object {
|
||||
internal var shortsCommentsButtonId: Long = -1
|
||||
}
|
||||
|
||||
override fun execute(context: ResourceContext): PatchResult {
|
||||
SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(
|
||||
PreferenceScreen(
|
||||
"revanced_comments",
|
||||
StringResource("revanced_comments_title", "Comments"),
|
||||
listOf(
|
||||
SwitchPreference(
|
||||
"revanced_hide_comments_section",
|
||||
StringResource("revanced_hide_comments_section_title", "Hide comments section"),
|
||||
false,
|
||||
StringResource("revanced_hide_comments_section_summary_on", "Comment section is hidden"),
|
||||
StringResource("revanced_hide_comments_section_summary_off", "Comment section is shown")
|
||||
),
|
||||
SwitchPreference(
|
||||
"revanced_hide_preview_comment",
|
||||
StringResource("revanced_hide_preview_comment_title", "Hide preview comment"),
|
||||
false,
|
||||
StringResource("revanced_hide_preview_comment_on", "Preview comment is hidden"),
|
||||
StringResource("revanced_hide_preview_comment_off", "Preview comment is shown")
|
||||
),
|
||||
SwitchPreference(
|
||||
"revanced_hide_shorts_comments_button",
|
||||
StringResource("revanced_hide_shorts_comments_button_title", "Hide shorts comments button"),
|
||||
false,
|
||||
StringResource("revanced_hide_shorts_comments_button_on", "Shorts comments button is hidden"),
|
||||
StringResource("revanced_hide_shorts_comments_button_off", "Shorts comments button is shown")
|
||||
),
|
||||
),
|
||||
StringResource("revanced_comments_summary", "Manage the visibility of comments section components")
|
||||
)
|
||||
)
|
||||
|
||||
shortsCommentsButtonId = ResourceMappingPatch.resourceMappings.single {
|
||||
it.type == "drawable" && it.name == "ic_right_comment_32c"
|
||||
}.id
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package app.revanced.patches.youtube.layout.flyoutpanel.flyoutpanel.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patches.youtube.misc.litho.filter.patch.LithoFilterPatch
|
||||
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.shared.util.resources.ResourceHelper
|
||||
|
||||
@Patch
|
||||
@Name("hide-flyout-panel")
|
||||
@Description("Adds options to hide player settings flyout panel.")
|
||||
@DependsOn(
|
||||
[
|
||||
LithoFilterPatch::class,
|
||||
SettingsPatch::class
|
||||
]
|
||||
)
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class FlyoutPanelPatch : ResourcePatch {
|
||||
override fun execute(context: ResourceContext): PatchResult {
|
||||
|
||||
/*
|
||||
add settings
|
||||
*/
|
||||
ResourceHelper.addSettings2(
|
||||
context,
|
||||
"PREFERENCE_CATEGORY: REVANCED_SETTINGS",
|
||||
"PREFERENCE: LAYOUT_SETTINGS",
|
||||
"PREFERENCE_HEADER: FLYOUT_PANEL",
|
||||
"SETTINGS: FLYOUT_PANEL_COMPONENT"
|
||||
)
|
||||
|
||||
ResourceHelper.patchSuccess(
|
||||
context,
|
||||
"hide-flyout-panel"
|
||||
)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package app.revanced.patches.youtube.layout.flyoutpanel.oldqualitylayout.bytecode.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourcdIdPatch
|
||||
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
object QualityMenuViewInflateFingerprint : MethodFingerprint(
|
||||
opcodes = listOf(Opcode.INVOKE_SUPER),
|
||||
customFingerprint = { methodDef ->
|
||||
methodDef.implementation?.instructions?.any { instruction ->
|
||||
instruction.opcode.ordinal == Opcode.CONST.ordinal &&
|
||||
(instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.videoqualityfragmentLabelId
|
||||
} == true
|
||||
}
|
||||
)
|
@ -0,0 +1,40 @@
|
||||
package app.revanced.patches.youtube.layout.flyoutpanel.oldqualitylayout.bytecode.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.addInstruction
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patches.youtube.layout.flyoutpanel.oldqualitylayout.bytecode.fingerprints.QualityMenuViewInflateFingerprint
|
||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.shared.util.integrations.Constants.FLYOUTPANEL_LAYOUT
|
||||
import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||
|
||||
@Name("enable-oldstyle-quality-layout-bytecode-patch")
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class OldQualityLayoutBytecodePatch : BytecodePatch(
|
||||
listOf(QualityMenuViewInflateFingerprint)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
val inflateFingerprintResult = QualityMenuViewInflateFingerprint.result!!
|
||||
val method = inflateFingerprintResult.mutableMethod
|
||||
val instructions = method.implementation!!.instructions
|
||||
|
||||
// at this index the listener is added to the list view
|
||||
val listenerInvokeRegister = instructions.size - 1 - 1
|
||||
|
||||
// get the register which stores the quality menu list view
|
||||
val onItemClickViewRegister = (instructions[listenerInvokeRegister] as FiveRegisterInstruction).registerC
|
||||
|
||||
// insert the integrations method
|
||||
method.addInstruction(
|
||||
listenerInvokeRegister, // insert the integrations instructions right before the listener
|
||||
"invoke-static { v$onItemClickViewRegister }, $FLYOUTPANEL_LAYOUT->enableOldQualityMenu(Landroid/widget/ListView;)V"
|
||||
)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package app.revanced.patches.youtube.layout.flyoutpanel.oldqualitylayout.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.ResourceContext
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patches.youtube.layout.flyoutpanel.oldqualitylayout.bytecode.patch.OldQualityLayoutBytecodePatch
|
||||
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.shared.util.resources.ResourceHelper
|
||||
|
||||
@Patch
|
||||
@Name("enable-oldstyle-quality-layout")
|
||||
@Description("Enables the original quality flyout menu.")
|
||||
@DependsOn(
|
||||
[
|
||||
OldQualityLayoutBytecodePatch::class,
|
||||
SettingsPatch::class
|
||||
]
|
||||
)
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class OldQualityLayoutPatch : ResourcePatch {
|
||||
override fun execute(context: ResourceContext): PatchResult {
|
||||
|
||||
/*
|
||||
add settings
|
||||
*/
|
||||
ResourceHelper.addSettings2(
|
||||
context,
|
||||
"PREFERENCE_CATEGORY: REVANCED_SETTINGS",
|
||||
"PREFERENCE: LAYOUT_SETTINGS",
|
||||
"PREFERENCE_HEADER: FLYOUT_PANEL",
|
||||
"SETTINGS: ENABLE_OLD_STYLE_QUALITY_LAYOUT"
|
||||
)
|
||||
|
||||
ResourceHelper.patchSuccess(
|
||||
context,
|
||||
"enable-oldstyle-quality-layout"
|
||||
)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
package app.revanced.patches.youtube.layout.fullscreen.endscreenoverlay.bytecode.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.addInstructions
|
||||
import app.revanced.patcher.extensions.instruction
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.util.smali.ExternalLabel
|
||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.shared.extensions.findMutableMethodOf
|
||||
import app.revanced.shared.patches.mapping.ResourceMappingPatch
|
||||
import app.revanced.shared.util.integrations.Constants.FULLSCREEN_LAYOUT
|
||||
import org.jf.dexlib2.iface.instruction.formats.Instruction22c
|
||||
import org.jf.dexlib2.iface.instruction.formats.Instruction31i
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
@Name("hide-endscreen-overlay-bytecode-patch")
|
||||
@DependsOn([ResourceMappingPatch::class])
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class HideEndscreenOverlayBytecodePatch : BytecodePatch() {
|
||||
// list of resource names to get the id of
|
||||
private val resourceIds = arrayOf(
|
||||
"app_related_endscreen_results"
|
||||
).map { name ->
|
||||
ResourceMappingPatch.resourceMappings.single { it.name == name }.id
|
||||
}
|
||||
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
context.classes.forEach { classDef ->
|
||||
classDef.methods.forEach { method ->
|
||||
with(method.implementation) {
|
||||
this?.instructions?.forEachIndexed { index, instruction ->
|
||||
when (instruction.opcode) {
|
||||
Opcode.CONST -> {
|
||||
when ((instruction as Instruction31i).wideLiteral) {
|
||||
resourceIds[0] -> { // end screen result
|
||||
val insertIndex = index - 13
|
||||
val invokeInstruction = instructions.elementAt(insertIndex)
|
||||
if (invokeInstruction.opcode != Opcode.IF_NEZ) return@forEachIndexed
|
||||
|
||||
val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method)
|
||||
|
||||
val dummyRegister = (instructions.elementAt(index) as Instruction31i).registerA
|
||||
mutableMethod.addInstructions(
|
||||
insertIndex, """
|
||||
invoke-static {}, $FULLSCREEN_LAYOUT->hideEndscreenOverlay()Z
|
||||
move-result v$dummyRegister
|
||||
if-eqz v$dummyRegister, :on
|
||||
return-void
|
||||
""", listOf(ExternalLabel("on", mutableMethod.instruction(insertIndex)))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> return@forEachIndexed
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package app.revanced.patches.youtube.layout.fullscreen.endscreenoverlay.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.ResourceContext
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patches.youtube.layout.fullscreen.endscreenoverlay.bytecode.patch.HideEndscreenOverlayBytecodePatch
|
||||
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.shared.util.resources.ResourceHelper
|
||||
import app.revanced.shared.util.resources.ResourceUtils
|
||||
import app.revanced.shared.util.resources.ResourceUtils.copyResources
|
||||
|
||||
@Patch
|
||||
@Name("hide-endscreen-overlay")
|
||||
@Description("Hide endscreen overlay on swipe controls.")
|
||||
@DependsOn(
|
||||
[
|
||||
HideEndscreenOverlayBytecodePatch::class,
|
||||
SettingsPatch::class
|
||||
]
|
||||
)
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class HideFilmStripPatch : ResourcePatch {
|
||||
override fun execute(context: ResourceContext): PatchResult {
|
||||
|
||||
/*
|
||||
add settings
|
||||
*/
|
||||
ResourceHelper.addSettings2(
|
||||
context,
|
||||
"PREFERENCE_CATEGORY: REVANCED_SETTINGS",
|
||||
"PREFERENCE: LAYOUT_SETTINGS",
|
||||
"PREFERENCE_HEADER: FULLSCREEN",
|
||||
"SETTINGS: HIDE_ENDSCREEN_OVERLAY"
|
||||
)
|
||||
|
||||
ResourceHelper.patchSuccess(
|
||||
context,
|
||||
"hide-endscreen-overlay"
|
||||
)
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package app.revanced.patches.youtube.layout.fullscreen.flimstripoverlay.bytecode.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourcdIdPatch
|
||||
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
object ScrubbingLabelFingerprint : MethodFingerprint(
|
||||
opcodes = listOf(Opcode.IPUT_BOOLEAN),
|
||||
customFingerprint = { methodDef ->
|
||||
methodDef.implementation?.instructions?.any { instruction ->
|
||||
instruction.opcode.ordinal == Opcode.CONST.ordinal &&
|
||||
(instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.scrubbingLabelId
|
||||
} == true
|
||||
}
|
||||
)
|
@ -0,0 +1,56 @@
|
||||
package app.revanced.patches.youtube.layout.fullscreen.flimstripoverlay.bytecode.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.addInstructions
|
||||
import app.revanced.patcher.extensions.removeInstruction
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patches.youtube.layout.fullscreen.flimstripoverlay.bytecode.fingerprints.ScrubbingLabelFingerprint
|
||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.shared.util.integrations.Constants.FULLSCREEN_LAYOUT
|
||||
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
|
||||
import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||
import org.jf.dexlib2.iface.reference.FieldReference
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
@Name("hide-filmstrip-overlay-bytecode-patch")
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class HideFilmstripOverlayBytecodePatch : BytecodePatch(
|
||||
listOf(
|
||||
ScrubbingLabelFingerprint
|
||||
)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
val scrubbingLabelResult = ScrubbingLabelFingerprint.result!!
|
||||
val scrubbingLabelMethod = scrubbingLabelResult.mutableMethod
|
||||
val scrubbingLabelMethodInstructions = scrubbingLabelMethod.implementation!!.instructions
|
||||
|
||||
for ((index, instruction) in scrubbingLabelMethodInstructions.withIndex()) {
|
||||
if (instruction.opcode != Opcode.IPUT_BOOLEAN) continue
|
||||
val scrubbingLabelRegisterA = (instruction as TwoRegisterInstruction).registerA
|
||||
val scrubbingLabelRegisterB = scrubbingLabelRegisterA + 2
|
||||
val scrubbingLabelRegisterC = (instruction as TwoRegisterInstruction).registerB
|
||||
val scrubbingLabelReference = (instruction as ReferenceInstruction).reference as FieldReference
|
||||
|
||||
scrubbingLabelMethod.addInstructions(
|
||||
index + 1, """
|
||||
invoke-static {}, $FULLSCREEN_LAYOUT->hideFilmstripOverlay()Z
|
||||
move-result v$scrubbingLabelRegisterB
|
||||
if-eqz v$scrubbingLabelRegisterB, :show
|
||||
const/4 v$scrubbingLabelRegisterA, 0x0
|
||||
:show
|
||||
iput-boolean v$scrubbingLabelRegisterA, v$scrubbingLabelRegisterC, ${scrubbingLabelReference.definingClass}->${scrubbingLabelReference.name}:${scrubbingLabelReference.type}
|
||||
"""
|
||||
)
|
||||
|
||||
scrubbingLabelMethod.removeInstruction(index)
|
||||
break
|
||||
}
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package app.revanced.patches.youtube.layout.fullscreen.flimstripoverlay.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.ResourceContext
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patches.youtube.layout.fullscreen.flimstripoverlay.bytecode.patch.HideFilmstripOverlayBytecodePatch
|
||||
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.shared.util.resources.ResourceHelper
|
||||
|
||||
@Patch
|
||||
@Name("hide-filmstrip-overlay")
|
||||
@Description("Hide flimstrip overlay on swipe controls.")
|
||||
@DependsOn(
|
||||
[
|
||||
HideFilmstripOverlayBytecodePatch::class,
|
||||
SettingsPatch::class
|
||||
]
|
||||
)
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class HideFilmstripOverlayPatch : ResourcePatch {
|
||||
override fun execute(context: ResourceContext): PatchResult {
|
||||
|
||||
/*
|
||||
add settings
|
||||
*/
|
||||
ResourceHelper.addSettings2(
|
||||
context,
|
||||
"PREFERENCE_CATEGORY: REVANCED_SETTINGS",
|
||||
"PREFERENCE: LAYOUT_SETTINGS",
|
||||
"PREFERENCE_HEADER: FULLSCREEN",
|
||||
"SETTINGS: HIDE_FILMSTRIP_OVERLAY"
|
||||
)
|
||||
|
||||
ResourceHelper.patchSuccess(
|
||||
context,
|
||||
"hide-filmstrip-overlay"
|
||||
)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package app.revanced.patches.youtube.layout.fullscreen.fullscreenbuttoncontainer.bytecode.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.shared.extensions.findMutableMethodOf
|
||||
import app.revanced.shared.extensions.injectHideCall
|
||||
import app.revanced.shared.patches.mapping.ResourceMappingPatch
|
||||
import org.jf.dexlib2.iface.instruction.formats.Instruction21c
|
||||
import org.jf.dexlib2.iface.instruction.formats.Instruction31i
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
@Name("hide-fullscreen-buttoncontainer-bytecode-patch")
|
||||
@DependsOn([ResourceMappingPatch::class])
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class FullscreenButtonContainerBytecodePatch : BytecodePatch() {
|
||||
private val resourceIds = arrayOf(
|
||||
"quick_actions_element_container"
|
||||
).map { name ->
|
||||
ResourceMappingPatch.resourceMappings.single { it.name == name }.id
|
||||
}
|
||||
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
context.classes.forEach { classDef ->
|
||||
classDef.methods.forEach { method ->
|
||||
with(method.implementation) {
|
||||
this?.instructions?.forEachIndexed { index, instruction ->
|
||||
when (instruction.opcode) {
|
||||
Opcode.CONST -> {
|
||||
when ((instruction as Instruction31i).wideLiteral) {
|
||||
resourceIds[0] -> { // fullscreen panel
|
||||
val insertIndex = index + 3
|
||||
val invokeInstruction = instructions.elementAt(insertIndex)
|
||||
if (invokeInstruction.opcode != Opcode.CHECK_CAST) return@forEachIndexed
|
||||
|
||||
val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method)
|
||||
|
||||
val viewRegister = (invokeInstruction as Instruction21c).registerA
|
||||
mutableMethod.implementation!!.injectHideCall(insertIndex, viewRegister, "layout/FullscreenLayoutPatch", "hideFullscreenButtonContainer")
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> return@forEachIndexed
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package app.revanced.patches.youtube.layout.fullscreen.fullscreenbuttoncontainer.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.ResourceContext
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patches.youtube.layout.fullscreen.fullscreenbuttoncontainer.bytecode.patch.FullscreenButtonContainerBytecodePatch
|
||||
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.shared.util.resources.ResourceHelper
|
||||
|
||||
@Patch
|
||||
@Name("hide-fullscreen-buttoncontainer")
|
||||
@Description("Hides the button containers in fullscreen.")
|
||||
@DependsOn(
|
||||
[
|
||||
FullscreenButtonContainerBytecodePatch::class,
|
||||
SettingsPatch::class
|
||||
]
|
||||
)
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class FullscreenButtonContainerPatch : ResourcePatch {
|
||||
override fun execute(context: ResourceContext): PatchResult {
|
||||
|
||||
/*
|
||||
add settings
|
||||
*/
|
||||
ResourceHelper.addSettings2(
|
||||
context,
|
||||
"PREFERENCE_CATEGORY: REVANCED_SETTINGS",
|
||||
"PREFERENCE: LAYOUT_SETTINGS",
|
||||
"PREFERENCE_HEADER: FULLSCREEN",
|
||||
"SETTINGS: HIDE_FULLSCREEN_BUTTON_CONTAINER"
|
||||
)
|
||||
|
||||
ResourceHelper.patchSuccess(
|
||||
context,
|
||||
"hide-fullscreen-buttoncontainer"
|
||||
)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package app.revanced.patches.youtube.layout.fullscreen.hapticfeedback.bytecode.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
|
||||
object MarkerHapticsFingerprint : MethodFingerprint(
|
||||
strings = listOf("Failed to execute markers haptics vibrate.")
|
||||
)
|
@ -0,0 +1,7 @@
|
||||
package app.revanced.patches.youtube.layout.fullscreen.hapticfeedback.bytecode.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
|
||||
object ScrubbingHapticsFingerprint : MethodFingerprint(
|
||||
strings = listOf("Failed to haptics vibrate for fine scrubbing.")
|
||||
)
|
@ -0,0 +1,14 @@
|
||||
package app.revanced.patches.youtube.layout.fullscreen.hapticfeedback.bytecode.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
object SeekHapticsFingerprint : MethodFingerprint(
|
||||
opcodes = listOf(
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.RETURN_VOID
|
||||
),
|
||||
strings = listOf("Failed to easy seek haptics vibrate.")
|
||||
)
|
@ -0,0 +1,7 @@
|
||||
package app.revanced.patches.youtube.layout.fullscreen.hapticfeedback.bytecode.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
|
||||
object ZoomHapticsFingerprint : MethodFingerprint(
|
||||
strings = listOf("Failed to haptics vibrate for video zoom")
|
||||
)
|
@ -0,0 +1,88 @@
|
||||
package app.revanced.patches.youtube.layout.fullscreen.hapticfeedback.bytecode.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.addInstructions
|
||||
import app.revanced.patcher.extensions.instruction
|
||||
import app.revanced.patcher.extensions.removeInstruction
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.util.smali.ExternalLabel
|
||||
import app.revanced.patches.youtube.layout.fullscreen.hapticfeedback.bytecode.fingerprints.*
|
||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.shared.util.integrations.Constants.FULLSCREEN_LAYOUT
|
||||
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
|
||||
@Name("disable-haptic-feedback-bytecode-patch")
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class HapticFeedBackBytecodePatch : BytecodePatch(
|
||||
listOf(
|
||||
MarkerHapticsFingerprint,
|
||||
SeekHapticsFingerprint,
|
||||
ScrubbingHapticsFingerprint,
|
||||
ZoomHapticsFingerprint
|
||||
)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
|
||||
SeekHapticsFingerprint.disableHaptics("disableSeekVibrate")
|
||||
ScrubbingHapticsFingerprint.voidHaptics("disableScrubbingVibrate")
|
||||
MarkerHapticsFingerprint.voidHaptics("disableChapterVibrate")
|
||||
ZoomHapticsFingerprint.voidHaptics("disableZoomVibrate")
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
|
||||
private companion object {
|
||||
fun MethodFingerprint.disableHaptics(targetMethodName: String) {
|
||||
with(this.result!!) {
|
||||
val startIndex = scanResult.patternScanResult!!.startIndex
|
||||
val endIndex = scanResult.patternScanResult!!.endIndex
|
||||
val insertIndex = endIndex + 4
|
||||
val targetRegister = (method.implementation!!.instructions.elementAt(insertIndex) as OneRegisterInstruction).registerA
|
||||
val dummyRegister = targetRegister + 1
|
||||
|
||||
mutableMethod.removeInstruction(insertIndex)
|
||||
|
||||
mutableMethod.addInstructions(
|
||||
insertIndex, """
|
||||
invoke-static {}, $FULLSCREEN_LAYOUT->$targetMethodName()Z
|
||||
move-result v$dummyRegister
|
||||
if-eqz v$dummyRegister, :vibrate
|
||||
const-wide/16 v$targetRegister, 0x0
|
||||
goto :exit
|
||||
:vibrate
|
||||
const-wide/16 v$targetRegister, 0x19
|
||||
""", listOf(ExternalLabel("exit", mutableMethod.instruction(insertIndex)))
|
||||
)
|
||||
|
||||
mutableMethod.addInstructions(
|
||||
startIndex, """
|
||||
invoke-static {}, $FULLSCREEN_LAYOUT->$targetMethodName()Z
|
||||
move-result v$dummyRegister
|
||||
if-eqz v$dummyRegister, :vibrate
|
||||
return-void
|
||||
""", listOf(ExternalLabel("vibrate", mutableMethod.instruction(startIndex)))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun MethodFingerprint.voidHaptics(targetMethodName: String) {
|
||||
with(this.result!!) {
|
||||
mutableMethod.addInstructions(
|
||||
0, """
|
||||
invoke-static {}, $FULLSCREEN_LAYOUT->$targetMethodName()Z
|
||||
move-result v0
|
||||
if-eqz v0, :vibrate
|
||||
return-void
|
||||
""", listOf(ExternalLabel("vibrate", mutableMethod.instruction(0)))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package app.revanced.patches.youtube.layout.fullscreen.hapticfeedback.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.ResourceContext
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patches.youtube.layout.fullscreen.hapticfeedback.bytecode.patch.HapticFeedBackBytecodePatch
|
||||
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.shared.util.resources.ResourceHelper
|
||||
|
||||
@Patch
|
||||
@Name("disable-haptic-feedback")
|
||||
@Description("Disable haptic feedback when swiping.")
|
||||
@DependsOn(
|
||||
[
|
||||
HapticFeedBackBytecodePatch::class,
|
||||
SettingsPatch::class
|
||||
]
|
||||
)
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class HapticFeedBackPatch : ResourcePatch {
|
||||
override fun execute(context: ResourceContext): PatchResult {
|
||||
|
||||
/*
|
||||
add settings
|
||||
*/
|
||||
ResourceHelper.addSettings2(
|
||||
context,
|
||||
"PREFERENCE_CATEGORY: REVANCED_SETTINGS",
|
||||
"PREFERENCE: LAYOUT_SETTINGS",
|
||||
"PREFERENCE_HEADER: FULLSCREEN",
|
||||
"SETTINGS: DISABLE_HAPTIC_FEEDBACK"
|
||||
)
|
||||
|
||||
ResourceHelper.patchSuccess(
|
||||
context,
|
||||
"disable-haptic-feedback"
|
||||
)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
package app.revanced.patches.youtube.layout.fullscreenpanels.annotations
|
||||
|
||||
import app.revanced.patcher.annotation.Compatibility
|
||||
import app.revanced.patcher.annotation.Package
|
||||
|
||||
@Compatibility(
|
||||
[Package(
|
||||
"com.google.android.youtube", arrayOf("17.49.37")
|
||||
)]
|
||||
)
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
internal annotation class FullscreenPanelsCompatibility
|
@ -1,11 +0,0 @@
|
||||
package app.revanced.patches.youtube.layout.fullscreenpanels.fingerprints
|
||||
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
object FullscreenViewAdderFingerprint : MethodFingerprint(
|
||||
opcodes = listOf(
|
||||
Opcode.IGET_BOOLEAN
|
||||
)
|
||||
)
|
@ -1,18 +0,0 @@
|
||||
package app.revanced.patches.youtube.layout.fullscreenpanels.fingerprints
|
||||
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
object FullscreenViewAdderParentFingerprint : MethodFingerprint(
|
||||
parameters = listOf("L", "L"),
|
||||
opcodes = listOf(
|
||||
Opcode.GOTO,
|
||||
Opcode.IGET_BOOLEAN,
|
||||
Opcode.IF_EQ,
|
||||
Opcode.GOTO,
|
||||
Opcode.CONST_4,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
),
|
||||
customFingerprint = { it.definingClass.endsWith("FullscreenEngagementPanelOverlay;") }
|
||||
)
|
@ -1,65 +0,0 @@
|
||||
package app.revanced.patches.youtube.layout.fullscreenpanels.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.addInstructions
|
||||
import app.revanced.patcher.extensions.removeInstruction
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultError
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patches.youtube.layout.fullscreenpanels.annotations.FullscreenPanelsCompatibility
|
||||
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.shared.settings.preference.impl.StringResource
|
||||
import app.revanced.patches.shared.settings.preference.impl.SwitchPreference
|
||||
|
||||
@Patch
|
||||
@Name("disable-fullscreen-panels")
|
||||
@DependsOn([IntegrationsPatch::class, SettingsPatch::class])
|
||||
@Description("Disables video description and comments panel in fullscreen view.")
|
||||
@FullscreenPanelsCompatibility
|
||||
@Version("0.0.1")
|
||||
class FullscreenPanelsRemoverPatch : BytecodePatch(
|
||||
listOf(
|
||||
FullscreenViewAdderParentFingerprint
|
||||
)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(
|
||||
SwitchPreference(
|
||||
"revanced_hide_fullscreen_panels",
|
||||
StringResource("revanced_hide_fullscreen_panels_title", "Hide fullscreen panels"),
|
||||
true,
|
||||
StringResource("revanced_hide_fullscreen_panels_summary_on", "Fullscreen panels are hidden"),
|
||||
StringResource("revanced_hide_fullscreen_panels_summary_off", "Fullscreen panels are shown")
|
||||
)
|
||||
)
|
||||
|
||||
val parentResult = FullscreenViewAdderParentFingerprint.result!!
|
||||
FullscreenViewAdderFingerprint.resolve(context, parentResult.method, parentResult.classDef)
|
||||
val result = FullscreenViewAdderParentFingerprint.result
|
||||
?: return PatchResultError("Fingerprint not resolved!")
|
||||
|
||||
val method = result.mutableMethod
|
||||
|
||||
val ifIndex = result.scanResult.patternScanResult!!.startIndex + 2
|
||||
|
||||
method.removeInstruction(ifIndex)
|
||||
method.addInstructions(
|
||||
ifIndex, """
|
||||
invoke-static {}, Lapp/revanced/integrations/patches/FullscreenPanelsRemoverPatch;->getFullscreenPanelsVisibility()I
|
||||
move-result p1
|
||||
"""
|
||||
)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -1,13 +1,10 @@
|
||||
package app.revanced.patches.youtube.layout.autocaptions.fingerprints
|
||||
package app.revanced.patches.youtube.layout.general.autocaptions.bytecode.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
|
||||
@FuzzyPatternScanMethod(3)
|
||||
object StartVideoInformerFingerprint : MethodFingerprint(
|
||||
"V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L", "L", "L", "L"), listOf(
|
||||
Opcode.INVOKE_STATIC,
|
||||
@ -22,12 +19,5 @@ object StartVideoInformerFingerprint : MethodFingerprint(
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.CONST_4,
|
||||
Opcode.IF_EQ,
|
||||
Opcode.GOTO,
|
||||
)
|
||||
)
|
@ -1,4 +1,4 @@
|
||||
package app.revanced.patches.youtube.layout.autocaptions.fingerprints
|
||||
package app.revanced.patches.youtube.layout.general.autocaptions.bytecode.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
@ -0,0 +1,71 @@
|
||||
package app.revanced.patches.youtube.layout.general.autocaptions.bytecode.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.addInstructions
|
||||
import app.revanced.patcher.extensions.instruction
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.extensions.MethodFingerprintExtensions.name
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultError
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.util.smali.ExternalLabel
|
||||
import app.revanced.patches.youtube.layout.general.autocaptions.bytecode.fingerprints.*
|
||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.shared.fingerprints.SubtitleButtonControllerFingerprint
|
||||
import app.revanced.shared.util.integrations.Constants.GENERAL_LAYOUT
|
||||
|
||||
@Name("hide-auto-captions-bytecode-patch")
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class AutoCaptionsBytecodePatch : BytecodePatch(
|
||||
listOf(
|
||||
StartVideoInformerFingerprint,
|
||||
SubtitleButtonControllerFingerprint,
|
||||
SubtitleTrackFingerprint
|
||||
)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
listOf(
|
||||
StartVideoInformerFingerprint.toPatch(Status.DISABLED),
|
||||
SubtitleButtonControllerFingerprint.toPatch(Status.ENABLED)
|
||||
).forEach { (fingerprint, status) ->
|
||||
with(fingerprint.result ?: return PatchResultError("Failed to find ${fingerprint.name} method.")) {
|
||||
mutableMethod.addInstructions(
|
||||
0,
|
||||
"""
|
||||
const/4 v0, ${status.value}
|
||||
sput-boolean v0, $GENERAL_LAYOUT->captionsButtonStatus:Z
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val subtitleTrackMethod = SubtitleTrackFingerprint.result!!.mutableMethod
|
||||
|
||||
subtitleTrackMethod.addInstructions(
|
||||
0, """
|
||||
invoke-static {}, $GENERAL_LAYOUT->hideAutoCaptions()Z
|
||||
move-result v0
|
||||
if-eqz v0, :auto_captions_shown
|
||||
sget-boolean v0, $GENERAL_LAYOUT->captionsButtonStatus:Z
|
||||
if-nez v0, :auto_captions_shown
|
||||
const/4 v0, 0x1
|
||||
return v0
|
||||
""", listOf(ExternalLabel("auto_captions_shown", subtitleTrackMethod.instruction(0)))
|
||||
)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
|
||||
private fun MethodFingerprint.toPatch(visibility: Status) = SetStatus(this, visibility)
|
||||
|
||||
private data class SetStatus(val fingerprint: MethodFingerprint, val visibility: Status)
|
||||
|
||||
private enum class Status(val value: Int) {
|
||||
ENABLED(1),
|
||||
DISABLED(0)
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package app.revanced.patches.youtube.layout.general.autocaptions.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.ResourceContext
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patches.youtube.layout.general.autocaptions.bytecode.patch.AutoCaptionsBytecodePatch
|
||||
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.shared.util.resources.ResourceHelper
|
||||
|
||||
@Patch
|
||||
@Name("hide-auto-captions")
|
||||
@Description("Hide captions from being automatically enabled.")
|
||||
@DependsOn(
|
||||
[
|
||||
AutoCaptionsBytecodePatch::class,
|
||||
SettingsPatch::class
|
||||
]
|
||||
)
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class AutoCaptionsPatch : ResourcePatch {
|
||||
override fun execute(context: ResourceContext): PatchResult {
|
||||
|
||||
/*
|
||||
add settings
|
||||
*/
|
||||
ResourceHelper.addSettings2(
|
||||
context,
|
||||
"PREFERENCE_CATEGORY: REVANCED_SETTINGS",
|
||||
"PREFERENCE: LAYOUT_SETTINGS",
|
||||
"PREFERENCE_HEADER: GENERAL",
|
||||
"SETTINGS: HIDE_AUTO_CAPTIONS"
|
||||
)
|
||||
|
||||
ResourceHelper.patchSuccess(
|
||||
context,
|
||||
"hide-auto-captions"
|
||||
)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package app.revanced.patches.youtube.layout.general.autopopuppanels.bytecode.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
|
||||
object EngagementPanelControllerFingerprint : MethodFingerprint(
|
||||
"L",
|
||||
AccessFlags.PRIVATE or AccessFlags.FINAL,
|
||||
strings = listOf(
|
||||
"EngagementPanelController: cannot show EngagementPanel before EngagementPanelController.init() has been called.",
|
||||
"[EngagementPanel] Cannot show EngagementPanel before EngagementPanelController.init() has been called."
|
||||
)
|
||||
)
|
@ -0,0 +1,40 @@
|
||||
package app.revanced.patches.youtube.layout.general.autopopuppanels.bytecode.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.addInstructions
|
||||
import app.revanced.patcher.extensions.instruction
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.util.smali.ExternalLabel
|
||||
import app.revanced.patches.youtube.layout.general.autopopuppanels.bytecode.fingerprints.EngagementPanelControllerFingerprint
|
||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.shared.util.integrations.Constants.GENERAL_LAYOUT
|
||||
|
||||
@Name("hide-auto-player-popup-panels-bytecode-patch")
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class PlayerPopupPanelsBytecodePatch : BytecodePatch(
|
||||
listOf(
|
||||
EngagementPanelControllerFingerprint
|
||||
)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
val engagementPanelControllerMethod = EngagementPanelControllerFingerprint.result!!.mutableMethod
|
||||
|
||||
engagementPanelControllerMethod.addInstructions(
|
||||
0, """
|
||||
invoke-static { }, $GENERAL_LAYOUT->hideAutoPlayerPopupPanels()Z
|
||||
move-result v0
|
||||
if-eqz v0, :player_popup_panels_shown
|
||||
if-eqz p4, :player_popup_panels_shown
|
||||
const/4 v0, 0x0
|
||||
return-object v0
|
||||
""", listOf(ExternalLabel("player_popup_panels_shown", engagementPanelControllerMethod.instruction(0)))
|
||||
)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package app.revanced.patches.youtube.layout.general.autopopuppanels.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.ResourceContext
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patches.youtube.layout.general.autopopuppanels.bytecode.patch.PlayerPopupPanelsBytecodePatch
|
||||
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.shared.util.resources.ResourceHelper
|
||||
|
||||
@Patch
|
||||
@Name("hide-auto-player-popup-panels")
|
||||
@Description("Hide automatic popup panels (playlist or live chat) on video player.")
|
||||
@DependsOn(
|
||||
[
|
||||
PlayerPopupPanelsBytecodePatch::class,
|
||||
SettingsPatch::class
|
||||
]
|
||||
)
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class PlayerPopupPanelsPatch : ResourcePatch {
|
||||
override fun execute(context: ResourceContext): PatchResult {
|
||||
|
||||
/*
|
||||
add settings
|
||||
*/
|
||||
ResourceHelper.addSettings2(
|
||||
context,
|
||||
"PREFERENCE_CATEGORY: REVANCED_SETTINGS",
|
||||
"PREFERENCE: LAYOUT_SETTINGS",
|
||||
"PREFERENCE_HEADER: GENERAL",
|
||||
"SETTINGS: HIDE_AUTO_PLAYER_POPUP_PANELS"
|
||||
)
|
||||
|
||||
ResourceHelper.patchSuccess(
|
||||
context,
|
||||
"hide-auto-player-popup-panels"
|
||||
)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
package app.revanced.patches.youtube.layout.general.crowdfundingbox.bytecode.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.addInstructions
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.shared.extensions.findMutableMethodOf
|
||||
import app.revanced.shared.extensions.injectHideCall
|
||||
import app.revanced.shared.patches.mapping.ResourceMappingPatch
|
||||
import org.jf.dexlib2.iface.instruction.formats.Instruction22c
|
||||
import org.jf.dexlib2.iface.instruction.formats.Instruction31i
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
@Name("hide-crowdfunding-box-bytecode-patch")
|
||||
@DependsOn([ResourceMappingPatch::class])
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class CrowdfundingBoxBytecodePatch : BytecodePatch() {
|
||||
|
||||
// list of resource names to get the id of
|
||||
private val resourceIds = arrayOf(
|
||||
"donation_companion"
|
||||
).map { name ->
|
||||
ResourceMappingPatch.resourceMappings.single { it.name == name }.id
|
||||
}
|
||||
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
context.classes.forEach { classDef ->
|
||||
classDef.methods.forEach { method ->
|
||||
with(method.implementation) {
|
||||
this?.instructions?.forEachIndexed { index, instruction ->
|
||||
when (instruction.opcode) {
|
||||
Opcode.CONST -> {
|
||||
when ((instruction as Instruction31i).wideLiteral) {
|
||||
resourceIds[0] -> { // crowdfunding
|
||||
val insertIndex = index + 3
|
||||
val iPutInstruction = instructions.elementAt(insertIndex)
|
||||
if (iPutInstruction.opcode != Opcode.IPUT_OBJECT) return@forEachIndexed
|
||||
|
||||
val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method)
|
||||
|
||||
val viewRegister = (iPutInstruction as Instruction22c).registerA
|
||||
mutableMethod.implementation!!.injectHideCall(insertIndex, viewRegister, "layout/GeneralLayoutPatch", "hideCrowdfundingBox")
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> return@forEachIndexed
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package app.revanced.patches.youtube.layout.general.crowdfundingbox.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.ResourceContext
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patches.youtube.layout.general.crowdfundingbox.bytecode.patch.CrowdfundingBoxBytecodePatch
|
||||
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.shared.util.resources.ResourceHelper
|
||||
|
||||
@Patch
|
||||
@Name("hide-crowdfunding-box")
|
||||
@Description("Hides the crowdfunding box between the player and video description.")
|
||||
@DependsOn(
|
||||
[
|
||||
CrowdfundingBoxBytecodePatch::class,
|
||||
SettingsPatch::class
|
||||
]
|
||||
)
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class CrowdfundingBoxPatch : ResourcePatch {
|
||||
override fun execute(context: ResourceContext): PatchResult {
|
||||
|
||||
/*
|
||||
add settings
|
||||
*/
|
||||
ResourceHelper.addSettings2(
|
||||
context,
|
||||
"PREFERENCE_CATEGORY: REVANCED_SETTINGS",
|
||||
"PREFERENCE: LAYOUT_SETTINGS",
|
||||
"PREFERENCE_HEADER: GENERAL",
|
||||
"SETTINGS: HIDE_CROWDFUNDING_BOX"
|
||||
)
|
||||
|
||||
ResourceHelper.patchSuccess(
|
||||
context,
|
||||
"hide-crowdfunding-box"
|
||||
)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
package app.revanced.patches.youtube.layout.general.headerswitch.bytecode.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.addInstructions
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.shared.extensions.findMutableMethodOf
|
||||
import app.revanced.shared.patches.mapping.ResourceMappingPatch
|
||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||
import org.jf.dexlib2.builder.MutableMethodImplementation
|
||||
import org.jf.dexlib2.iface.instruction.formats.Instruction31i
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
@DependsOn([ResourceMappingPatch::class])
|
||||
@Name("header-switch-bytecode-patch")
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class HeaderSwitchBytecodePatch : BytecodePatch() {
|
||||
|
||||
// list of resource names to get the id of
|
||||
private val resourceIds = arrayOf(
|
||||
"ytWordmarkHeader"
|
||||
).map { name ->
|
||||
ResourceMappingPatch.resourceMappings.single { it.name == name }.id
|
||||
}
|
||||
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
context.classes.forEach { classDef ->
|
||||
classDef.methods.forEach { method ->
|
||||
with(method.implementation) {
|
||||
this?.instructions?.forEachIndexed { index, instruction ->
|
||||
when (instruction.opcode) {
|
||||
Opcode.CONST -> {
|
||||
when ((instruction as Instruction31i).wideLiteral) {
|
||||
resourceIds[0] -> { // header
|
||||
val insertIndex = index + 1
|
||||
|
||||
val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method)
|
||||
|
||||
val viewRegister = (instructions.elementAt(index) as Instruction31i).registerA
|
||||
|
||||
mutableMethod.addInstructions(
|
||||
insertIndex, """
|
||||
invoke-static {v$viewRegister}, Lapp/revanced/integrations/patches/layout/GeneralLayoutPatch;->enablePremiumHeader(I)I
|
||||
move-result v$viewRegister
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> return@forEachIndexed
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package app.revanced.patches.youtube.layout.general.headerswitch.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.ResourceContext
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patches.youtube.layout.general.headerswitch.bytecode.patch.HeaderSwitchBytecodePatch
|
||||
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.shared.util.resources.ResourceHelper
|
||||
|
||||
@Patch
|
||||
@Name("header-switch")
|
||||
@Description("Add switch to change header.")
|
||||
@DependsOn(
|
||||
[
|
||||
HeaderSwitchBytecodePatch::class,
|
||||
SettingsPatch::class
|
||||
]
|
||||
)
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class HeaderSwitchPatch : ResourcePatch {
|
||||
override fun execute(context: ResourceContext): PatchResult {
|
||||
|
||||
/*
|
||||
add settings
|
||||
*/
|
||||
ResourceHelper.addSettings2(
|
||||
context,
|
||||
"PREFERENCE_CATEGORY: REVANCED_SETTINGS",
|
||||
"PREFERENCE: LAYOUT_SETTINGS",
|
||||
"PREFERENCE_HEADER: GENERAL",
|
||||
"SETTINGS: HEADER_SWITCH"
|
||||
)
|
||||
|
||||
ResourceHelper.patchSuccess(
|
||||
context,
|
||||
"header-switch"
|
||||
)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -1,10 +1,16 @@
|
||||
package app.revanced.patches.youtube.layout.hidemixplaylists.fingerprints
|
||||
package app.revanced.patches.youtube.layout.general.mixplaylists.bytecode.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.shared.annotation.YouTubeCompatibility
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
@Name("mix-playlists-first-fingerprint")
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
object CreateMixPlaylistFingerprint : MethodFingerprint(
|
||||
"V", AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, listOf("L", "L", "L", "L", "L", "L", "L"), listOf(
|
||||
Opcode.INVOKE_DIRECT,
|
||||
@ -19,6 +25,6 @@ object CreateMixPlaylistFingerprint : MethodFingerprint(
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.INVOKE_VIRTUAL
|
||||
)
|
||||
)
|
@ -0,0 +1,30 @@
|
||||
package app.revanced.patches.youtube.layout.general.mixplaylists.bytecode.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.patches.youtube.misc.resourceid.patch.SharedResourcdIdPatch
|
||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
@Name("mix-playlists-fourth-fingerprint")
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
object FourthCreateMixPlaylistFingerprint : MethodFingerprint(
|
||||
opcodes = listOf(
|
||||
Opcode.CONST,
|
||||
Opcode.CONST_4,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.MOVE_OBJECT,
|
||||
Opcode.CHECK_CAST
|
||||
),
|
||||
customFingerprint = { methodDef ->
|
||||
methodDef.implementation?.instructions?.any { instruction ->
|
||||
instruction.opcode.ordinal == Opcode.CONST.ordinal &&
|
||||
(instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.abclistmenuitemLabelId
|
||||
} == true
|
||||
}
|
||||
)
|
@ -1,10 +1,16 @@
|
||||
package app.revanced.patches.youtube.layout.hidemixplaylists.fingerprints
|
||||
package app.revanced.patches.youtube.layout.general.mixplaylists.bytecode.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.shared.annotation.YouTubeCompatibility
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
@Name("mix-playlists-second-fingerprint")
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
object SecondCreateMixPlaylistFingerprint : MethodFingerprint(
|
||||
"V", AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, listOf("L", "L", "L", "L", "L", "L"), listOf(
|
||||
Opcode.INVOKE_DIRECT,
|
@ -0,0 +1,30 @@
|
||||
package app.revanced.patches.youtube.layout.general.mixplaylists.bytecode.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.patches.youtube.misc.resourceid.patch.SharedResourcdIdPatch
|
||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
@Name("mix-playlists-third-fingerprint")
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
object ThirdCreateMixPlaylistFingerprint : MethodFingerprint(
|
||||
opcodes = listOf(
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.CONST_4,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.IPUT_OBJECT
|
||||
),
|
||||
customFingerprint = { methodDef ->
|
||||
methodDef.implementation?.instructions?.any { instruction ->
|
||||
instruction.opcode.ordinal == Opcode.CONST.ordinal &&
|
||||
(instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.bottompaneloverlaytextLabelId
|
||||
} == true
|
||||
}
|
||||
)
|
@ -0,0 +1,64 @@
|
||||
package app.revanced.patches.youtube.layout.general.mixplaylists.bytecode.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.addInstruction
|
||||
import app.revanced.patcher.extensions.instruction
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patches.youtube.layout.general.mixplaylists.bytecode.fingerprints.*
|
||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.shared.extensions.injectHideCall
|
||||
import app.revanced.shared.util.bytecode.BytecodeHelper
|
||||
import org.jf.dexlib2.iface.instruction.formats.Instruction21c
|
||||
import org.jf.dexlib2.iface.instruction.Instruction
|
||||
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||
|
||||
@Name("hide-mix-playlists-bytecode-patch")
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class MixPlaylistsBytecodePatch : BytecodePatch(
|
||||
listOf(
|
||||
CreateMixPlaylistFingerprint,
|
||||
SecondCreateMixPlaylistFingerprint,
|
||||
ThirdCreateMixPlaylistFingerprint,
|
||||
FourthCreateMixPlaylistFingerprint
|
||||
)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
|
||||
arrayOf(CreateMixPlaylistFingerprint, SecondCreateMixPlaylistFingerprint).forEach(::addHook)
|
||||
ThirdCreateMixPlaylistFingerprint.hookMixPlaylists(true)
|
||||
FourthCreateMixPlaylistFingerprint.hookMixPlaylists(false)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
|
||||
private fun addHook(fingerprint: MethodFingerprint) {
|
||||
with (fingerprint.result!!) {
|
||||
val insertIndex = scanResult.patternScanResult!!.endIndex - 3
|
||||
|
||||
val register = (mutableMethod.instruction(insertIndex - 2) as OneRegisterInstruction).registerA
|
||||
|
||||
mutableMethod.implementation!!.injectHideCall(insertIndex, register, "layout/GeneralLayoutPatch", "hideMixPlaylists")
|
||||
}
|
||||
}
|
||||
|
||||
fun MethodFingerprint.hookMixPlaylists(isThirdFingerprint: Boolean) {
|
||||
fun getRegister(instruction: Instruction): Int {
|
||||
if (isThirdFingerprint) return (instruction as TwoRegisterInstruction).registerA
|
||||
return (instruction as Instruction21c).registerA
|
||||
}
|
||||
with(this.result!!) {
|
||||
val endIndex = scanResult.patternScanResult!!.endIndex
|
||||
val instruction = method.implementation!!.instructions.elementAt(endIndex)
|
||||
val register = getRegister(instruction)
|
||||
|
||||
mutableMethod.implementation!!.injectHideCall(endIndex, register, "layout/GeneralLayoutPatch", "hideMixPlaylists")
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package app.revanced.patches.youtube.layout.general.mixplaylists.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.ResourceContext
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patches.youtube.layout.general.mixplaylists.bytecode.patch.MixPlaylistsBytecodePatch
|
||||
import app.revanced.patches.youtube.misc.litho.filter.patch.LithoFilterPatch
|
||||
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.shared.util.resources.ResourceHelper
|
||||
|
||||
@Patch
|
||||
@Name("hide-mix-playlists")
|
||||
@Description("Removes mix playlists from home feed and video player.")
|
||||
@DependsOn(
|
||||
[
|
||||
LithoFilterPatch::class,
|
||||
MixPlaylistsBytecodePatch::class,
|
||||
SettingsPatch::class
|
||||
]
|
||||
)
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class MixPlaylistsPatch : ResourcePatch {
|
||||
override fun execute(context: ResourceContext): PatchResult {
|
||||
|
||||
/*
|
||||
add settings
|
||||
*/
|
||||
ResourceHelper.addSettings2(
|
||||
context,
|
||||
"PREFERENCE_CATEGORY: REVANCED_SETTINGS",
|
||||
"PREFERENCE: LAYOUT_SETTINGS",
|
||||
"PREFERENCE_HEADER: GENERAL",
|
||||
"SETTINGS: HIDE_MIX_PLAYLISTS"
|
||||
)
|
||||
|
||||
ResourceHelper.patchSuccess(
|
||||
context,
|
||||
"hide-mix-playlists"
|
||||
)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -1,10 +1,16 @@
|
||||
package app.revanced.patches.youtube.layout.personalinformation.bytecode.fingerprints
|
||||
package app.revanced.patches.youtube.layout.general.personalinformation.bytecode.fingerprints
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import app.revanced.patches.youtube.layout.personalinformation.resource.patch.HideEmailAddressResourcePatch
|
||||
import org.jf.dexlib2.Opcode
|
||||
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourcdIdPatch
|
||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
@Name("account-switcher-accessibility-label-fingerprint")
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
object AccountSwitcherAccessibilityLabelFingerprint : MethodFingerprint(
|
||||
opcodes = listOf(
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
@ -18,7 +24,7 @@ object AccountSwitcherAccessibilityLabelFingerprint : MethodFingerprint(
|
||||
customFingerprint = { methodDef ->
|
||||
methodDef.implementation?.instructions?.any { instruction ->
|
||||
instruction.opcode.ordinal == Opcode.CONST.ordinal &&
|
||||
(instruction as? WideLiteralInstruction)?.wideLiteral == HideEmailAddressResourcePatch.accountSwitcherAccessibilityLabelId
|
||||
(instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.accountSwitcherAccessibilityLabelId
|
||||
} == true
|
||||
}
|
||||
)
|
@ -1,6 +1,5 @@
|
||||
package app.revanced.patches.youtube.layout.personalinformation.bytecode.patch
|
||||
package app.revanced.patches.youtube.layout.general.personalinformation.bytecode.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
@ -9,22 +8,16 @@ import app.revanced.patcher.extensions.instruction
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
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.util.smali.ExternalLabel
|
||||
import app.revanced.patches.youtube.layout.personalinformation.annotations.HideEmailAddressCompatibility
|
||||
import app.revanced.patches.youtube.layout.personalinformation.bytecode.fingerprints.AccountSwitcherAccessibilityLabelFingerprint
|
||||
import app.revanced.patches.youtube.layout.personalinformation.resource.patch.HideEmailAddressResourcePatch
|
||||
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
||||
import app.revanced.patches.youtube.layout.general.personalinformation.bytecode.fingerprints.AccountSwitcherAccessibilityLabelFingerprint
|
||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.shared.util.integrations.Constants.GENERAL_LAYOUT
|
||||
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
|
||||
@Patch
|
||||
@DependsOn([IntegrationsPatch::class, HideEmailAddressResourcePatch::class])
|
||||
@Name("hide-email-address")
|
||||
@Description("Hides the email address in the account switcher.")
|
||||
@HideEmailAddressCompatibility
|
||||
@Name("hide-email-address-bytecode-patch")
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class HideEmailAddressPatch : BytecodePatch(
|
||||
class HideEmailAddressBytecodePatch : BytecodePatch(
|
||||
listOf(
|
||||
AccountSwitcherAccessibilityLabelFingerprint
|
||||
)
|
||||
@ -43,7 +36,7 @@ class HideEmailAddressPatch : BytecodePatch(
|
||||
|
||||
accountSwitcherAccessibilityLabelMethod.addInstructions(
|
||||
setVisibilityConstIndex, """
|
||||
invoke-static {v$setVisibilityConstRegister}, Lapp/revanced/integrations/patches/HideEmailAddressPatch;->hideEmailAddress(I)I
|
||||
invoke-static {v$setVisibilityConstRegister}, $GENERAL_LAYOUT->hideEmailAddress(I)I
|
||||
move-result v$setVisibilityConstRegister
|
||||
"""
|
||||
)
|
@ -0,0 +1,49 @@
|
||||
package app.revanced.patches.youtube.layout.general.personalinformation.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.ResourceContext
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patches.youtube.layout.general.personalinformation.bytecode.patch.HideEmailAddressBytecodePatch
|
||||
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.shared.util.resources.ResourceHelper
|
||||
|
||||
@Patch
|
||||
@Name("hide-email-address")
|
||||
@Description("Hides the email address in the account switcher.")
|
||||
@DependsOn(
|
||||
[
|
||||
HideEmailAddressBytecodePatch::class,
|
||||
SettingsPatch::class
|
||||
]
|
||||
)
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class HideEmailAddressPatch : ResourcePatch {
|
||||
override fun execute(context: ResourceContext): PatchResult {
|
||||
|
||||
/*
|
||||
add settings
|
||||
*/
|
||||
ResourceHelper.addSettings2(
|
||||
context,
|
||||
"PREFERENCE_CATEGORY: REVANCED_SETTINGS",
|
||||
"PREFERENCE: LAYOUT_SETTINGS",
|
||||
"PREFERENCE_HEADER: GENERAL",
|
||||
"SETTINGS: HIDE_EMAIL_ADDRESS"
|
||||
)
|
||||
|
||||
ResourceHelper.patchSuccess(
|
||||
context,
|
||||
"hide-email-address"
|
||||
)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package app.revanced.patches.youtube.layout.pivotbar.createbutton.fingerprints
|
||||
package app.revanced.patches.youtube.layout.general.pivotbar.createbutton.bytecode.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.Opcode
|
@ -0,0 +1,50 @@
|
||||
package app.revanced.patches.youtube.layout.general.pivotbar.createbutton.bytecode.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.MethodFingerprintExtensions.name
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultError
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patches.youtube.layout.general.pivotbar.createbutton.bytecode.fingerprints.PivotBarCreateButtonViewFingerprint
|
||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.shared.fingerprints.PivotBarFingerprint
|
||||
import app.revanced.shared.util.integrations.Constants.GENERAL_LAYOUT
|
||||
import app.revanced.shared.util.pivotbar.InjectionUtils.injectHook
|
||||
import app.revanced.shared.util.pivotbar.InjectionUtils.REGISTER_TEMPLATE_REPLACEMENT
|
||||
|
||||
@Name("hide-create-button-bytecode-patch")
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class CreateButtonRemoverBytecodePatch : BytecodePatch(
|
||||
listOf(PivotBarFingerprint)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
|
||||
/*
|
||||
* Resolve fingerprints
|
||||
*/
|
||||
|
||||
val pivotBarResult = PivotBarFingerprint.result ?: return PatchResultError("PivotBarFingerprint failed")
|
||||
|
||||
if (!PivotBarCreateButtonViewFingerprint.resolve(context, pivotBarResult.mutableMethod, pivotBarResult.mutableClass))
|
||||
return PatchResultError("${PivotBarCreateButtonViewFingerprint.name} failed")
|
||||
|
||||
val createButtonResult = PivotBarCreateButtonViewFingerprint.result!!
|
||||
val insertIndex = createButtonResult.scanResult.patternScanResult!!.endIndex
|
||||
|
||||
/*
|
||||
* Inject hooks
|
||||
*/
|
||||
|
||||
val hook =
|
||||
"invoke-static { v$REGISTER_TEMPLATE_REPLACEMENT }, $GENERAL_LAYOUT->hideCreateButton(Landroid/view/View;)V"
|
||||
|
||||
createButtonResult.mutableMethod.injectHook(hook, insertIndex)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package app.revanced.patches.youtube.layout.general.pivotbar.createbutton.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.ResourceContext
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patches.youtube.layout.general.pivotbar.createbutton.bytecode.patch.CreateButtonRemoverBytecodePatch
|
||||
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.shared.util.resources.ResourceHelper
|
||||
|
||||
@Patch
|
||||
@Name("hide-create-button")
|
||||
@Description("Hides the create button in the navigation bar.")
|
||||
@DependsOn(
|
||||
[
|
||||
CreateButtonRemoverBytecodePatch::class,
|
||||
SettingsPatch::class
|
||||
]
|
||||
)
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class CreateButtonRemoverPatch : ResourcePatch {
|
||||
override fun execute(context: ResourceContext): PatchResult {
|
||||
|
||||
/*
|
||||
add settings
|
||||
*/
|
||||
ResourceHelper.addSettings2(
|
||||
context,
|
||||
"PREFERENCE_CATEGORY: REVANCED_SETTINGS",
|
||||
"PREFERENCE: LAYOUT_SETTINGS",
|
||||
"PREFERENCE_HEADER: GENERAL",
|
||||
"SETTINGS: HIDE_CREATE_BUTTON"
|
||||
)
|
||||
|
||||
ResourceHelper.patchSuccess(
|
||||
context,
|
||||
"hide-create-button"
|
||||
)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package app.revanced.patches.youtube.layout.pivotbar.shortsbutton.fingerprints
|
||||
package app.revanced.patches.youtube.layout.general.pivotbar.shortsbutton.bytecode.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.Opcode
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user