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
This commit is contained in:
j4k0xb 2022-07-16 16:50:37 +02:00 committed by GitHub
parent 23da1455b3
commit 18a66d8454
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 287 additions and 0 deletions

View file

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

View file

@ -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;", "<init>"
)
@FuzzyPatternScanMethod(2)
@RYDCompatibility
@Version("0.0.2")
object DislikeFingerprint : MethodFingerprint(
"V",
AccessFlags.PROTECTED or AccessFlags.CONSTRUCTOR,
null,
null,
listOf("like/dislike")
)

View file

@ -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;", "<init>"
)
@FuzzyPatternScanMethod(2)
@RYDCompatibility
@Version("0.0.2")
object LikeFingerprint : MethodFingerprint(
"V",
AccessFlags.PROTECTED or AccessFlags.CONSTRUCTOR,
null,
null,
listOf("like/like")
)

View file

@ -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;", "<init>"
)
@FuzzyPatternScanMethod(2)
@RYDCompatibility
@Version("0.0.2")
object RemoveLikeFingerprint : MethodFingerprint(
"V",
AccessFlags.PROTECTED or AccessFlags.CONSTRUCTOR,
null,
null,
listOf("like/removelike")
)

View file

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

View file

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

View file

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

View file

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

View file

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