mirror of
https://github.com/ReVanced/revanced-patches.git
synced 2024-11-10 01:01:56 +01:00
feat(YouTube - Hide layout components): Filter home/search results by keywords (#2853)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
This commit is contained in:
parent
9a7f941ae4
commit
59162042b0
18 changed files with 311 additions and 196 deletions
|
@ -1609,6 +1609,13 @@ public final class app/revanced/patches/youtube/misc/minimizedplayback/Minimized
|
|||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/youtube/misc/navigation/NavigationBarHookPatch : app/revanced/patcher/patch/BytecodePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/youtube/misc/navigation/NavigationBarHookPatch;
|
||||
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
|
||||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
public final fun getHookNavigationButtonCreated ()Lkotlin/jvm/functions/Function1;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/youtube/misc/playercontrols/BottomControlsResourcePatch : app/revanced/patcher/patch/ResourcePatch, java/io/Closeable {
|
||||
public static final field INSTANCE Lapp/revanced/patches/youtube/misc/playercontrols/BottomControlsResourcePatch;
|
||||
public final fun addControls (Ljava/lang/String;)V
|
||||
|
|
|
@ -10,10 +10,10 @@ import app.revanced.patches.all.misc.resources.AddResourcesPatch
|
|||
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen
|
||||
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen.Sorting
|
||||
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||
import app.revanced.patches.youtube.layout.buttons.navigation.fingerprints.*
|
||||
import app.revanced.patches.youtube.layout.buttons.navigation.utils.InjectionUtils.REGISTER_TEMPLATE_REPLACEMENT
|
||||
import app.revanced.patches.youtube.layout.buttons.navigation.utils.InjectionUtils.injectHook
|
||||
import app.revanced.patches.youtube.layout.buttons.navigation.fingerprints.ANDROID_AUTOMOTIVE_STRING
|
||||
import app.revanced.patches.youtube.layout.buttons.navigation.fingerprints.AddCreateButtonViewFingerprint
|
||||
import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
|
||||
import app.revanced.patches.youtube.misc.navigation.NavigationBarHookPatch
|
||||
import app.revanced.patches.youtube.misc.settings.SettingsPatch
|
||||
import app.revanced.util.exception
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
|
@ -24,8 +24,8 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
|||
dependencies = [
|
||||
IntegrationsPatch::class,
|
||||
SettingsPatch::class,
|
||||
ResolvePivotBarFingerprintsPatch::class,
|
||||
AddResourcesPatch::class,
|
||||
NavigationBarHookPatch::class,
|
||||
],
|
||||
compatiblePackages = [
|
||||
CompatiblePackage(
|
||||
|
@ -47,7 +47,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
|||
"19.06.39",
|
||||
"19.07.40",
|
||||
"19.08.36",
|
||||
"19.09.37"
|
||||
"19.09.37",
|
||||
],
|
||||
),
|
||||
],
|
||||
|
@ -76,53 +76,7 @@ object NavigationButtonsPatch : BytecodePatch(
|
|||
),
|
||||
)
|
||||
|
||||
/*
|
||||
* Resolve fingerprints
|
||||
*/
|
||||
|
||||
val initializeButtonsResult = InitializeButtonsFingerprint.result!!
|
||||
|
||||
val fingerprintResults =
|
||||
arrayOf(PivotBarEnumFingerprint, PivotBarButtonsViewFingerprint)
|
||||
.onEach {
|
||||
if (!it.resolve(
|
||||
context,
|
||||
initializeButtonsResult.mutableMethod,
|
||||
initializeButtonsResult.mutableClass,
|
||||
)
|
||||
) {
|
||||
throw it.exception
|
||||
}
|
||||
}
|
||||
.map { it.result!!.scanResult.patternScanResult!! }
|
||||
|
||||
val enumScanResult = fingerprintResults[0]
|
||||
val buttonViewResult = fingerprintResults[1]
|
||||
|
||||
val enumHookInsertIndex = enumScanResult.startIndex + 2
|
||||
val buttonHookInsertIndex = buttonViewResult.endIndex
|
||||
|
||||
/*
|
||||
* Inject hooks
|
||||
*/
|
||||
|
||||
val enumHook = "sput-object v$REGISTER_TEMPLATE_REPLACEMENT, " +
|
||||
"$INTEGRATIONS_CLASS_DESCRIPTOR->lastNavigationButton:Ljava/lang/Enum;"
|
||||
val buttonHook = "invoke-static { v$REGISTER_TEMPLATE_REPLACEMENT }, " +
|
||||
"$INTEGRATIONS_CLASS_DESCRIPTOR->hideButton(Landroid/view/View;)V"
|
||||
|
||||
// Inject bottom to top to not mess up the indices
|
||||
mapOf(
|
||||
buttonHook to buttonHookInsertIndex,
|
||||
enumHook to enumHookInsertIndex,
|
||||
).forEach { (hook, insertIndex) ->
|
||||
initializeButtonsResult.mutableMethod.injectHook(hook, insertIndex)
|
||||
}
|
||||
|
||||
/*
|
||||
* Hide create or switch it with notifications buttons.
|
||||
*/
|
||||
|
||||
// Switch create with notifications button.
|
||||
AddCreateButtonViewFingerprint.result?.let {
|
||||
it.mutableMethod.apply {
|
||||
val stringIndex = it.scanResult.stringsScanResult!!.matches.find { match ->
|
||||
|
@ -130,7 +84,8 @@ object NavigationButtonsPatch : BytecodePatch(
|
|||
}!!.index
|
||||
|
||||
val conditionalCheckIndex = stringIndex - 1
|
||||
val conditionRegister = getInstruction<OneRegisterInstruction>(conditionalCheckIndex).registerA
|
||||
val conditionRegister =
|
||||
getInstruction<OneRegisterInstruction>(conditionalCheckIndex).registerA
|
||||
|
||||
addInstructions(
|
||||
conditionalCheckIndex,
|
||||
|
@ -142,26 +97,7 @@ object NavigationButtonsPatch : BytecodePatch(
|
|||
}
|
||||
} ?: throw AddCreateButtonViewFingerprint.exception
|
||||
|
||||
/*
|
||||
* Resolve fingerprints
|
||||
*/
|
||||
|
||||
InitializeButtonsFingerprint.result!!.let {
|
||||
if (!PivotBarCreateButtonViewFingerprint.resolve(context, it.mutableMethod, it.mutableClass)) {
|
||||
throw PivotBarCreateButtonViewFingerprint.exception
|
||||
}
|
||||
}
|
||||
|
||||
PivotBarCreateButtonViewFingerprint.result!!.apply {
|
||||
val insertIndex = scanResult.patternScanResult!!.endIndex
|
||||
|
||||
/*
|
||||
* Inject hooks
|
||||
*/
|
||||
val hook = "invoke-static { v$REGISTER_TEMPLATE_REPLACEMENT }, " +
|
||||
"$INTEGRATIONS_CLASS_DESCRIPTOR->hideCreateButton(Landroid/view/View;)V"
|
||||
|
||||
mutableMethod.injectHook(hook, insertIndex)
|
||||
}
|
||||
// Hook navigation button created, in order to hide them.
|
||||
NavigationBarHookPatch.hookNavigationButtonCreated(INTEGRATIONS_CLASS_DESCRIPTOR)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
package app.revanced.patches.youtube.layout.buttons.navigation
|
||||
|
||||
import app.revanced.util.exception
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchException
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch
|
||||
import app.revanced.patches.youtube.layout.buttons.navigation.fingerprints.InitializeButtonsFingerprint
|
||||
import app.revanced.patches.youtube.layout.buttons.navigation.fingerprints.PivotBarConstructorFingerprint
|
||||
|
||||
@Patch(
|
||||
description = "Resolves necessary fingerprints.",
|
||||
dependencies = [ResourceMappingPatch::class]
|
||||
)
|
||||
internal object ResolvePivotBarFingerprintsPatch : BytecodePatch(
|
||||
setOf(PivotBarConstructorFingerprint)
|
||||
) {
|
||||
internal var imageOnlyTabResourceId: Long = -1
|
||||
|
||||
override fun execute(context: BytecodeContext) {
|
||||
// imageOnlyTabResourceId is used in InitializeButtonsFingerprint fingerprint
|
||||
ResourceMappingPatch.resourceMappings.find { it.type == "layout" && it.name == "image_only_tab" }
|
||||
?.let { imageOnlyTabResourceId = it.id } ?: throw PatchException("Failed to find resource")
|
||||
|
||||
PivotBarConstructorFingerprint.result?.let {
|
||||
// Resolve InitializeButtonsFingerprint on the class of the method
|
||||
// which PivotBarConstructorFingerprint resolved to
|
||||
if (!InitializeButtonsFingerprint.resolve(
|
||||
context,
|
||||
it.classDef
|
||||
)
|
||||
) throw InitializeButtonsFingerprint.exception
|
||||
} ?: throw PivotBarConstructorFingerprint.exception
|
||||
}
|
||||
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
package app.revanced.patches.youtube.layout.buttons.navigation.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal object PivotBarButtonsViewFingerprint : MethodFingerprint(
|
||||
opcodes = listOf(
|
||||
Opcode.INVOKE_VIRTUAL_RANGE,
|
||||
Opcode.MOVE_RESULT_OBJECT, // target reference
|
||||
Opcode.GOTO,
|
||||
)
|
||||
)
|
|
@ -1,13 +0,0 @@
|
|||
package app.revanced.patches.youtube.layout.buttons.navigation.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal object PivotBarCreateButtonViewFingerprint : MethodFingerprint(
|
||||
opcodes = listOf(
|
||||
Opcode.INVOKE_DIRECT_RANGE,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_STATIC
|
||||
)
|
||||
)
|
|
@ -1,15 +0,0 @@
|
|||
package app.revanced.patches.youtube.layout.buttons.navigation.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal object PivotBarEnumFingerprint : MethodFingerprint(
|
||||
opcodes = listOf(
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.IF_NEZ, // target reference
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT,
|
||||
)
|
||||
)
|
|
@ -1,30 +0,0 @@
|
|||
package app.revanced.patches.youtube.layout.buttons.navigation.utils
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import com.android.tools.smali.dexlib2.Opcode.MOVE_RESULT_OBJECT
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
|
||||
internal object InjectionUtils {
|
||||
const val REGISTER_TEMPLATE_REPLACEMENT: String = "REGISTER_INDEX"
|
||||
|
||||
/**
|
||||
* Injects an instruction into insertIndex of the hook.
|
||||
* @param hook The hook to insert.
|
||||
* @param insertIndex The index to insert the instruction at.
|
||||
* [MOVE_RESULT_OBJECT] has to be the previous instruction before [insertIndex].
|
||||
*/
|
||||
fun MutableMethod.injectHook(hook: String, insertIndex: Int) {
|
||||
val injectTarget = this
|
||||
|
||||
// Register to pass to the hook
|
||||
val registerIndex = insertIndex - 1 // MOVE_RESULT_OBJECT is always the previous instruction
|
||||
val register = injectTarget.getInstruction<OneRegisterInstruction>(registerIndex).registerA
|
||||
|
||||
injectTarget.addInstruction(
|
||||
insertIndex,
|
||||
hook.replace("REGISTER_INDEX", register.toString()),
|
||||
)
|
||||
}
|
||||
}
|
|
@ -12,6 +12,7 @@ import app.revanced.patcher.patch.annotation.Patch
|
|||
import app.revanced.patcher.util.smali.ExternalLabel
|
||||
import app.revanced.patches.all.misc.resources.AddResourcesPatch
|
||||
import app.revanced.patches.shared.misc.settings.preference.InputType
|
||||
import app.revanced.patches.shared.misc.settings.preference.NonInteractivePreference
|
||||
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen
|
||||
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen.Sorting
|
||||
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||
|
@ -20,8 +21,10 @@ import app.revanced.patches.youtube.layout.hide.general.fingerprints.ParseElemen
|
|||
import app.revanced.patches.youtube.layout.hide.general.fingerprints.PlayerOverlayFingerprint
|
||||
import app.revanced.patches.youtube.layout.hide.general.fingerprints.ShowWatermarkFingerprint
|
||||
import app.revanced.patches.youtube.misc.litho.filter.LithoFilterPatch
|
||||
import app.revanced.patches.youtube.misc.navigation.NavigationBarHookPatch
|
||||
import app.revanced.patches.youtube.misc.playertype.PlayerTypeHookPatch
|
||||
import app.revanced.patches.youtube.misc.settings.SettingsPatch
|
||||
import app.revanced.util.exception
|
||||
import app.revanced.util.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||
|
@ -33,6 +36,8 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
|||
LithoFilterPatch::class,
|
||||
SettingsPatch::class,
|
||||
AddResourcesPatch::class,
|
||||
NavigationBarHookPatch::class,
|
||||
PlayerTypeHookPatch::class // Used by Keyword Content filter.
|
||||
],
|
||||
compatiblePackages = [
|
||||
CompatiblePackage(
|
||||
|
@ -69,6 +74,8 @@ object HideLayoutComponentsPatch : BytecodePatch(
|
|||
"Lapp/revanced/integrations/youtube/patches/components/DescriptionComponentsFilter;"
|
||||
private const val CUSTOM_FILTER_CLASS_NAME =
|
||||
"Lapp/revanced/integrations/youtube/patches/components/CustomFilter;"
|
||||
private const val KEYWORD_FILTER_CLASS_NAME =
|
||||
"Lapp/revanced/integrations/youtube/patches/components/KeywordContentFilter;"
|
||||
|
||||
override fun execute(context: BytecodeContext) {
|
||||
AddResourcesPatch(this::class)
|
||||
|
@ -117,6 +124,20 @@ object HideLayoutComponentsPatch : BytecodePatch(
|
|||
SwitchPreference("revanced_hide_search_result_shelf_header"),
|
||||
)
|
||||
|
||||
SettingsPatch.PreferenceScreen.FEED.addPreferences(
|
||||
PreferenceScreen(
|
||||
key = "revanced_hide_keyword_content_screen",
|
||||
sorting = Sorting.UNSORTED,
|
||||
preferences = setOf(
|
||||
SwitchPreference("revanced_hide_keyword_content_home"),
|
||||
SwitchPreference("revanced_hide_keyword_content_subscriptions"),
|
||||
SwitchPreference("revanced_hide_keyword_content_search"),
|
||||
TextPreference("revanced_hide_keyword_content_phrases", inputType = InputType.TEXT_MULTI_LINE),
|
||||
NonInteractivePreference("revanced_hide_keyword_content_about")
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
SettingsPatch.PreferenceScreen.GENERAL_LAYOUT.addPreferences(
|
||||
SwitchPreference("revanced_hide_gray_separator"),
|
||||
PreferenceScreen(
|
||||
|
@ -136,19 +157,19 @@ object HideLayoutComponentsPatch : BytecodePatch(
|
|||
|
||||
LithoFilterPatch.addFilter(LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR)
|
||||
LithoFilterPatch.addFilter(DESCRIPTION_COMPONENTS_FILTER_CLASS_NAME)
|
||||
LithoFilterPatch.addFilter(KEYWORD_FILTER_CLASS_NAME)
|
||||
LithoFilterPatch.addFilter(CUSTOM_FILTER_CLASS_NAME)
|
||||
|
||||
// region Mix playlists
|
||||
|
||||
ParseElementFromBufferFingerprint.result?.let { result ->
|
||||
val returnEmptyComponentInstruction =
|
||||
result.mutableMethod.getInstructions().last { it.opcode == Opcode.INVOKE_STATIC }
|
||||
ParseElementFromBufferFingerprint.resultOrThrow().let { result ->
|
||||
val consumeByteBufferIndex = result.scanResult.patternScanResult!!.startIndex
|
||||
|
||||
result.mutableMethod.apply {
|
||||
val consumeByteBufferIndex = result.scanResult.patternScanResult!!.startIndex
|
||||
val conversionContextRegister =
|
||||
getInstruction<TwoRegisterInstruction>(consumeByteBufferIndex - 2).registerA
|
||||
val byteBufferRegister = getInstruction<FiveRegisterInstruction>(consumeByteBufferIndex).registerD
|
||||
val returnEmptyComponentInstruction = getInstructions().last { it.opcode == Opcode.INVOKE_STATIC }
|
||||
|
||||
addInstructionsWithLabels(
|
||||
consumeByteBufferIndex,
|
||||
|
@ -160,15 +181,15 @@ object HideLayoutComponentsPatch : BytecodePatch(
|
|||
ExternalLabel("return_empty_component", returnEmptyComponentInstruction),
|
||||
)
|
||||
}
|
||||
} ?: throw ParseElementFromBufferFingerprint.exception
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region Watermark (legacy code for old versions of YouTube)
|
||||
|
||||
ShowWatermarkFingerprint.also {
|
||||
it.resolve(context, PlayerOverlayFingerprint.result?.classDef ?: throw PlayerOverlayFingerprint.exception)
|
||||
}.result?.mutableMethod?.apply {
|
||||
it.resolve(context, PlayerOverlayFingerprint.resultOrThrow().classDef)
|
||||
}.resultOrThrow().mutableMethod.apply {
|
||||
val index = implementation!!.instructions.size - 5
|
||||
|
||||
removeInstruction(index)
|
||||
|
@ -179,7 +200,7 @@ object HideLayoutComponentsPatch : BytecodePatch(
|
|||
move-result p2
|
||||
""",
|
||||
)
|
||||
} ?: throw ShowWatermarkFingerprint.exception
|
||||
}
|
||||
|
||||
// endregion
|
||||
}
|
||||
|
|
|
@ -0,0 +1,130 @@
|
|||
package app.revanced.patches.youtube.misc.navigation
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstructions
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchException
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
|
||||
import app.revanced.patches.youtube.misc.navigation.fingerprints.*
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstruction
|
||||
import app.revanced.util.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
import com.android.tools.smali.dexlib2.util.MethodUtil
|
||||
|
||||
@Patch(
|
||||
description = "Hooks the active navigation or search bar.",
|
||||
dependencies = [
|
||||
IntegrationsPatch::class,
|
||||
NavigationBarHookResourcePatch::class,
|
||||
],
|
||||
)
|
||||
@Suppress("unused")
|
||||
object NavigationBarHookPatch : BytecodePatch(
|
||||
setOf(
|
||||
PivotBarConstructorFingerprint,
|
||||
NavigationEnumFingerprint,
|
||||
PivotBarButtonsCreateDrawableViewFingerprint,
|
||||
PivotBarButtonsCreateResourceViewFingerprint,
|
||||
NavigationBarHookCallbackFingerprint,
|
||||
ActionBarSearchResultsFingerprint,
|
||||
),
|
||||
) {
|
||||
internal const val INTEGRATIONS_CLASS_DESCRIPTOR =
|
||||
"Lapp/revanced/integrations/youtube/shared/NavigationBar;"
|
||||
|
||||
internal const val INTEGRATIONS_NAVIGATION_BUTTON_DESCRIPTOR =
|
||||
"Lapp/revanced/integrations/youtube/shared/NavigationBar\$NavigationButton;"
|
||||
|
||||
override fun execute(context: BytecodeContext) {
|
||||
fun MutableMethod.addHook(hook: Hook, insertPredicate: Instruction.() -> Boolean) {
|
||||
val filtered = getInstructions().filter(insertPredicate)
|
||||
if (filtered.isEmpty()) throw PatchException("Could not find insert indexes")
|
||||
filtered.forEach {
|
||||
val insertIndex = it.location.index + 2
|
||||
val register = getInstruction<OneRegisterInstruction>(insertIndex - 1).registerA
|
||||
|
||||
addInstruction(
|
||||
insertIndex,
|
||||
"invoke-static { v$register }, " +
|
||||
"$INTEGRATIONS_CLASS_DESCRIPTOR->${hook.methodName}(${hook.parameters})V",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
InitializeButtonsFingerprint.apply {
|
||||
resolve(context, PivotBarConstructorFingerprint.resultOrThrow().classDef)
|
||||
}.resultOrThrow().mutableMethod.apply {
|
||||
// Hook the current navigation bar enum value. Note, the 'You' tab does not have an enum value.
|
||||
val navigationEnumClassName = NavigationEnumFingerprint.resultOrThrow().mutableClass.type
|
||||
addHook(Hook.SET_LAST_APP_NAVIGATION_ENUM) {
|
||||
opcode == Opcode.INVOKE_STATIC &&
|
||||
getReference<MethodReference>()?.definingClass == navigationEnumClassName
|
||||
}
|
||||
|
||||
// Hook the creation of navigation tab views.
|
||||
val drawableTabMethod = PivotBarButtonsCreateDrawableViewFingerprint.resultOrThrow().mutableMethod
|
||||
addHook(Hook.NAVIGATION_TAB_LOADED) predicate@{
|
||||
MethodUtil.methodSignaturesMatch(
|
||||
getReference<MethodReference>() ?: return@predicate false,
|
||||
drawableTabMethod,
|
||||
)
|
||||
}
|
||||
|
||||
val imageResourceTabMethod = PivotBarButtonsCreateResourceViewFingerprint.resultOrThrow().method
|
||||
addHook(Hook.NAVIGATION_IMAGE_RESOURCE_TAB_LOADED) predicate@{
|
||||
MethodUtil.methodSignaturesMatch(
|
||||
getReference<MethodReference>() ?: return@predicate false,
|
||||
imageResourceTabMethod,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Hook the search bar.
|
||||
|
||||
// Two different layouts are used at the hooked code.
|
||||
// Insert before the first ViewGroup method call after inflating,
|
||||
// so this works regardless which layout is used.
|
||||
ActionBarSearchResultsFingerprint.resultOrThrow().mutableMethod.apply {
|
||||
val instructionIndex = indexOfFirstInstruction {
|
||||
opcode == Opcode.INVOKE_VIRTUAL && getReference<MethodReference>()?.name == "setLayoutDirection"
|
||||
}
|
||||
|
||||
val viewRegister = getInstruction<FiveRegisterInstruction>(instructionIndex).registerC
|
||||
|
||||
addInstruction(
|
||||
instructionIndex,
|
||||
"invoke-static { v$viewRegister }, " +
|
||||
"$INTEGRATIONS_CLASS_DESCRIPTOR->searchBarResultsViewLoaded(Landroid/view/View;)V",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val hookNavigationButtonCreated: (String) -> Unit by lazy {
|
||||
val method = NavigationBarHookCallbackFingerprint.resultOrThrow().mutableMethod
|
||||
|
||||
{ integrationsClassDescriptor ->
|
||||
method.addInstruction(
|
||||
0,
|
||||
"invoke-static { p0, p1 }, " +
|
||||
"$integrationsClassDescriptor->navigationTabCreated" +
|
||||
"(${INTEGRATIONS_NAVIGATION_BUTTON_DESCRIPTOR}Landroid/view/View;)V",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private enum class Hook(val methodName: String, val parameters: String) {
|
||||
SET_LAST_APP_NAVIGATION_ENUM("setLastAppNavigationEnum", "Ljava/lang/Enum;"),
|
||||
NAVIGATION_TAB_LOADED("navigationTabLoaded", "Landroid/view/View;"),
|
||||
NAVIGATION_IMAGE_RESOURCE_TAB_LOADED("navigationImageResourceTabLoaded", "Landroid/view/View;"),
|
||||
SEARCH_BAR_RESULTS_VIEW_LOADED("searchBarResultsViewLoaded", "Landroid/view/View;"),
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package app.revanced.patches.youtube.misc.navigation
|
||||
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch
|
||||
|
||||
@Patch(
|
||||
dependencies = [ResourceMappingPatch::class]
|
||||
)
|
||||
internal object NavigationBarHookResourcePatch : ResourcePatch() {
|
||||
internal var imageOnlyTabResourceId: Long = -1
|
||||
internal var actionBarSearchResultsViewMicId: Long = -1
|
||||
|
||||
override fun execute(context: ResourceContext) {
|
||||
imageOnlyTabResourceId = ResourceMappingPatch.resourceMappings.first {
|
||||
it.type == "layout" && it.name == "image_only_tab"
|
||||
}.id
|
||||
|
||||
actionBarSearchResultsViewMicId = ResourceMappingPatch.resourceMappings.first {
|
||||
it.type == "layout" && it.name == "action_bar_search_results_view_mic"
|
||||
}.id
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package app.revanced.patches.youtube.misc.navigation.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patches.youtube.misc.navigation.NavigationBarHookResourcePatch
|
||||
import app.revanced.util.patch.LiteralValueFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
internal object ActionBarSearchResultsFingerprint : LiteralValueFingerprint(
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
returnType = "Landroid/view/View;",
|
||||
parameters = listOf("Landroid/view/LayoutInflater;"),
|
||||
literalSupplier = { NavigationBarHookResourcePatch.actionBarSearchResultsViewMicId }
|
||||
)
|
|
@ -1,13 +1,16 @@
|
|||
package app.revanced.patches.youtube.layout.buttons.navigation.fingerprints
|
||||
package app.revanced.patches.youtube.misc.navigation.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patches.youtube.layout.buttons.navigation.ResolvePivotBarFingerprintsPatch
|
||||
import app.revanced.patches.youtube.misc.navigation.NavigationBarHookResourcePatch
|
||||
import app.revanced.util.patch.LiteralValueFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
/**
|
||||
* Resolves to the class found in [PivotBarConstructorFingerprint].
|
||||
*/
|
||||
internal object InitializeButtonsFingerprint : LiteralValueFingerprint(
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
returnType = "V",
|
||||
parameters = listOf(),
|
||||
literalSupplier = { ResolvePivotBarFingerprintsPatch.imageOnlyTabResourceId }
|
||||
literalSupplier = { NavigationBarHookResourcePatch.imageOnlyTabResourceId }
|
||||
)
|
|
@ -0,0 +1,21 @@
|
|||
package app.revanced.patches.youtube.misc.navigation.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import app.revanced.patches.youtube.layout.buttons.navigation.NavigationButtonsPatch
|
||||
import app.revanced.patches.youtube.misc.navigation.NavigationBarHookPatch
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
/**
|
||||
* Integrations method, used for callback into to other patches.
|
||||
* Specifically, [NavigationButtonsPatch].
|
||||
*/
|
||||
internal object NavigationBarHookCallbackFingerprint : MethodFingerprint(
|
||||
accessFlags = AccessFlags.PRIVATE or AccessFlags.STATIC,
|
||||
returnType = "V",
|
||||
parameters = listOf(NavigationBarHookPatch.INTEGRATIONS_NAVIGATION_BUTTON_DESCRIPTOR, "Landroid/view/View;"),
|
||||
customFingerprint = { methodDef, _ ->
|
||||
methodDef.name == "navigationTabCreatedCallback" &&
|
||||
methodDef.definingClass == NavigationBarHookPatch.INTEGRATIONS_CLASS_DESCRIPTOR
|
||||
},
|
||||
)
|
|
@ -0,0 +1,21 @@
|
|||
package app.revanced.patches.youtube.misc.navigation.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
/**
|
||||
* Resolves to the Enum class that looks up ordinal -> instance.
|
||||
*/
|
||||
internal object NavigationEnumFingerprint : MethodFingerprint(
|
||||
accessFlags = AccessFlags.STATIC or AccessFlags.CONSTRUCTOR,
|
||||
strings = listOf(
|
||||
"PIVOT_HOME",
|
||||
"TAB_SHORTS",
|
||||
"CREATION_TAB_LARGE",
|
||||
"PIVOT_SUBSCRIPTIONS",
|
||||
"TAB_ACTIVITY",
|
||||
"VIDEO_LIBRARY_WHITE",
|
||||
"INCOGNITO_CIRCLE"
|
||||
)
|
||||
)
|
|
@ -0,0 +1,17 @@
|
|||
package app.revanced.patches.youtube.misc.navigation.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
internal object PivotBarButtonsCreateDrawableViewFingerprint : MethodFingerprint(
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
// Method has different number of parameters in some app targets.
|
||||
// Parameters are checked in custom fingerprint.
|
||||
returnType = "Landroid/view/View;",
|
||||
customFingerprint = { methodDef, classDef ->
|
||||
classDef.type == "Lcom/google/android/libraries/youtube/rendering/ui/pivotbar/PivotBar;" &&
|
||||
// Only one method has a Drawable parameter.
|
||||
methodDef.parameterTypes.firstOrNull() == "Landroid/graphics/drawable/Drawable;"
|
||||
}
|
||||
)
|
|
@ -0,0 +1,14 @@
|
|||
package app.revanced.patches.youtube.misc.navigation.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
internal object PivotBarButtonsCreateResourceViewFingerprint : MethodFingerprint(
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = listOf("L", "Z", "I", "L"),
|
||||
returnType = "Landroid/view/View;",
|
||||
customFingerprint = { _, classDef ->
|
||||
classDef.type == "Lcom/google/android/libraries/youtube/rendering/ui/pivotbar/PivotBar;"
|
||||
}
|
||||
)
|
|
@ -1,4 +1,4 @@
|
|||
package app.revanced.patches.youtube.layout.buttons.navigation.fingerprints
|
||||
package app.revanced.patches.youtube.misc.navigation.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
|
@ -167,9 +167,24 @@
|
|||
<string name="revanced_custom_filter_summary_off">Custom filter is disabled</string>
|
||||
<string name="revanced_custom_filter_strings_title">Custom filter</string>
|
||||
<string name="revanced_custom_filter_strings_summary">List of component path builder strings to filter separated by new line</string>
|
||||
<string name="revanced_custom_filter_toast_invalid_characters">Invalid custom filter (must be ASCII only): %s</string>
|
||||
<string name="revanced_custom_filter_toast_invalid_syntax">Invalid custom filter: %s</string>
|
||||
<string name="revanced_custom_filter_toast_reset">Custom filter reset to default</string>
|
||||
<string name="revanced_hide_keyword_content_screen_title">Hide keyword content</string>
|
||||
<string name="revanced_hide_keyword_content_screen_summary">Hide search and feed videos using keyword filters</string>
|
||||
<string name="revanced_hide_keyword_content_home_title">Hide home videos by keywords</string>
|
||||
<string name="revanced_hide_keyword_content_home_summary_on">Videos in the home tab are filtered by keywords</string>
|
||||
<string name="revanced_hide_keyword_content_home_summary_off">Videos in the home tab are not filtered by keywords</string>
|
||||
<string name="revanced_hide_keyword_content_subscriptions_title">Hide subscription videos by keywords</string>x
|
||||
<string name="revanced_hide_keyword_content_subscriptions_summary_on">Videos in the subscriptions tab are filtered by keywords</string>
|
||||
<string name="revanced_hide_keyword_content_subscriptions_summary_off">Videos in the subscriptions tab are not filtered by keywords</string>
|
||||
<string name="revanced_hide_keyword_content_search_title">Hide search results by keywords</string>
|
||||
<string name="revanced_hide_keyword_content_search_summary_on">Search results are filtered by keywords</string>
|
||||
<string name="revanced_hide_keyword_content_search_summary_off">Search results are not filtered by keywords</string>
|
||||
<string name="revanced_hide_keyword_content_phrases_title">Keywords to hide</string>
|
||||
<string name="revanced_hide_keyword_content_phrases_summary">Keywords and phrases to hide, separated by new lines\n\nWords with uppercase letters in the middle must be entered with the casing (ie: iPhone, TikTok, LeBlanc)</string>
|
||||
<string name="revanced_hide_keyword_content_about_title">About keyword filtering</string>
|
||||
<string name="revanced_hide_keyword_content_about_summary">Home/Subscription/Search results are filtered to hide content that matches keyword phrases\n\nLimitations\n• Some Shorts may not be hidden\n• Some UI components may not be hidden\n• Searching for a keyword may show no results</string>
|
||||
<string name="revanced_hide_keyword_toast_invalid_common" formatted="false">Invalid keyword. Cannot use: \'%s\' as a filter</string>
|
||||
<string name="revanced_hide_keyword_toast_invalid_length" formatted="false">Invalid keyword. \'%s\' is less than %s characters</string>
|
||||
</patch>
|
||||
<patch id="ad.general.HideAdsResourcePatch">
|
||||
<string name="revanced_hide_general_ads_title">Hide general ads</string>
|
||||
|
|
Loading…
Reference in a new issue