diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/general/fingerprints/DislikeFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/general/fingerprints/DislikeFingerprint.kt new file mode 100644 index 000000000..282ff24a0 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/general/fingerprints/DislikeFingerprint.kt @@ -0,0 +1,8 @@ +package app.revanced.patches.youtube.misc.returnyoutubedislike.general.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint + +object DislikeFingerprint : MethodFingerprint( + returnType = "V", + strings = listOf("like/dislike") +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/general/fingerprints/LikeFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/general/fingerprints/LikeFingerprint.kt new file mode 100644 index 000000000..877dd4654 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/general/fingerprints/LikeFingerprint.kt @@ -0,0 +1,8 @@ +package app.revanced.patches.youtube.misc.returnyoutubedislike.general.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint + +object LikeFingerprint : MethodFingerprint( + returnType = "V", + strings = listOf("like/like") +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/general/fingerprints/RemoveLikeFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/general/fingerprints/RemoveLikeFingerprint.kt new file mode 100644 index 000000000..869ae1bfc --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/general/fingerprints/RemoveLikeFingerprint.kt @@ -0,0 +1,8 @@ +package app.revanced.patches.youtube.misc.returnyoutubedislike.general.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint + +object RemoveLikeFingerprint : MethodFingerprint( + returnType = "V", + strings = listOf("like/removelike") +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/general/fingerprints/TextComponentAtomicReferenceFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/general/fingerprints/TextComponentAtomicReferenceFingerprint.kt new file mode 100644 index 000000000..9d659e311 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/general/fingerprints/TextComponentAtomicReferenceFingerprint.kt @@ -0,0 +1,18 @@ +package app.revanced.patches.youtube.misc.returnyoutubedislike.general.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 TextComponentAtomicReferenceFingerprint : MethodFingerprint( + returnType = "L", + access = AccessFlags.PROTECTED or AccessFlags.FINAL, + parameters = listOf("L"), + opcodes = listOf( + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.MOVE_OBJECT + ) +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/general/fingerprints/TextComponentConstructorFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/general/fingerprints/TextComponentConstructorFingerprint.kt new file mode 100644 index 000000000..42497c86b --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/general/fingerprints/TextComponentConstructorFingerprint.kt @@ -0,0 +1,11 @@ +package app.revanced.patches.youtube.misc.returnyoutubedislike.general.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags + +object TextComponentConstructorFingerprint : MethodFingerprint( + returnType = "V", + access = AccessFlags.PRIVATE or AccessFlags.CONSTRUCTOR, + strings = listOf("TextComponent") +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/general/fingerprints/TextComponentContextFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/general/fingerprints/TextComponentContextFingerprint.kt new file mode 100644 index 000000000..7dc7ffef5 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/general/fingerprints/TextComponentContextFingerprint.kt @@ -0,0 +1,18 @@ +package app.revanced.patches.youtube.misc.returnyoutubedislike.general.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 TextComponentContextFingerprint : MethodFingerprint( + returnType = "L", + access = AccessFlags.PROTECTED or AccessFlags.FINAL, + parameters = listOf("L"), + opcodes = listOf( + Opcode.IGET_OBJECT, // conversion context + Opcode.IGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.IGET_BOOLEAN + ) +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/general/fingerprints/TextComponentTmpFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/general/fingerprints/TextComponentTmpFingerprint.kt new file mode 100644 index 000000000..5874e4d75 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/general/fingerprints/TextComponentTmpFingerprint.kt @@ -0,0 +1,16 @@ +package app.revanced.patches.youtube.misc.returnyoutubedislike.general.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 TextComponentTmpFingerprint : MethodFingerprint( + returnType = "L", + access = AccessFlags.PROTECTED or AccessFlags.FINAL, + parameters = listOf("L"), + opcodes = listOf( + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, // last instruction of the method + ) +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/general/patch/ReturnYouTubeDislikePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/general/patch/ReturnYouTubeDislikePatch.kt new file mode 100644 index 000000000..b8eb94430 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/general/patch/ReturnYouTubeDislikePatch.kt @@ -0,0 +1,143 @@ +package app.revanced.patches.youtube.misc.returnyoutubedislike.general.patch + +import app.revanced.extensions.toErrorResult +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.replaceInstructions +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.shared.annotation.YouTubeCompatibility +import app.revanced.patches.youtube.misc.returnyoutubedislike.general.fingerprints.* +import app.revanced.patches.youtube.misc.returnyoutubedislike.oldlayout.patch.ReturnYouTubeDislikeOldLayoutPatch +import app.revanced.patches.youtube.misc.returnyoutubedislike.shorts.patch.ReturnYouTubeDislikeShortsPatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.patches.youtube.misc.videoid.mainstream.patch.MainstreamVideoIdPatch +import app.revanced.util.integrations.Constants.UTILS_PATH +import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction +import org.jf.dexlib2.iface.instruction.ReferenceInstruction +import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction +import org.jf.dexlib2.iface.reference.Reference + +@Patch +@Name("return-youtube-dislike") +@Description("Shows the dislike count of videos using the Return YouTube Dislike API.") +@DependsOn( + [ + MainstreamVideoIdPatch::class, + ReturnYouTubeDislikeOldLayoutPatch::class, + ReturnYouTubeDislikeShortsPatch::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class ReturnYouTubeDislikePatch : BytecodePatch( + listOf( + DislikeFingerprint, + LikeFingerprint, + RemoveLikeFingerprint, + TextComponentConstructorFingerprint + ) +) { + override fun execute(context: BytecodeContext): PatchResult { + listOf( + LikeFingerprint.toPatch(Vote.LIKE), + DislikeFingerprint.toPatch(Vote.DISLIKE), + RemoveLikeFingerprint.toPatch(Vote.REMOVE_LIKE) + ).forEach { (fingerprint, vote) -> + with(fingerprint.result ?: return fingerprint.toErrorResult()) { + mutableMethod.addInstructions( + 0, + """ + const/4 v0, ${vote.value} + invoke-static {v0}, $INTEGRATIONS_RYD_CLASS_DESCRIPTOR->sendVote(I)V + """ + ) + } + } + + + TextComponentConstructorFingerprint.result?.let { parentResult -> + + TextComponentContextFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.let { + with (it.mutableMethod) { + val conversionContextIndex = it.scanResult.patternScanResult!!.startIndex + conversionContextFieldReference = + (instruction(conversionContextIndex) as ReferenceInstruction).reference + } + } ?: return TextComponentContextFingerprint.toErrorResult() + + TextComponentTmpFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.let { + with (it.mutableMethod) { + val startIndex = it.scanResult.patternScanResult!!.startIndex + tmpRegister = + (instruction(startIndex) as FiveRegisterInstruction).registerE + + } + } ?: return TextComponentTmpFingerprint.toErrorResult() + + + TextComponentAtomicReferenceFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.let { + with (it.mutableMethod) { + val atomicReferenceStartIndex = it.scanResult.patternScanResult!!.startIndex + val insertIndex = it.scanResult.patternScanResult!!.endIndex + val moveCharSequenceInstruction = instruction(insertIndex) as TwoRegisterInstruction + + val atomicReferenceRegister = + (instruction(atomicReferenceStartIndex) as FiveRegisterInstruction).registerC + + val charSequenceRegister = + moveCharSequenceInstruction.registerB + + replaceInstructions(insertIndex, "move-object/from16 v$tmpRegister, p0") + addInstructions( + insertIndex + 1, """ + iget-object v$tmpRegister, v$tmpRegister, $conversionContextFieldReference + invoke-static {v$tmpRegister, v$atomicReferenceRegister, v$charSequenceRegister}, $INTEGRATIONS_RYD_CLASS_DESCRIPTOR->onLithoTextLoaded(Ljava/lang/Object;Ljava/util/concurrent/atomic/AtomicReference;Ljava/lang/CharSequence;)Ljava/lang/CharSequence; + move-result-object v$charSequenceRegister + move-object v${moveCharSequenceInstruction.registerA}, v${charSequenceRegister} + """ + ) + } + } ?: return TextComponentAtomicReferenceFingerprint.toErrorResult() + } ?: return TextComponentConstructorFingerprint.toErrorResult() + + + MainstreamVideoIdPatch.injectCall("$INTEGRATIONS_RYD_CLASS_DESCRIPTOR->newVideoLoaded(Ljava/lang/String;)V") + + /* + * Add ReVanced Settings + */ + SettingsPatch.addReVancedPreference("ryd_settings") + + SettingsPatch.updatePatchStatus("return-youtube-dislike") + + return PatchResultSuccess() + } + private companion object { + const val INTEGRATIONS_RYD_CLASS_DESCRIPTOR = + "$UTILS_PATH/ReturnYouTubeDislikePatch;" + + lateinit var conversionContextFieldReference: Reference + var tmpRegister: Int = 12 + } + + private fun MethodFingerprint.toPatch(voteKind: Vote) = VotePatch(this, voteKind) + + private data class VotePatch(val fingerprint: MethodFingerprint, val voteKind: Vote) + + private enum class Vote(val value: Int) { + LIKE(1), + DISLIKE(-1), + REMOVE_LIKE(0) + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/oldlayout/fingerprints/ButtonTagFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/oldlayout/fingerprints/ButtonTagFingerprint.kt new file mode 100644 index 000000000..39d4d1ba4 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/oldlayout/fingerprints/ButtonTagFingerprint.kt @@ -0,0 +1,20 @@ +package app.revanced.patches.youtube.misc.returnyoutubedislike.oldlayout.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourceIdPatch +import org.jf.dexlib2.iface.instruction.WideLiteralInstruction +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +object ButtonTagFingerprint : MethodFingerprint( + returnType = "V", + access = AccessFlags.PUBLIC or AccessFlags.FINAL, + parameters = listOf("L"), + customFingerprint = { methodDef -> + methodDef.implementation?.instructions?.any { + it.opcode.ordinal == Opcode.CONST.ordinal && + (it as? WideLiteralInstruction)?.wideLiteral == SharedResourceIdPatch.dislikeButtonLabelId + } == true + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/oldlayout/fingerprints/ButtonTagOnClickFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/oldlayout/fingerprints/ButtonTagOnClickFingerprint.kt new file mode 100644 index 000000000..b46942e57 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/oldlayout/fingerprints/ButtonTagOnClickFingerprint.kt @@ -0,0 +1,14 @@ +package app.revanced.patches.youtube.misc.returnyoutubedislike.oldlayout.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.Opcode + +object ButtonTagOnClickFingerprint : MethodFingerprint( + returnType = "V", + parameters = listOf("L"), + opcodes = listOf( + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT + ), + customFingerprint = { it.name == "onClick" } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/oldlayout/fingerprints/SlimMetadataButtonParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/oldlayout/fingerprints/SlimMetadataButtonParentFingerprint.kt new file mode 100644 index 000000000..54bceafd6 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/oldlayout/fingerprints/SlimMetadataButtonParentFingerprint.kt @@ -0,0 +1,16 @@ +package app.revanced.patches.youtube.misc.returnyoutubedislike.oldlayout.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourceIdPatch +import org.jf.dexlib2.iface.instruction.WideLiteralInstruction +import org.jf.dexlib2.Opcode + +object SlimMetadataButtonParentFingerprint : MethodFingerprint( + returnType = "I", + customFingerprint = { methodDef -> + methodDef.implementation?.instructions?.any { + it.opcode.ordinal == Opcode.CONST.ordinal && + (it as? WideLiteralInstruction)?.wideLiteral == SharedResourceIdPatch.slimMetadataToggleButtonLabelId + } == true + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/oldlayout/fingerprints/SlimMetadataButtonTextFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/oldlayout/fingerprints/SlimMetadataButtonTextFingerprint.kt new file mode 100644 index 000000000..0caa2ed8d --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/oldlayout/fingerprints/SlimMetadataButtonTextFingerprint.kt @@ -0,0 +1,17 @@ +package app.revanced.patches.youtube.misc.returnyoutubedislike.oldlayout.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 SlimMetadataButtonTextFingerprint : MethodFingerprint( + returnType = "V", + access = AccessFlags.PUBLIC or AccessFlags.FINAL, + parameters = listOf(), + opcodes = listOf( + Opcode.INVOKE_VIRTUAL, + Opcode.IGET_OBJECT, + Opcode.IGET + ) +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/oldlayout/fingerprints/SlimMetadataButtonViewFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/oldlayout/fingerprints/SlimMetadataButtonViewFingerprint.kt new file mode 100644 index 000000000..471e403db --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/oldlayout/fingerprints/SlimMetadataButtonViewFingerprint.kt @@ -0,0 +1,16 @@ +package app.revanced.patches.youtube.misc.returnyoutubedislike.oldlayout.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 SlimMetadataButtonViewFingerprint : MethodFingerprint( + returnType = "L", + access = AccessFlags.PUBLIC or AccessFlags.FINAL, + parameters = listOf(), + opcodes = listOf( + Opcode.IGET_OBJECT, + Opcode.RETURN_OBJECT + ) +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/oldlayout/patch/ReturnYouTubeDislikeOldLayoutPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/oldlayout/patch/ReturnYouTubeDislikeOldLayoutPatch.kt new file mode 100644 index 000000000..e8a73707f --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/oldlayout/patch/ReturnYouTubeDislikeOldLayoutPatch.kt @@ -0,0 +1,124 @@ +package app.revanced.patches.youtube.misc.returnyoutubedislike.oldlayout.patch + +import app.revanced.extensions.toErrorResult +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.patch.annotations.DependsOn +import app.revanced.patches.shared.annotation.YouTubeCompatibility +import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourceIdPatch +import app.revanced.patches.youtube.misc.returnyoutubedislike.oldlayout.fingerprints.* +import app.revanced.util.integrations.Constants.UTILS_PATH +import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction +import org.jf.dexlib2.iface.instruction.OneRegisterInstruction +import org.jf.dexlib2.iface.instruction.ReferenceInstruction +import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction +import org.jf.dexlib2.iface.instruction.WideLiteralInstruction +import org.jf.dexlib2.iface.reference.Reference + +@Name("return-youtube-dislike-old-layout") +@DependsOn([SharedResourceIdPatch::class]) +@YouTubeCompatibility +@Version("0.0.1") +class ReturnYouTubeDislikeOldLayoutPatch : BytecodePatch( + listOf( + SlimMetadataButtonParentFingerprint, + ButtonTagFingerprint + ) +) { + override fun execute(context: BytecodeContext): PatchResult { + + SlimMetadataButtonParentFingerprint.result?.let { parentResult -> + + SlimMetadataButtonViewFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.let { + with (it.mutableMethod) { + val startIndex = it.scanResult.patternScanResult!!.startIndex + slimMetadataButtonViewFieldReference = + (instruction(startIndex) as ReferenceInstruction).reference + } + } ?: return SlimMetadataButtonViewFingerprint.toErrorResult() + + SlimMetadataButtonTextFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.let { + with (it.mutableMethod) { + val insertIndex = it.scanResult.patternScanResult!!.startIndex + val setTextInstruction = instruction(insertIndex) as FiveRegisterInstruction + + val tempRegister = + setTextInstruction.registerC + 1 + + val charSequenceRegister = + setTextInstruction.registerD + + addInstructions( + insertIndex, """ + iget-object v$tempRegister, p0, $slimMetadataButtonViewFieldReference + invoke-static {v$tempRegister, v$charSequenceRegister}, $INTEGRATIONS_RYD_CLASS_DESCRIPTOR->onSetText(Landroid/view/View;Ljava/lang/CharSequence;)Ljava/lang/CharSequence; + move-result-object v$charSequenceRegister + """ + ) + } + } ?: return SlimMetadataButtonTextFingerprint.toErrorResult() + } ?: return SlimMetadataButtonParentFingerprint.toErrorResult() + + + ButtonTagFingerprint.result?.let { parentResult -> + + ButtonTagOnClickFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.let { + with (it.mutableMethod) { + val startIndex = it.scanResult.patternScanResult!!.startIndex + getActiveBooleanFieldReference = + (instruction(startIndex) as ReferenceInstruction).reference + } + } ?: return ButtonTagOnClickFingerprint.toErrorResult() + + with (parentResult.mutableMethod.implementation!!.instructions) { + val dislikeButtonIndex = this.indexOfFirst { + (it as? WideLiteralInstruction)?.wideLiteral == SharedResourceIdPatch.dislikeButtonLabelId + } + + val dislikeButtonRegister = (elementAt(dislikeButtonIndex) as OneRegisterInstruction).registerA + + val dislikeButtonInstruction = elementAt(dislikeButtonIndex - 1) as TwoRegisterInstruction + + parentResult.mutableMethod.addInstructions( + dislikeButtonIndex, """ + invoke-virtual {v${dislikeButtonInstruction.registerB}}, $getActiveBooleanFieldReference + move-result v$dislikeButtonRegister + invoke-static {v${dislikeButtonInstruction.registerA}, v$dislikeButtonRegister}, $INTEGRATIONS_RYD_CLASS_DESCRIPTOR->setDislikeTag(Landroid/view/View;Z)V + """ + ) + + val likeButtonIndex = this.indexOfFirst { + (it as? WideLiteralInstruction)?.wideLiteral == SharedResourceIdPatch.likeButtonLabelId + } + + val likeButtonRegister = (elementAt(likeButtonIndex) as OneRegisterInstruction).registerA + + val likeButtonInstruction = elementAt(likeButtonIndex - 1) as TwoRegisterInstruction + + parentResult.mutableMethod.addInstructions( + likeButtonIndex, """ + invoke-virtual {v${likeButtonInstruction.registerB}}, $getActiveBooleanFieldReference + move-result v$likeButtonRegister + invoke-static {v${likeButtonInstruction.registerA}, v$likeButtonRegister}, $INTEGRATIONS_RYD_CLASS_DESCRIPTOR->setLikeTag(Landroid/view/View;Z)V + """ + ) + } + } ?: return ButtonTagFingerprint.toErrorResult() + + return PatchResultSuccess() + } + private companion object { + const val INTEGRATIONS_RYD_CLASS_DESCRIPTOR = + "$UTILS_PATH/ReturnYouTubeDislikePatch;" + + lateinit var slimMetadataButtonViewFieldReference: Reference + lateinit var getActiveBooleanFieldReference: Reference + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/shorts/fingerprints/ShortsTextComponentParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/shorts/fingerprints/ShortsTextComponentParentFingerprint.kt new file mode 100644 index 000000000..461f1c37c --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/shorts/fingerprints/ShortsTextComponentParentFingerprint.kt @@ -0,0 +1,23 @@ +package app.revanced.patches.youtube.misc.returnyoutubedislike.shorts.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.Opcode + +object ShortsTextComponentParentFingerprint : MethodFingerprint( + returnType = "V", + parameters = listOf("L", "L"), + opcodes = listOf( + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.GOTO, + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.RETURN_VOID, + Opcode.IGET_OBJECT, + Opcode.CHECK_CAST, + Opcode.IGET_BOOLEAN, + Opcode.IF_EQZ, + Opcode.INVOKE_STATIC + ) +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/shorts/patch/ReturnYouTubeDislikeShortsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/shorts/patch/ReturnYouTubeDislikeShortsPatch.kt new file mode 100644 index 000000000..5acac3b70 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/shorts/patch/ReturnYouTubeDislikeShortsPatch.kt @@ -0,0 +1,64 @@ +package app.revanced.patches.youtube.misc.returnyoutubedislike.shorts.patch + +import app.revanced.extensions.toErrorResult +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.addInstructions +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.shared.annotation.YouTubeCompatibility +import app.revanced.patches.youtube.misc.returnyoutubedislike.shorts.fingerprints.ShortsTextComponentParentFingerprint +import app.revanced.util.integrations.Constants.UTILS_PATH +import org.jf.dexlib2.iface.instruction.OneRegisterInstruction + +@Name("return-youtube-dislike-shorts") +@YouTubeCompatibility +@Version("0.0.1") +class ReturnYouTubeDislikeShortsPatch : BytecodePatch( + listOf( + ShortsTextComponentParentFingerprint + ) +) { + override fun execute(context: BytecodeContext): PatchResult { + ShortsTextComponentParentFingerprint.result?.let { + with (context + .toMethodWalker(it.method) + .nextMethod(it.scanResult.patternScanResult!!.endIndex, true) + .getMethod() as MutableMethod + ) { + val insertInstructions = this.implementation!!.instructions + val insertIndex = insertInstructions.size - 1 + val insertRegister = (insertInstructions.elementAt(insertIndex) as OneRegisterInstruction).registerA + + this.insertShorts(insertIndex, insertRegister) + } + + with (it.mutableMethod) { + val insertInstructions = this.implementation!!.instructions + val insertIndex = it.scanResult.patternScanResult!!.startIndex + 2 + val insertRegister = (insertInstructions.elementAt(insertIndex - 1) as OneRegisterInstruction).registerA + + this.insertShorts(insertIndex, insertRegister) + } + } ?: return ShortsTextComponentParentFingerprint.toErrorResult() + + return PatchResultSuccess() + } + private companion object { + const val INTEGRATIONS_RYD_CLASS_DESCRIPTOR = + "$UTILS_PATH/ReturnYouTubeDislikePatch;" + } + + private fun MutableMethod.insertShorts(index: Int, register: Int) { + addInstructions( + index, """ + invoke-static {v$register}, $INTEGRATIONS_RYD_CLASS_DESCRIPTOR->onShortsComponentCreated(Landroid/text/Spanned;)Landroid/text/Spanned; + move-result-object v$register + """ + ) + } +}