From 18a66d8454cf6e7cfdd4183631a6870c80d16b90 Mon Sep 17 00:00:00 2001 From: j4k0xb <55899582+j4k0xb@users.noreply.github.com> Date: Sat, 16 Jul 2022 16:50:37 +0200 Subject: [PATCH] feat: `return-youtube-dislikes` patch (#175) * feat: ryd * refactor: use ryd patches class * feat: add video id dependency patch * fix: compatibility with 17.26.35 * refactor: named param variable, simpler mutableClass access --- .../annotations/RYDCompatibility.kt | 13 +++ .../fingerprints/DislikeFingerprint.kt | 25 ++++++ .../fingerprints/LikeFingerprint.kt | 25 ++++++ .../fingerprints/RemoveLikeFingerprint.kt | 25 ++++++ .../TextComponentSpecParentFingerprint.kt | 23 ++++++ .../returnyoutubedislikes/patch/RYDPatch.kt | 79 +++++++++++++++++++ .../annotation/VideoIdCompatibility.kt | 13 +++ .../videoid/fingerprint/VideoIdFingerprint.kt | 28 +++++++ .../misc/videoid/patch/VideoIdPatch.kt | 56 +++++++++++++ 9 files changed, 287 insertions(+) create mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislikes/annotations/RYDCompatibility.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislikes/fingerprints/DislikeFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislikes/fingerprints/LikeFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislikes/fingerprints/RemoveLikeFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislikes/fingerprints/TextComponentSpecParentFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislikes/patch/RYDPatch.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/videoid/annotation/VideoIdCompatibility.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/videoid/fingerprint/VideoIdFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/videoid/patch/VideoIdPatch.kt diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislikes/annotations/RYDCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislikes/annotations/RYDCompatibility.kt new file mode 100644 index 00000000..bb048dca --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislikes/annotations/RYDCompatibility.kt @@ -0,0 +1,13 @@ +package app.revanced.patches.youtube.layout.returnyoutubedislikes.annotations + +import app.revanced.patcher.annotation.Compatibility +import app.revanced.patcher.annotation.Package + +@Compatibility( + [Package( + "com.google.android.youtube", arrayOf("17.14.35", "17.26.35") + )] +) +@Target(AnnotationTarget.CLASS) +@Retention(AnnotationRetention.RUNTIME) +internal annotation class RYDCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislikes/fingerprints/DislikeFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislikes/fingerprints/DislikeFingerprint.kt new file mode 100644 index 00000000..06b33e4f --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislikes/fingerprints/DislikeFingerprint.kt @@ -0,0 +1,25 @@ +package app.revanced.patches.youtube.layout.returnyoutubedislikes.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.annotation.FuzzyPatternScanMethod +import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import app.revanced.patches.youtube.layout.returnyoutubedislikes.annotations.RYDCompatibility +import org.jf.dexlib2.AccessFlags + +@Name("dislike-fingerprint") +@MatchingMethod( + "Luqs;", "" +) +@FuzzyPatternScanMethod(2) +@RYDCompatibility +@Version("0.0.2") +object DislikeFingerprint : MethodFingerprint( + "V", + AccessFlags.PROTECTED or AccessFlags.CONSTRUCTOR, + null, + null, + listOf("like/dislike") +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislikes/fingerprints/LikeFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislikes/fingerprints/LikeFingerprint.kt new file mode 100644 index 00000000..cd086ec2 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislikes/fingerprints/LikeFingerprint.kt @@ -0,0 +1,25 @@ +package app.revanced.patches.youtube.layout.returnyoutubedislikes.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.annotation.FuzzyPatternScanMethod +import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import app.revanced.patches.youtube.layout.returnyoutubedislikes.annotations.RYDCompatibility +import org.jf.dexlib2.AccessFlags + +@Name("like-fingerprint") +@MatchingMethod( + "Luqt;", "" +) +@FuzzyPatternScanMethod(2) +@RYDCompatibility +@Version("0.0.2") +object LikeFingerprint : MethodFingerprint( + "V", + AccessFlags.PROTECTED or AccessFlags.CONSTRUCTOR, + null, + null, + listOf("like/like") +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislikes/fingerprints/RemoveLikeFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislikes/fingerprints/RemoveLikeFingerprint.kt new file mode 100644 index 00000000..797605f4 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislikes/fingerprints/RemoveLikeFingerprint.kt @@ -0,0 +1,25 @@ +package app.revanced.patches.youtube.layout.returnyoutubedislikes.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.annotation.FuzzyPatternScanMethod +import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import app.revanced.patches.youtube.layout.returnyoutubedislikes.annotations.RYDCompatibility +import org.jf.dexlib2.AccessFlags + +@Name("remove-like-fingerprint") +@MatchingMethod( + "Luqw;", "" +) +@FuzzyPatternScanMethod(2) +@RYDCompatibility +@Version("0.0.2") +object RemoveLikeFingerprint : MethodFingerprint( + "V", + AccessFlags.PROTECTED or AccessFlags.CONSTRUCTOR, + null, + null, + listOf("like/removelike") +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislikes/fingerprints/TextComponentSpecParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislikes/fingerprints/TextComponentSpecParentFingerprint.kt new file mode 100644 index 00000000..16843aa8 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislikes/fingerprints/TextComponentSpecParentFingerprint.kt @@ -0,0 +1,23 @@ +package app.revanced.patches.youtube.layout.returnyoutubedislikes.fingerprints + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.fingerprint.method.annotation.DirectPatternScanMethod +import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import app.revanced.patches.youtube.layout.returnyoutubedislikes.annotations.RYDCompatibility + +@Name("text-component-spec-parent-fingerprint") +@MatchingMethod( + "Lnvy;", "e" +) +@DirectPatternScanMethod +@RYDCompatibility +@Version("0.0.1") +object TextComponentSpecParentFingerprint : MethodFingerprint( + null, + null, + null, + null, + listOf("TextComponentSpec: No converter for extension: ") +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislikes/patch/RYDPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislikes/patch/RYDPatch.kt new file mode 100644 index 00000000..7ceaaf2b --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislikes/patch/RYDPatch.kt @@ -0,0 +1,79 @@ +package app.revanced.patches.youtube.layout.returnyoutubedislikes.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.impl.BytecodeData +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultError +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.annotations.Dependencies +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.impl.BytecodePatch +import app.revanced.patches.youtube.layout.returnyoutubedislikes.annotations.RYDCompatibility +import app.revanced.patches.youtube.layout.returnyoutubedislikes.fingerprints.TextComponentSpecParentFingerprint +import app.revanced.patches.youtube.layout.returnyoutubedislikes.fingerprints.DislikeFingerprint +import app.revanced.patches.youtube.layout.returnyoutubedislikes.fingerprints.LikeFingerprint +import app.revanced.patches.youtube.layout.returnyoutubedislikes.fingerprints.RemoveLikeFingerprint +import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch +import app.revanced.patches.youtube.misc.videoid.patch.VideoIdPatch + +@Patch +@Dependencies(dependencies = [IntegrationsPatch::class, VideoIdPatch::class]) +@Name("return-youtube-dislikes") +@Description("Shows the dislike count of videos.") +@RYDCompatibility +@Version("0.0.1") +class RYDPatch : BytecodePatch( + listOf( + TextComponentSpecParentFingerprint, LikeFingerprint, DislikeFingerprint, RemoveLikeFingerprint + ) +) { + override fun execute(data: BytecodeData): PatchResult { + LikeFingerprint.result!!.mutableMethod.addInstructions( + 0, + """ + const/4 v0, 1 + invoke-static {v0}, Lapp/revanced/integrations/patches/ReturnYouTubeDislikesPatch;->sendVote(I)V + """ + ) + DislikeFingerprint.result!!.mutableMethod.addInstructions( + 0, + """ + const/4 v0, -1 + invoke-static {v0}, Lapp/revanced/integrations/patches/ReturnYouTubeDislikesPatch;->sendVote(I)V + """ + ) + RemoveLikeFingerprint.result!!.mutableMethod.addInstructions( + 0, + """ + const/4 v0, 0 + invoke-static {v0}, Lapp/revanced/integrations/patches/ReturnYouTubeDislikesPatch;->sendVote(I)V + """ + ) + + VideoIdPatch.injectCall("Lapp/revanced/integrations/patches/ReturnYouTubeDislikesPatch;->newVideoLoaded(Ljava/lang/String;)V") + + val parentResult = TextComponentSpecParentFingerprint.result!! + val createComponentMethod = parentResult.mutableClass.methods.find { method -> + method.parameters.size >= 19 && method.parameterTypes.takeLast(4) + .all { param -> param == "Ljava/util/concurrent/atomic/AtomicReference;" } + } + ?: return PatchResultError("TextComponentSpec.createComponent not found") + + val conversionContextParam = 5 + val textRefParam = createComponentMethod.parameters.size - 2 + + createComponentMethod.addInstructions( + 0, + """ + move-object/from16 v0, p$conversionContextParam + move-object/from16 v1, p$textRefParam + invoke-static {v0, v1}, Lapp/revanced/integrations/patches/ReturnYouTubeDislikesPatch;->onComponentCreated(Ljava/lang/Object;Ljava/util/concurrent/atomic/AtomicReference;)V + """ + ) + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/videoid/annotation/VideoIdCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/videoid/annotation/VideoIdCompatibility.kt new file mode 100644 index 00000000..f8713604 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/videoid/annotation/VideoIdCompatibility.kt @@ -0,0 +1,13 @@ +package app.revanced.patches.youtube.misc.videoid.annotation + +import app.revanced.patcher.annotation.Compatibility +import app.revanced.patcher.annotation.Package + +@Compatibility( + [Package( + "com.google.android.youtube", arrayOf("17.14.35", "17.22.36", "17.26.35") + )] +) +@Target(AnnotationTarget.CLASS) +@Retention(AnnotationRetention.RUNTIME) +internal annotation class VideoIdCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/videoid/fingerprint/VideoIdFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/videoid/fingerprint/VideoIdFingerprint.kt new file mode 100644 index 00000000..13e7e18e --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/videoid/fingerprint/VideoIdFingerprint.kt @@ -0,0 +1,28 @@ +package app.revanced.patches.youtube.misc.videoid.fingerprint + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.annotation.DirectPatternScanMethod +import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import app.revanced.patches.youtube.misc.videoid.annotation.VideoIdCompatibility +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +@Name("video-id-fingerprint") +@MatchingMethod( + "Lcom/google/android/apps/youtube/app/common/player/PlaybackLifecycleMonitor;", "l" +) +@DirectPatternScanMethod +@VideoIdCompatibility +@Version("0.0.1") +object VideoIdFingerprint : MethodFingerprint( + "V", + AccessFlags.DECLARED_SYNCHRONIZED or AccessFlags.FINAL or AccessFlags.PUBLIC, + listOf("L"), + listOf(Opcode.INVOKE_INTERFACE), + customFingerprint = { + it.definingClass.endsWith("PlaybackLifecycleMonitor;") + } +) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/videoid/patch/VideoIdPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/videoid/patch/VideoIdPatch.kt new file mode 100644 index 00000000..028a3873 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/videoid/patch/VideoIdPatch.kt @@ -0,0 +1,56 @@ +package app.revanced.patches.youtube.misc.videoid.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.impl.BytecodeData +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.annotations.Dependencies +import app.revanced.patcher.patch.impl.BytecodePatch +import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch +import app.revanced.patches.youtube.misc.videoid.annotation.VideoIdCompatibility +import app.revanced.patches.youtube.misc.videoid.fingerprint.VideoIdFingerprint +import org.jf.dexlib2.iface.instruction.formats.Instruction11x + +@Name("video-id-hook") +@Description("hook to detect when the video id changes") +@VideoIdCompatibility +@Version("0.0.1") +@Dependencies(dependencies = [IntegrationsPatch::class]) +class VideoIdPatch : BytecodePatch( + listOf( + VideoIdFingerprint + ) +) { + override fun execute(data: BytecodeData): PatchResult { + injectCall("Lapp/revanced/integrations/videoplayer/VideoInformation;->setCurrentVideoId(Ljava/lang/String;)V") + + return PatchResultSuccess() + } + + companion object { + private var offset = 2 + + /** + * Adds an invoke-static instruction, called with the new id when the video changes + * @param methodDescriptor which method to call. Params have to be `Ljava/lang/String;` + */ + fun injectCall( + methodDescriptor: String + ) { + val result = VideoIdFingerprint.result!! + + val method = result.mutableMethod + val videoIdRegister = + (method.implementation!!.instructions[result.patternScanResult!!.endIndex + 1] as Instruction11x).registerA + method.addInstructions( + result.patternScanResult!!.endIndex + offset, // after the move-result-object + "invoke-static {v$videoIdRegister}, $methodDescriptor" + ) + offset++ // so additional instructions get added later + } + } +} +