bump v2.147.0

This commit is contained in:
inotia00
2022-12-23 17:49:31 +09:00
parent 74aecf4720
commit 187d905bdb
1034 changed files with 21004 additions and 11645 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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