diff --git a/src/main/kotlin/app/revanced/patches/tumblr/ads/fingerprints/AdWaterfallFingerprint.kt b/src/main/kotlin/app/revanced/patches/tumblr/ads/fingerprints/AdWaterfallFingerprint.kt new file mode 100644 index 0000000000..b7737a6c0c --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/tumblr/ads/fingerprints/AdWaterfallFingerprint.kt @@ -0,0 +1,12 @@ +package app.revanced.patches.tumblr.ads.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint + +// The Tumblr app sends a request to /v2/timeline/dashboard which replies with an array of elements +// to show in the user dashboard. These element have different type ids (post, title, carousel, etc.) +// The standard dashboard Ad has the id client_side_ad_waterfall, and this string has to be in the code +// to handle ads and provide their appearance. +// If we just replace this string in the tumblr code with anything else, it will fail to recognize the +// dashboard object type and just skip it. This is a bit weird, but it shouldn't break +// unless they change the api (unlikely) or explicitly Change the tumblr code to prevent this. +object AdWaterfallFingerprint : MethodFingerprint(strings = listOf("client_side_ad_waterfall")) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tumblr/ads/patch/DisableDashboardAds.kt b/src/main/kotlin/app/revanced/patches/tumblr/ads/patch/DisableDashboardAds.kt new file mode 100644 index 0000000000..24a0d8a5d9 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/tumblr/ads/patch/DisableDashboardAds.kt @@ -0,0 +1,34 @@ +package app.revanced.patches.tumblr.ads.patch + +import app.revanced.extensions.exception +import app.revanced.patcher.annotation.Compatibility +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Package +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.InstructionExtensions.getInstruction +import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patches.tumblr.ads.fingerprints.AdWaterfallFingerprint +import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction + +@Patch +@Name("Disable dashboard ads") +@Description("Disables ads in the dashboard.") +@Compatibility([Package("com.tumblr")]) +class DisableDashboardAds : BytecodePatch( + listOf(AdWaterfallFingerprint) +) { + override fun execute(context: BytecodeContext) = AdWaterfallFingerprint.result?.let { + it.scanResult.stringsScanResult!!.matches.forEach { match -> + // We just replace all occurrences of "client_side_ad_waterfall" with anything else + // so the app fails to handle ads in the timeline elements array and just skips them. + // See AdWaterfallFingerprint for more info. + val stringRegister = it.mutableMethod.getInstruction(match.index).registerA + it.mutableMethod.replaceInstruction( + match.index, "const-string v$stringRegister, \"dummy\"" + ) + } + } ?: throw AdWaterfallFingerprint.exception +} \ No newline at end of file