mirror of
https://github.com/revanced/revanced-patches
synced 2024-09-01 12:05:35 +02:00
feat(YouTube - Return YouTube Dislike): Support version 18.43.45
and 18.44.41
(#3260)
Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
This commit is contained in:
parent
c7927e9e52
commit
70dee584ed
@ -8,7 +8,10 @@ import app.revanced.patcher.util.proxy.mutableTypes.MutableClass
|
|||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||||
import app.revanced.patches.shared.mapping.misc.ResourceMappingPatch
|
import app.revanced.patches.shared.mapping.misc.ResourceMappingPatch
|
||||||
import com.android.tools.smali.dexlib2.iface.Method
|
import com.android.tools.smali.dexlib2.iface.Method
|
||||||
|
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
|
||||||
|
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.WideLiteralInstruction
|
import com.android.tools.smali.dexlib2.iface.instruction.WideLiteralInstruction
|
||||||
|
import com.android.tools.smali.dexlib2.iface.reference.Reference
|
||||||
import com.android.tools.smali.dexlib2.util.MethodUtil
|
import com.android.tools.smali.dexlib2.util.MethodUtil
|
||||||
import org.w3c.dom.Node
|
import org.w3c.dom.Node
|
||||||
|
|
||||||
@ -102,4 +105,23 @@ fun BytecodeContext.traverseClassHierarchy(targetClass: MutableClass, callback:
|
|||||||
this.findClass(targetClass.superclass ?: return)?.mutableClass?.let {
|
this.findClass(targetClass.superclass ?: return)?.mutableClass?.let {
|
||||||
traverseClassHierarchy(it, callback)
|
traverseClassHierarchy(it, callback)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the [Reference] of an [Instruction] as [T].
|
||||||
|
*
|
||||||
|
* @param T The type of [Reference] to cast to.
|
||||||
|
* @return The [Reference] as [T] or null
|
||||||
|
* if the [Instruction] is not a [ReferenceInstruction] or the [Reference] is not of type [T].
|
||||||
|
* @see ReferenceInstruction
|
||||||
|
*/
|
||||||
|
fun <T : Reference> Instruction.getReference() = (this as? ReferenceInstruction)?.reference as? T
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the index of the first [Instruction] that matches the predicate.
|
||||||
|
*
|
||||||
|
* @param predicate The predicate to match.
|
||||||
|
* @return The index of the first [Instruction] that matches the predicate.
|
||||||
|
*/
|
||||||
|
fun Method.indexOfFirstInstruction(predicate: Instruction.() -> Boolean) =
|
||||||
|
this.implementation!!.instructions.indexOfFirst(predicate)
|
@ -1,6 +1,8 @@
|
|||||||
package app.revanced.patches.youtube.layout.returnyoutubedislike
|
package app.revanced.patches.youtube.layout.returnyoutubedislike
|
||||||
|
|
||||||
import app.revanced.extensions.exception
|
import app.revanced.extensions.exception
|
||||||
|
import app.revanced.extensions.getReference
|
||||||
|
import app.revanced.extensions.indexOfFirstInstruction
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
import app.revanced.patcher.data.BytecodeContext
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||||
@ -9,6 +11,7 @@ import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
|||||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||||
import app.revanced.patcher.patch.BytecodePatch
|
import app.revanced.patcher.patch.BytecodePatch
|
||||||
|
import app.revanced.patcher.patch.PatchException
|
||||||
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
||||||
import app.revanced.patcher.patch.annotation.Patch
|
import app.revanced.patcher.patch.annotation.Patch
|
||||||
import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.*
|
import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.*
|
||||||
@ -20,6 +23,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
|||||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||||
|
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||||
|
|
||||||
@Patch(
|
@Patch(
|
||||||
name = "Return YouTube Dislike",
|
name = "Return YouTube Dislike",
|
||||||
@ -34,8 +38,8 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
|||||||
compatiblePackages = [
|
compatiblePackages = [
|
||||||
CompatiblePackage(
|
CompatiblePackage(
|
||||||
"com.google.android.youtube", [
|
"com.google.android.youtube", [
|
||||||
"18.37.36",
|
"18.43.45",
|
||||||
"18.38.44"
|
"18.44.41",
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
@ -49,6 +53,8 @@ object ReturnYouTubeDislikePatch : BytecodePatch(
|
|||||||
LikeFingerprint,
|
LikeFingerprint,
|
||||||
DislikeFingerprint,
|
DislikeFingerprint,
|
||||||
RemoveLikeFingerprint,
|
RemoveLikeFingerprint,
|
||||||
|
RollingNumberSetterFingerprint,
|
||||||
|
RollingNumberTextViewFingerprint
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
private const val INTEGRATIONS_CLASS_DESCRIPTOR =
|
private const val INTEGRATIONS_CLASS_DESCRIPTOR =
|
||||||
@ -143,7 +149,77 @@ object ReturnYouTubeDislikePatch : BytecodePatch(
|
|||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
// region Hook for non litho Short videos.
|
// region Hook rolling numbers.
|
||||||
|
|
||||||
|
RollingNumberSetterFingerprint.result?.let {
|
||||||
|
val dislikesIndex = it.scanResult.patternScanResult!!.endIndex
|
||||||
|
|
||||||
|
it.mutableMethod.apply {
|
||||||
|
val insertIndex = 1
|
||||||
|
|
||||||
|
val charSequenceInstanceRegister =
|
||||||
|
getInstruction<OneRegisterInstruction>(0).registerA
|
||||||
|
val charSequenceFieldReference =
|
||||||
|
getInstruction<ReferenceInstruction>(dislikesIndex).reference.toString()
|
||||||
|
|
||||||
|
val registerCount = implementation!!.registerCount
|
||||||
|
|
||||||
|
// This register is being overwritten, so it is free to use.
|
||||||
|
val freeRegister = registerCount - 1
|
||||||
|
val conversionContextRegister = registerCount - parameters.size + 1
|
||||||
|
|
||||||
|
addInstructions(
|
||||||
|
insertIndex,
|
||||||
|
"""
|
||||||
|
iget-object v$freeRegister, v$charSequenceInstanceRegister, $charSequenceFieldReference
|
||||||
|
invoke-static {v$conversionContextRegister, v$freeRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->onRollingNumberLoaded(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/String;
|
||||||
|
move-result-object v$freeRegister
|
||||||
|
iput-object v$freeRegister, v$charSequenceInstanceRegister, $charSequenceFieldReference
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} ?: throw RollingNumberSetterFingerprint.exception
|
||||||
|
|
||||||
|
// The rolling number Span is missing styling since it's initially set as a String.
|
||||||
|
// Modify the UI text view and use the styled like/dislike Span.
|
||||||
|
RollingNumberTextViewFingerprint.result?.let {
|
||||||
|
// Initial TextView is set in this method.
|
||||||
|
val initiallyCreatedTextViewMethod = it.mutableMethod
|
||||||
|
|
||||||
|
// Videos less than 24 hours after uploaded, like counts will be updated in real time.
|
||||||
|
// Whenever like counts are updated, TextView is set in this method.
|
||||||
|
val realTimeUpdateTextViewMethod = it.mutableClass.methods.find { method ->
|
||||||
|
method.parameterTypes.first() == "Landroid/graphics/Bitmap;"
|
||||||
|
} ?: throw PatchException("Failed to find realTimeUpdateTextViewMethod")
|
||||||
|
|
||||||
|
arrayOf(
|
||||||
|
initiallyCreatedTextViewMethod,
|
||||||
|
realTimeUpdateTextViewMethod
|
||||||
|
).forEach { insertMethod ->
|
||||||
|
insertMethod.apply {
|
||||||
|
val setTextIndex = indexOfFirstInstruction {
|
||||||
|
getReference<MethodReference>()?.name == "setText"
|
||||||
|
}
|
||||||
|
|
||||||
|
val textViewRegister =
|
||||||
|
getInstruction<FiveRegisterInstruction>(setTextIndex).registerC
|
||||||
|
val textSpanRegister =
|
||||||
|
getInstruction<FiveRegisterInstruction>(setTextIndex).registerD
|
||||||
|
|
||||||
|
addInstructions(
|
||||||
|
setTextIndex,
|
||||||
|
"""
|
||||||
|
invoke-static {v$textViewRegister, v$textSpanRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->updateRollingNumber(Landroid/widget/TextView;Ljava/lang/CharSequence;)Ljava/lang/CharSequence;
|
||||||
|
move-result-object v$textSpanRegister
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} ?: throw RollingNumberTextViewFingerprint.exception
|
||||||
|
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region Hook for non-litho Short videos.
|
||||||
|
|
||||||
ShortsTextViewFingerprint.result?.let {
|
ShortsTextViewFingerprint.result?.let {
|
||||||
it.mutableMethod.apply {
|
it.mutableMethod.apply {
|
||||||
@ -172,7 +248,7 @@ object ReturnYouTubeDislikePatch : BytecodePatch(
|
|||||||
move-result v0
|
move-result v0
|
||||||
if-eqz v0, :ryd_disabled
|
if-eqz v0, :ryd_disabled
|
||||||
return-void
|
return-void
|
||||||
|
|
||||||
:is_like
|
:is_like
|
||||||
:ryd_disabled
|
:ryd_disabled
|
||||||
nop
|
nop
|
||||||
|
@ -0,0 +1,12 @@
|
|||||||
|
package app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints
|
||||||
|
|
||||||
|
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||||
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
|
||||||
|
object RollingNumberSetterFingerprint : MethodFingerprint(
|
||||||
|
opcodes = listOf(
|
||||||
|
Opcode.INVOKE_DIRECT,
|
||||||
|
Opcode.IGET_OBJECT
|
||||||
|
),
|
||||||
|
strings = listOf("RollingNumberType required properties missing! Need updateCount, fontName, color and fontSize.")
|
||||||
|
)
|
@ -0,0 +1,23 @@
|
|||||||
|
package app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints
|
||||||
|
|
||||||
|
import app.revanced.patcher.extensions.or
|
||||||
|
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||||
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
|
||||||
|
object RollingNumberTextViewFingerprint : MethodFingerprint(
|
||||||
|
returnType = "V",
|
||||||
|
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
|
parameters = listOf("L", "F", "F"),
|
||||||
|
opcodes = listOf(
|
||||||
|
Opcode.IPUT,
|
||||||
|
null, // invoke-direct or invoke-virtual
|
||||||
|
Opcode.IPUT_OBJECT,
|
||||||
|
Opcode.IGET_OBJECT,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.RETURN_VOID
|
||||||
|
),
|
||||||
|
customFingerprint = custom@{ _, classDef ->
|
||||||
|
classDef.superclass == "Landroid/support/v7/widget/AppCompatTextView;"
|
||||||
|
}
|
||||||
|
)
|
@ -12,7 +12,7 @@ object ShortsTextViewFingerprint : MethodFingerprint(
|
|||||||
opcodes = listOf(
|
opcodes = listOf(
|
||||||
Opcode.INVOKE_SUPER, // first instruction of method
|
Opcode.INVOKE_SUPER, // first instruction of method
|
||||||
Opcode.IF_NEZ,
|
Opcode.IF_NEZ,
|
||||||
Opcode.RETURN_VOID,
|
null,
|
||||||
Opcode.INVOKE_VIRTUAL,
|
Opcode.INVOKE_VIRTUAL,
|
||||||
Opcode.MOVE_RESULT_OBJECT,
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
Opcode.CHECK_CAST,
|
Opcode.CHECK_CAST,
|
||||||
|
@ -18,7 +18,7 @@ object TextComponentAtomicReferenceFingerprint : MethodFingerprint(
|
|||||||
Opcode.MOVE_OBJECT_FROM16,
|
Opcode.MOVE_OBJECT_FROM16,
|
||||||
Opcode.MOVE_OBJECT_FROM16,
|
Opcode.MOVE_OBJECT_FROM16,
|
||||||
Opcode.MOVE_OBJECT_FROM16,
|
Opcode.MOVE_OBJECT_FROM16,
|
||||||
Opcode.MOVE_OBJECT_FROM16,
|
null,
|
||||||
Opcode.INVOKE_VIRTUAL, // Register C is atomic reference
|
Opcode.INVOKE_VIRTUAL, // Register C is atomic reference
|
||||||
Opcode.MOVE_RESULT_OBJECT, // Register A is char sequence
|
Opcode.MOVE_RESULT_OBJECT, // Register A is char sequence
|
||||||
Opcode.CHECK_CAST,
|
Opcode.CHECK_CAST,
|
||||||
|
@ -21,6 +21,7 @@ object TextComponentContextFingerprint : MethodFingerprint(
|
|||||||
Opcode.IGET_OBJECT,
|
Opcode.IGET_OBJECT,
|
||||||
Opcode.IGET_OBJECT,
|
Opcode.IGET_OBJECT,
|
||||||
Opcode.IGET_OBJECT,
|
Opcode.IGET_OBJECT,
|
||||||
|
Opcode.IGET_OBJECT,
|
||||||
Opcode.IGET_OBJECT, // conversion context field name
|
Opcode.IGET_OBJECT, // conversion context field name
|
||||||
)
|
)
|
||||||
)
|
)
|
Loading…
Reference in New Issue
Block a user