mirror of
https://github.com/inotia00/revanced-patches.git
synced 2025-05-22 19:09:12 +02:00
feat(reddit): add reddit patches
This commit is contained in:
parent
2f7cdc86c8
commit
10733c7a19
@ -0,0 +1,44 @@
|
||||
package app.revanced.patches.reddit.ad.banner.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
|
||||
@Name("hide-subreddit-banner")
|
||||
@Description("Hides banner ads from comments on subreddits.")
|
||||
@Version("0.0.1")
|
||||
class HideBannerPatch : ResourcePatch {
|
||||
override fun execute(context: ResourceContext): PatchResult {
|
||||
context.xmlEditor[RESOURCE_FILE_PATH].use {
|
||||
it.file.getElementsByTagName("merge").item(0).childNodes.apply {
|
||||
val attributes = arrayOf("height", "width")
|
||||
|
||||
for (i in 1 until length) {
|
||||
val view = item(i)
|
||||
if (
|
||||
view.hasAttributes() &&
|
||||
view.attributes.getNamedItem("android:id").nodeValue.endsWith("ad_view_stub")
|
||||
) {
|
||||
attributes.forEach { attribute ->
|
||||
view.attributes.getNamedItem("android:layout_$attribute").nodeValue =
|
||||
"0.0dip"
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val RESOURCE_FILE_PATH = "res/layout/merge_listheader_link_detail.xml"
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,11 @@
|
||||
package app.revanced.patches.reddit.ad.comments.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
|
||||
object HideCommentAdsFingerprint : MethodFingerprint(
|
||||
returnType = "Ljava/lang/Object;",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
customFingerprint = { it, _ -> it.definingClass.endsWith("RedditCommentsPageAdRepository;") },
|
||||
)
|
@ -0,0 +1,38 @@
|
||||
package app.revanced.patches.reddit.ad.comments.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.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.annotations.RequiresIntegrations
|
||||
import app.revanced.patches.reddit.ad.comments.fingerprints.HideCommentAdsFingerprint
|
||||
|
||||
@Name("hide-comment-ads")
|
||||
@Description("Removes all comment ads.")
|
||||
@RequiresIntegrations
|
||||
@Version("0.0.1")
|
||||
class HideCommentAdsPatch : BytecodePatch(
|
||||
listOf(HideCommentAdsFingerprint)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
HideCommentAdsFingerprint.result?.let {
|
||||
it.mutableMethod.apply {
|
||||
addInstructions(
|
||||
0,
|
||||
"""
|
||||
new-instance v0, Ljava/lang/Object;
|
||||
invoke-direct {v0}, Ljava/lang/Object;-><init>()V
|
||||
return-object v0
|
||||
"""
|
||||
)
|
||||
}
|
||||
} ?: return HideCommentAdsFingerprint.toErrorResult()
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package app.revanced.patches.reddit.ad.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 AdPostFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
|
||||
opcodes = listOf(
|
||||
Opcode.CONST_STRING,
|
||||
null,
|
||||
Opcode.CONST_STRING,
|
||||
null,
|
||||
Opcode.INVOKE_DIRECT,
|
||||
Opcode.IPUT_OBJECT
|
||||
),
|
||||
// "children" are present throughout multiple versions
|
||||
strings = listOf(
|
||||
"children",
|
||||
"uxExperiences"
|
||||
),
|
||||
customFingerprint = { methodDef, classDef -> methodDef.definingClass.endsWith("/Listing;") && methodDef.name == "<init>" && classDef.sourceFile == "Listing.kt" },
|
||||
)
|
@ -0,0 +1,19 @@
|
||||
package app.revanced.patches.reddit.ad.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 NewAdPostFingerprint : MethodFingerprint(
|
||||
returnType = "L",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
opcodes = listOf(
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
),
|
||||
strings = listOf(
|
||||
"chain",
|
||||
"feedElement"
|
||||
),
|
||||
customFingerprint = { _, classDef -> classDef.sourceFile == "AdElementConverter.kt" },
|
||||
)
|
@ -0,0 +1,94 @@
|
||||
package app.revanced.patches.reddit.ad.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.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.removeInstruction
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultError
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patches.reddit.ad.banner.patch.HideBannerPatch
|
||||
import app.revanced.patches.reddit.ad.comments.patch.HideCommentAdsPatch
|
||||
import app.revanced.patches.reddit.ad.general.fingerprints.AdPostFingerprint
|
||||
import app.revanced.patches.reddit.ad.general.fingerprints.NewAdPostFingerprint
|
||||
import app.revanced.patches.reddit.utils.annotations.RedditCompatibility
|
||||
import app.revanced.patches.reddit.utils.integrations.patch.IntegrationsPatch
|
||||
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
|
||||
import org.jf.dexlib2.iface.instruction.formats.Instruction22c
|
||||
import org.jf.dexlib2.iface.reference.FieldReference
|
||||
|
||||
@Patch
|
||||
@Name("hide-ads")
|
||||
@Description("Removes ads from the Reddit.")
|
||||
@DependsOn(
|
||||
[
|
||||
HideBannerPatch::class,
|
||||
HideCommentAdsPatch::class,
|
||||
IntegrationsPatch::class
|
||||
]
|
||||
)
|
||||
@RedditCompatibility
|
||||
@Version("0.0.2")
|
||||
class HideAdsPatch : BytecodePatch(
|
||||
listOf(
|
||||
AdPostFingerprint,
|
||||
NewAdPostFingerprint
|
||||
)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
// region Filter promoted ads (does not work in popular or latest feed)
|
||||
|
||||
AdPostFingerprint.result?.let {
|
||||
it.mutableMethod.apply {
|
||||
val targetIndex = it.scanResult.patternScanResult!!.endIndex
|
||||
val targetReference = getInstruction<ReferenceInstruction>(targetIndex).reference
|
||||
val targetReferenceName = (targetReference as FieldReference).name
|
||||
|
||||
if (targetReferenceName != "children")
|
||||
throw PatchResultError("Method signature reference name did not match: $targetReferenceName")
|
||||
|
||||
val castedInstruction = getInstruction<Instruction22c>(targetIndex)
|
||||
|
||||
removeInstruction(targetIndex)
|
||||
addInstructions(
|
||||
targetIndex, """
|
||||
invoke-static {v${castedInstruction.registerA}}, $FILTER_METHOD_DESCRIPTOR
|
||||
move-result-object v0
|
||||
iput-object v0, v${castedInstruction.registerB}, ${castedInstruction.reference}
|
||||
"""
|
||||
)
|
||||
}
|
||||
} ?: return AdPostFingerprint.toErrorResult()
|
||||
|
||||
// The new feeds work by inserting posts into lists.
|
||||
// AdElementConverter is conveniently responsible for inserting all feed ads.
|
||||
// By removing the appending instruction no ad posts gets appended to the feed.
|
||||
NewAdPostFingerprint.result?.let {
|
||||
it.mutableMethod.apply {
|
||||
val targetIndex = it.scanResult.patternScanResult!!.endIndex
|
||||
val targetParameter =
|
||||
getInstruction<ReferenceInstruction>(targetIndex).reference.toString()
|
||||
|
||||
if (!targetParameter.endsWith("Ljava/util/ArrayList;->add(Ljava/lang/Object;)Z"))
|
||||
throw PatchResultError("Method signature parameter did not match: $targetParameter")
|
||||
|
||||
removeInstruction(targetIndex)
|
||||
}
|
||||
} ?: return NewAdPostFingerprint.toErrorResult()
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
|
||||
private companion object {
|
||||
private const val FILTER_METHOD_DESCRIPTOR =
|
||||
"Lapp/revanced/reddit/patches/FilterPromotedLinksPatch;" +
|
||||
"->filterChildren(Ljava/lang/Iterable;)Ljava/util/List;"
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package app.revanced.patches.reddit.layout.premiumicon.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
|
||||
object PremiumIconFingerprint : MethodFingerprint(
|
||||
returnType = "Z",
|
||||
customFingerprint = { methodDef, classDef ->
|
||||
methodDef.definingClass.endsWith("MyAccount;") && methodDef.name == "isPremiumSubscriber" && classDef.sourceFile == "MyAccount.kt"
|
||||
}
|
||||
)
|
@ -0,0 +1,39 @@
|
||||
package app.revanced.patches.reddit.layout.premiumicon.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.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patches.reddit.layout.premiumicon.fingerprints.PremiumIconFingerprint
|
||||
import app.revanced.patches.reddit.utils.annotations.RedditCompatibility
|
||||
|
||||
@Patch
|
||||
@Name("premium-icon-reddit")
|
||||
@Description("Unlocks premium Reddit app icons.")
|
||||
@RedditCompatibility
|
||||
@Version("0.0.1")
|
||||
class PremiumIconPatch : BytecodePatch(
|
||||
listOf(PremiumIconFingerprint)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
|
||||
PremiumIconFingerprint.result?.let {
|
||||
it.mutableMethod.apply {
|
||||
addInstructions(
|
||||
0, """
|
||||
const/4 v0, 0x1
|
||||
return v0
|
||||
"""
|
||||
)
|
||||
}
|
||||
} ?: return PremiumIconFingerprint.toErrorResult()
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package app.revanced.patches.reddit.misc.tracking.url.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 ShareLinkFactoryFingerprint : MethodFingerprint(
|
||||
returnType = "L",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
opcodes = listOf(
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_DIRECT,
|
||||
Opcode.APUT_OBJECT,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_STATIC, // Returns the URL.
|
||||
Opcode.MOVE_RESULT_OBJECT
|
||||
),
|
||||
customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("ShareLinkFactory;") }
|
||||
)
|
@ -0,0 +1,52 @@
|
||||
package app.revanced.patches.reddit.misc.tracking.url.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.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patcher.patch.annotations.RequiresIntegrations
|
||||
import app.revanced.patches.reddit.misc.tracking.url.fingerprints.ShareLinkFactoryFingerprint
|
||||
import app.revanced.patches.reddit.utils.annotations.RedditCompatibility
|
||||
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
|
||||
@Patch
|
||||
@Name("sanitize-sharing-links")
|
||||
@Description("Removes (tracking) query parameters from the URLs when sharing links.")
|
||||
@RedditCompatibility
|
||||
@Version("0.0.1")
|
||||
@RequiresIntegrations
|
||||
class SanitizeUrlQueryPatch : BytecodePatch(
|
||||
listOf(ShareLinkFactoryFingerprint)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
ShareLinkFactoryFingerprint.result?.let { result ->
|
||||
result.mutableMethod.apply {
|
||||
val insertIndex = result.scanResult.patternScanResult!!.endIndex + 1
|
||||
val urlRegister = getInstruction<OneRegisterInstruction>(insertIndex - 1).registerA
|
||||
|
||||
addInstructions(
|
||||
insertIndex,
|
||||
"""
|
||||
invoke-static {v$urlRegister}, $SANITIZE_METHOD_DESCRIPTOR
|
||||
move-result-object v$urlRegister
|
||||
"""
|
||||
)
|
||||
}
|
||||
} ?: return ShareLinkFactoryFingerprint.toErrorResult()
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
|
||||
private companion object {
|
||||
private const val SANITIZE_METHOD_DESCRIPTOR =
|
||||
"Lapp/revanced/reddit/patches/SanitizeUrlQueryPatch;" +
|
||||
"->stripQueryParameters(Ljava/lang/String;)Ljava/lang/String;"
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package app.revanced.patches.reddit.utils.annotations
|
||||
|
||||
import app.revanced.patcher.annotation.Compatibility
|
||||
import app.revanced.patcher.annotation.Package
|
||||
|
||||
@Compatibility([Package("com.reddit.frontpage")])
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
internal annotation class RedditCompatibility
|
Loading…
x
Reference in New Issue
Block a user