diff --git a/src/main/kotlin/app/revanced/patches/shared/textcomponent/fingerprints/SpannableStringBuilderFingerprint.kt b/src/main/kotlin/app/revanced/patches/shared/fingerprints/SpannableStringBuilderFingerprint.kt similarity index 84% rename from src/main/kotlin/app/revanced/patches/shared/textcomponent/fingerprints/SpannableStringBuilderFingerprint.kt rename to src/main/kotlin/app/revanced/patches/shared/fingerprints/SpannableStringBuilderFingerprint.kt index 1d88bab534..840b13b712 100644 --- a/src/main/kotlin/app/revanced/patches/shared/textcomponent/fingerprints/SpannableStringBuilderFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/shared/fingerprints/SpannableStringBuilderFingerprint.kt @@ -1,7 +1,7 @@ -package app.revanced.patches.shared.textcomponent.fingerprints +package app.revanced.patches.shared.fingerprints import app.revanced.patcher.fingerprint.MethodFingerprint -import app.revanced.patches.shared.textcomponent.fingerprints.SpannableStringBuilderFingerprint.indexOfSpannableStringInstruction +import app.revanced.patches.shared.fingerprints.SpannableStringBuilderFingerprint.indexOfSpannableStringInstruction import app.revanced.util.getReference import app.revanced.util.indexOfFirstInstruction import com.android.tools.smali.dexlib2.Opcode diff --git a/src/main/kotlin/app/revanced/patches/shared/textcomponent/TextComponentPatch.kt b/src/main/kotlin/app/revanced/patches/shared/textcomponent/TextComponentPatch.kt index 44aa2ee80d..c9996f1f05 100644 --- a/src/main/kotlin/app/revanced/patches/shared/textcomponent/TextComponentPatch.kt +++ b/src/main/kotlin/app/revanced/patches/shared/textcomponent/TextComponentPatch.kt @@ -8,7 +8,7 @@ import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchException import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod -import app.revanced.patches.shared.textcomponent.fingerprints.SpannableStringBuilderFingerprint +import app.revanced.patches.shared.fingerprints.SpannableStringBuilderFingerprint import app.revanced.patches.shared.textcomponent.fingerprints.TextComponentConstructorFingerprint import app.revanced.patches.shared.textcomponent.fingerprints.TextComponentContextFingerprint import app.revanced.util.alsoResolve @@ -33,7 +33,8 @@ object TextComponentPatch : BytecodePatch( SpannableStringBuilderFingerprint.resultOrThrow().mutableMethod.apply { spannedMethod = this - spannedIndex = SpannableStringBuilderFingerprint.indexOfSpannableStringInstruction(this) + spannedIndex = + SpannableStringBuilderFingerprint.indexOfSpannableStringInstruction(this) spannedRegister = getInstruction(spannedIndex).registerC spannedContextRegister = getInstruction(0).registerA diff --git a/src/main/kotlin/app/revanced/patches/shared/textcomponent/fingerprints/InclusiveSpanFingerprint.kt b/src/main/kotlin/app/revanced/patches/shared/textcomponent/fingerprints/InclusiveSpanFingerprint.kt new file mode 100644 index 0000000000..ccb19a1fad --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/shared/textcomponent/fingerprints/InclusiveSpanFingerprint.kt @@ -0,0 +1,56 @@ +package app.revanced.patches.shared.textcomponent.fingerprints + +import app.revanced.patcher.fingerprint.MethodFingerprint +import app.revanced.patches.shared.textcomponent.fingerprints.InclusiveSpanFingerprint.STARTS_WITH_PARAMETER_LIST +import app.revanced.patches.shared.textcomponent.fingerprints.InclusiveSpanFingerprint.indexOfSetSpanInstruction +import app.revanced.util.getReference +import app.revanced.util.indexOfFirstInstructionReversed +import app.revanced.util.parametersEqual +import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.iface.Method +import com.android.tools.smali.dexlib2.iface.reference.MethodReference + +internal object InclusiveSpanFingerprint : MethodFingerprint( + returnType = "V", + // 19.14 and earlier parameters are: + // "Landroid/text/SpannableString;", + // "Ljava/lang/Object;", + // "I", + // "I" + + // 19.15+ parameters are: + // "Landroid/text/SpannableString;", + // "Ljava/lang/Object;", + // "I", + // "I", + // "Z" + customFingerprint = custom@{ methodDef, _ -> + val parameterTypes = methodDef.parameterTypes + val parameterSize = parameterTypes.size + if (parameterSize != 4 && parameterSize != 5) { + return@custom false + } + val startsWithMethodParameterList = parameterTypes.slice(0..3) + + if (!parametersEqual(STARTS_WITH_PARAMETER_LIST, startsWithMethodParameterList)) { + return@custom false + } + indexOfSetSpanInstruction(methodDef) >= 0 + }, +) { + internal const val SET_SPAN_METHOD_CALL = + "Landroid/text/SpannableString;->setSpan(Ljava/lang/Object;III)V" + + private val STARTS_WITH_PARAMETER_LIST = listOf( + "Landroid/text/SpannableString;", + "Ljava/lang/Object;", + "I", + "I" + ) + + fun indexOfSetSpanInstruction(methodDef: Method) = + methodDef.indexOfFirstInstructionReversed { + opcode == Opcode.INVOKE_VIRTUAL && + getReference().toString() == SET_SPAN_METHOD_CALL + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/player/comments/CommentsComponentPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/player/comments/CommentsComponentPatch.kt index 8add5c0f8a..e1009fa5e9 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/player/comments/CommentsComponentPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/player/comments/CommentsComponentPatch.kt @@ -4,21 +4,29 @@ import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.getInstruction +import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction +import app.revanced.patches.shared.fingerprints.SpannableStringBuilderFingerprint import app.revanced.patches.shared.litho.LithoFilterPatch +import app.revanced.patches.shared.textcomponent.TextComponentPatch import app.revanced.patches.youtube.player.comments.fingerprints.ShortsLiveStreamEmojiPickerOnClickListenerFingerprint import app.revanced.patches.youtube.player.comments.fingerprints.ShortsLiveStreamEmojiPickerOpacityFingerprint import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE import app.revanced.patches.youtube.utils.integrations.Constants.COMPONENTS_PATH import app.revanced.patches.youtube.utils.integrations.Constants.PLAYER_CLASS_DESCRIPTOR +import app.revanced.patches.youtube.utils.integrations.Constants.PLAYER_PATH import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch import app.revanced.patches.youtube.utils.settings.SettingsPatch +import app.revanced.util.getFiveRegisters +import app.revanced.util.getReference import app.revanced.util.getWalkerMethod import app.revanced.util.indexOfFirstInstructionOrThrow +import app.revanced.util.indexOfFirstInstructionReversedOrThrow import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow import app.revanced.util.patch.BaseBytecodePatch import app.revanced.util.resultOrThrow import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction +import com.android.tools.smali.dexlib2.iface.reference.MethodReference @Suppress("unused") object CommentsComponentPatch : BaseBytecodePatch( @@ -27,19 +35,59 @@ object CommentsComponentPatch : BaseBytecodePatch( dependencies = setOf( LithoFilterPatch::class, SettingsPatch::class, - SharedResourceIdPatch::class + SharedResourceIdPatch::class, + TextComponentPatch::class, ), compatiblePackages = COMPATIBLE_PACKAGE, fingerprints = setOf( ShortsLiveStreamEmojiPickerOnClickListenerFingerprint, - ShortsLiveStreamEmojiPickerOpacityFingerprint + ShortsLiveStreamEmojiPickerOpacityFingerprint, + SpannableStringBuilderFingerprint, ) ) { private const val FILTER_CLASS_DESCRIPTOR = "$COMPONENTS_PATH/CommentsFilter;" + private const val INTEGRATIONS_SEARCH_LINKS_CLASS_DESCRIPTOR = + "$PLAYER_PATH/SearchLinksPatch;" override fun execute(context: BytecodeContext) { + TextComponentPatch.hookSpannableString( + INTEGRATIONS_SEARCH_LINKS_CLASS_DESCRIPTOR, + "setConversionContext" + ) + + SpannableStringBuilderFingerprint.resultOrThrow().mutableMethod.apply { + val spannedIndex = + SpannableStringBuilderFingerprint.indexOfSpannableStringInstruction(this) + val setInclusiveSpanIndex = indexOfFirstInstructionOrThrow(spannedIndex) { + val reference = getReference() + opcode == Opcode.INVOKE_STATIC && + reference?.returnType == "V" && + reference.parameterTypes.size > 3 && + reference.parameterTypes.firstOrNull() == "Landroid/text/SpannableString;" + } + // In YouTube 18.29.38, YouTube 19.41.39, the target method is in class 'La;' + // 'getWalkerMethod' should be used until the dependency is updated to ReVanced Patcher 20+. + // https://github.com/ReVanced/revanced-patcher/issues/309 + val setInclusiveSpanMethod = + getWalkerMethod(context, setInclusiveSpanIndex) + + setInclusiveSpanMethod.apply { + val insertIndex = indexOfFirstInstructionReversedOrThrow { + opcode == Opcode.INVOKE_VIRTUAL && + getReference().toString() == "Landroid/text/SpannableString;->setSpan(Ljava/lang/Object;III)V" + } + replaceInstruction( + insertIndex, + "invoke-static { ${getFiveRegisters(insertIndex)} }, " + + INTEGRATIONS_SEARCH_LINKS_CLASS_DESCRIPTOR + + "->" + + "hideSearchLinks(Landroid/text/SpannableString;Ljava/lang/Object;III)V" + ) + } + } + // region patch for emoji picker button in shorts ShortsLiveStreamEmojiPickerOpacityFingerprint.resultOrThrow().let { diff --git a/src/main/kotlin/app/revanced/util/BytecodeUtils.kt b/src/main/kotlin/app/revanced/util/BytecodeUtils.kt index bb3ea6e8e7..f53f590af1 100644 --- a/src/main/kotlin/app/revanced/util/BytecodeUtils.kt +++ b/src/main/kotlin/app/revanced/util/BytecodeUtils.kt @@ -509,6 +509,16 @@ fun MutableMethod.getWalkerMethod(context: BytecodeContext, offset: Int): Mutabl } } +/** + * Taken from BiliRoamingX: + * https://github.com/BiliRoamingX/BiliRoamingX/blob/ae58109f3acdd53ec2d2b3fb439c2a2ef1886221/patches/src/main/kotlin/app/revanced/patches/bilibili/utils/Extenstions.kt#L151 + */ +fun MutableMethod.getFiveRegisters(index: Int) = + with (getInstruction(index)) { + arrayOf(registerC, registerD, registerE, registerF, registerG) + .take(registerCount).joinToString(",") { "v$it" } + } + fun BytecodeContext.addStaticFieldToIntegration( className: String, methodName: String, diff --git a/src/main/resources/youtube/settings/host/values/strings.xml b/src/main/resources/youtube/settings/host/values/strings.xml index 19dacf00a8..3fc103e247 100644 --- a/src/main/resources/youtube/settings/host/values/strings.xml +++ b/src/main/resources/youtube/settings/host/values/strings.xml @@ -791,6 +791,9 @@ Settings → Autoplay → Autoplay next video" Hide Comments by members banner Comments by members banner is hidden. Comments by members banner is shown. + Hide highlighted search links + Highlighted search links are hidden. + Highlighted search links are shown. Hide Comments section Comments section is hidden. Comments section is shown. diff --git a/src/main/resources/youtube/settings/xml/revanced_prefs.xml b/src/main/resources/youtube/settings/xml/revanced_prefs.xml index 7066e075cb..d1cccc9163 100644 --- a/src/main/resources/youtube/settings/xml/revanced_prefs.xml +++ b/src/main/resources/youtube/settings/xml/revanced_prefs.xml @@ -321,6 +321,7 @@ +