feat(twitch): remove block-embedded-ads
patch (#1164)
This commit is contained in:
parent
d93b480057
commit
a43d149660
|
@ -25,7 +25,7 @@ internal data class ArrayResource(
|
||||||
resourceCallback?.invoke(item)
|
resourceCallback?.invoke(item)
|
||||||
|
|
||||||
this.appendChild(ownerDocument.createElement("item").also { itemNode ->
|
this.appendChild(ownerDocument.createElement("item").also { itemNode ->
|
||||||
itemNode.textContent = "@string/${item.name}"
|
itemNode.textContent = item.value
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,7 +92,7 @@ abstract class AbstractSettingsResourcePatch(
|
||||||
* @param arrayResource The array resource to add.
|
* @param arrayResource The array resource to add.
|
||||||
*/
|
*/
|
||||||
fun addArray(arrayResource: ArrayResource) =
|
fun addArray(arrayResource: ArrayResource) =
|
||||||
arraysNode!!.addResource(arrayResource) { it.include() }
|
arraysNode!!.addResource(arrayResource)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a preference to the settings.
|
* Add a preference to the settings.
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
package app.revanced.patches.twitch.ad.embedded.annotations
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Compatibility
|
|
||||||
import app.revanced.patcher.annotation.Package
|
|
||||||
|
|
||||||
@Compatibility([Package("tv.twitch.android.app")])
|
|
||||||
@Target(AnnotationTarget.CLASS)
|
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
|
||||||
internal annotation class EmbeddedAdsCompatibility
|
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
package app.revanced.patches.twitch.ad.embedded.fingerprints
|
|
||||||
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
|
|
||||||
object CreateUsherClientFingerprint : MethodFingerprint(
|
|
||||||
customFingerprint = { method ->
|
|
||||||
method.definingClass.endsWith("Ltv/twitch/android/network/OkHttpClientFactory;") && method.name == "buildOkHttpClient"
|
|
||||||
}
|
|
||||||
)
|
|
|
@ -1,78 +0,0 @@
|
||||||
package app.revanced.patches.twitch.ad.embedded.patch
|
|
||||||
|
|
||||||
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.MethodFingerprintExtensions.name
|
|
||||||
import app.revanced.patcher.extensions.addInstructions
|
|
||||||
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.shared.settings.preference.impl.ArrayResource
|
|
||||||
import app.revanced.patches.shared.settings.preference.impl.ListPreference
|
|
||||||
import app.revanced.patches.shared.settings.preference.impl.StringResource
|
|
||||||
import app.revanced.patches.twitch.ad.embedded.annotations.EmbeddedAdsCompatibility
|
|
||||||
import app.revanced.patches.twitch.ad.embedded.fingerprints.CreateUsherClientFingerprint
|
|
||||||
import app.revanced.patches.twitch.ad.video.patch.VideoAdsPatch
|
|
||||||
import app.revanced.patches.twitch.misc.integrations.patch.IntegrationsPatch
|
|
||||||
import app.revanced.patches.twitch.misc.settings.bytecode.patch.SettingsPatch
|
|
||||||
|
|
||||||
@Patch
|
|
||||||
@DependsOn([VideoAdsPatch::class, IntegrationsPatch::class, SettingsPatch::class])
|
|
||||||
@Name("block-embedded-ads")
|
|
||||||
@Description("Blocks embedded steam ads using services like TTV.lol or PurpleAdBlocker.")
|
|
||||||
@EmbeddedAdsCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
class EmbeddedAdsPatch : BytecodePatch(
|
|
||||||
listOf(CreateUsherClientFingerprint)
|
|
||||||
) {
|
|
||||||
override fun execute(context: BytecodeContext): PatchResult {
|
|
||||||
val result = CreateUsherClientFingerprint.result ?: return PatchResultError("${CreateUsherClientFingerprint.name} not found")
|
|
||||||
|
|
||||||
// Inject OkHttp3 application interceptor
|
|
||||||
result.mutableMethod.addInstructions(
|
|
||||||
3,
|
|
||||||
"""
|
|
||||||
invoke-static {}, Lapp/revanced/twitch/patches/EmbeddedAdsPatch;->createRequestInterceptor()Lapp/revanced/twitch/api/RequestInterceptor;
|
|
||||||
move-result-object v2
|
|
||||||
invoke-virtual {v0, v2}, Lokhttp3/OkHttpClient${"$"}Builder;->addInterceptor(Lokhttp3/Interceptor;)Lokhttp3/OkHttpClient${"$"}Builder;
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
|
|
||||||
SettingsPatch.PreferenceScreen.ADS.SURESTREAM.addPreferences(
|
|
||||||
ListPreference(
|
|
||||||
"revanced_block_embedded_ads",
|
|
||||||
StringResource(
|
|
||||||
"revanced_block_embedded_ads",
|
|
||||||
"Block embedded video ads"
|
|
||||||
),
|
|
||||||
ArrayResource(
|
|
||||||
"revanced_hls_proxies",
|
|
||||||
listOf(
|
|
||||||
StringResource("revanced_proxy_disabled", "Disabled"),
|
|
||||||
StringResource("revanced_proxy_ttv_lol", "TTV LOL proxy"),
|
|
||||||
StringResource("revanced_proxy_purpleadblock", "PurpleAdBlock proxy"),
|
|
||||||
)
|
|
||||||
),
|
|
||||||
ArrayResource(
|
|
||||||
"revanced_hls_proxies_values",
|
|
||||||
listOf(
|
|
||||||
StringResource("key_revanced_proxy_disabled", "disabled"),
|
|
||||||
StringResource("key_revanced_proxy_ttv_lol", "ttv-lol"),
|
|
||||||
StringResource("key_revanced_proxy_purpleadblock", "purpleadblock")
|
|
||||||
)
|
|
||||||
),
|
|
||||||
"ttv-lol"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
SettingsPatch.addString("revanced_embedded_ads_service_unavailable", "%s is unavailable. Ads may show. Try switching to another ad block service in settings.")
|
|
||||||
SettingsPatch.addString("revanced_embedded_ads_service_failed", "%s server returned an error. Ads may show. Try switching to another ad block service in settings.")
|
|
||||||
|
|
||||||
return PatchResultSuccess()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,51 +0,0 @@
|
||||||
package app.revanced.patches.twitch.ad.shared.util
|
|
||||||
|
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
|
||||||
import app.revanced.patcher.extensions.addInstructions
|
|
||||||
import app.revanced.patcher.extensions.instruction
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
import app.revanced.patcher.patch.BytecodePatch
|
|
||||||
import app.revanced.patcher.util.smali.ExternalLabel
|
|
||||||
|
|
||||||
abstract class AbstractAdPatch(
|
|
||||||
val conditionCall: String,
|
|
||||||
val skipLabelName: String,
|
|
||||||
internal val fingerprints: Iterable<MethodFingerprint>? = null,
|
|
||||||
) : BytecodePatch(fingerprints) {
|
|
||||||
|
|
||||||
protected fun createConditionInstructions(register: String = "v0") = """
|
|
||||||
invoke-static { }, $conditionCall
|
|
||||||
move-result $register
|
|
||||||
if-eqz $register, :$skipLabelName
|
|
||||||
"""
|
|
||||||
|
|
||||||
protected data class ReturnMethod(val returnType: Char = 'V', val value: String = "")
|
|
||||||
|
|
||||||
protected fun BytecodeContext.blockMethods(clazz: String, vararg methodNames: String, returnMethod: ReturnMethod = ReturnMethod()): Boolean {
|
|
||||||
|
|
||||||
return with(findClass(clazz)?.mutableClass) {
|
|
||||||
this ?: return false
|
|
||||||
|
|
||||||
this.methods.filter { methodNames.contains(it.name) }.forEach {
|
|
||||||
val retIntructions = when(returnMethod.returnType) {
|
|
||||||
'V' -> "return-void"
|
|
||||||
'Z' -> """
|
|
||||||
const/4 v0, ${returnMethod.value}
|
|
||||||
return v0
|
|
||||||
"""
|
|
||||||
else -> throw NotImplementedError()
|
|
||||||
}
|
|
||||||
it.addInstructions(
|
|
||||||
0,
|
|
||||||
"""
|
|
||||||
${createConditionInstructions("v0")}
|
|
||||||
$retIntructions
|
|
||||||
""",
|
|
||||||
listOf(ExternalLabel(skipLabelName, it.instruction(0)))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,9 +1,10 @@
|
||||||
package app.revanced.patches.twitch.ad.video.fingerprints
|
package app.revanced.patches.twitch.ad.video.fingerprints
|
||||||
|
|
||||||
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
|
|
||||||
object GetReadyToShowAdFingerprint : MethodFingerprint(
|
object AdsManagerFingerprint : MethodFingerprint(
|
||||||
customFingerprint = { method ->
|
customFingerprint = { method ->
|
||||||
method.definingClass.endsWith("/StreamDisplayAdsPresenter;") && method.name == "getReadyToShowAdOrAbort"
|
method.definingClass.endsWith("AdsManagerImpl;") && method.name == "playAds"
|
||||||
}
|
}
|
||||||
)
|
)
|
|
@ -6,6 +6,7 @@ import app.revanced.patcher.annotation.Version
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
import app.revanced.patcher.data.BytecodeContext
|
||||||
import app.revanced.patcher.extensions.addInstructions
|
import app.revanced.patcher.extensions.addInstructions
|
||||||
import app.revanced.patcher.extensions.instruction
|
import app.revanced.patcher.extensions.instruction
|
||||||
|
import app.revanced.patcher.patch.BytecodePatch
|
||||||
import app.revanced.patcher.patch.PatchResult
|
import app.revanced.patcher.patch.PatchResult
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
import app.revanced.patcher.patch.PatchResultSuccess
|
||||||
import app.revanced.patcher.patch.annotations.DependsOn
|
import app.revanced.patcher.patch.annotations.DependsOn
|
||||||
|
@ -13,11 +14,10 @@ import app.revanced.patcher.patch.annotations.Patch
|
||||||
import app.revanced.patcher.util.smali.ExternalLabel
|
import app.revanced.patcher.util.smali.ExternalLabel
|
||||||
import app.revanced.patches.shared.settings.preference.impl.StringResource
|
import app.revanced.patches.shared.settings.preference.impl.StringResource
|
||||||
import app.revanced.patches.shared.settings.preference.impl.SwitchPreference
|
import app.revanced.patches.shared.settings.preference.impl.SwitchPreference
|
||||||
import app.revanced.patches.twitch.ad.shared.util.AbstractAdPatch
|
|
||||||
import app.revanced.patches.twitch.ad.video.annotations.VideoAdsCompatibility
|
import app.revanced.patches.twitch.ad.video.annotations.VideoAdsCompatibility
|
||||||
|
import app.revanced.patches.twitch.ad.video.fingerprints.AdsManagerFingerprint
|
||||||
import app.revanced.patches.twitch.ad.video.fingerprints.CheckAdEligibilityLambdaFingerprint
|
import app.revanced.patches.twitch.ad.video.fingerprints.CheckAdEligibilityLambdaFingerprint
|
||||||
import app.revanced.patches.twitch.ad.video.fingerprints.ContentConfigShowAdsFingerprint
|
import app.revanced.patches.twitch.ad.video.fingerprints.ContentConfigShowAdsFingerprint
|
||||||
import app.revanced.patches.twitch.ad.video.fingerprints.GetReadyToShowAdFingerprint
|
|
||||||
import app.revanced.patches.twitch.misc.integrations.patch.IntegrationsPatch
|
import app.revanced.patches.twitch.misc.integrations.patch.IntegrationsPatch
|
||||||
import app.revanced.patches.twitch.misc.settings.bytecode.patch.SettingsPatch
|
import app.revanced.patches.twitch.misc.settings.bytecode.patch.SettingsPatch
|
||||||
|
|
||||||
|
@ -27,63 +27,20 @@ import app.revanced.patches.twitch.misc.settings.bytecode.patch.SettingsPatch
|
||||||
@Description("Blocks video ads in streams and VODs.")
|
@Description("Blocks video ads in streams and VODs.")
|
||||||
@VideoAdsCompatibility
|
@VideoAdsCompatibility
|
||||||
@Version("0.0.1")
|
@Version("0.0.1")
|
||||||
class VideoAdsPatch : AbstractAdPatch(
|
class VideoAdsPatch : BytecodePatch(
|
||||||
"Lapp/revanced/twitch/patches/VideoAdsPatch;->shouldBlockVideoAds()Z",
|
|
||||||
"show_video_ads",
|
|
||||||
listOf(
|
listOf(
|
||||||
ContentConfigShowAdsFingerprint,
|
ContentConfigShowAdsFingerprint,
|
||||||
CheckAdEligibilityLambdaFingerprint,
|
AdsManagerFingerprint,
|
||||||
GetReadyToShowAdFingerprint
|
CheckAdEligibilityLambdaFingerprint
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
|
private fun createConditionInstructions(register: String = "v0") = """
|
||||||
|
invoke-static { }, Lapp/revanced/twitch/patches/VideoAdsPatch;->shouldBlockVideoAds()Z
|
||||||
|
move-result $register
|
||||||
|
if-eqz $register, :show_video_ads
|
||||||
|
"""
|
||||||
|
|
||||||
override fun execute(context: BytecodeContext): PatchResult {
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
/* Amazon ads SDK */
|
|
||||||
context.blockMethods(
|
|
||||||
"Lcom/amazon/ads/video/player/AdsManagerImpl;",
|
|
||||||
"playAds"
|
|
||||||
)
|
|
||||||
|
|
||||||
/* Twitch ads manager */
|
|
||||||
context.blockMethods(
|
|
||||||
"Ltv/twitch/android/shared/ads/VideoAdManager;",
|
|
||||||
"checkAdEligibilityAndRequestAd", "requestAd", "requestAds"
|
|
||||||
)
|
|
||||||
|
|
||||||
/* Various ad presenters */
|
|
||||||
context.blockMethods(
|
|
||||||
"Ltv/twitch/android/shared/ads/AdsPlayerPresenter;",
|
|
||||||
"requestAd", "requestFirstAd", "requestFirstAdIfEligible", "requestMidroll", "requestAdFromMultiAdFormatEvent"
|
|
||||||
)
|
|
||||||
|
|
||||||
context.blockMethods(
|
|
||||||
"Ltv/twitch/android/shared/ads/AdsVodPlayerPresenter;",
|
|
||||||
"requestAd", "requestFirstAd",
|
|
||||||
)
|
|
||||||
|
|
||||||
context.blockMethods(
|
|
||||||
"Ltv/twitch/android/feature/theatre/ads/AdEdgeAllocationPresenter;",
|
|
||||||
"parseAdAndCheckEligibility", "requestAdsAfterEligibilityCheck", "showAd", "bindMultiAdFormatAllocation"
|
|
||||||
)
|
|
||||||
|
|
||||||
/* A/B ad testing experiments */
|
|
||||||
context.blockMethods(
|
|
||||||
"Ltv/twitch/android/provider/experiments/helpers/DisplayAdsExperimentHelper;",
|
|
||||||
"areDisplayAdsEnabled",
|
|
||||||
returnMethod = ReturnMethod('Z', "0")
|
|
||||||
)
|
|
||||||
|
|
||||||
context.blockMethods(
|
|
||||||
"Ltv/twitch/android/shared/ads/tracking/MultiFormatAdsTrackingExperiment;",
|
|
||||||
"shouldUseMultiAdFormatTracker", "shouldUseVideoAdTracker",
|
|
||||||
returnMethod = ReturnMethod('Z', "0")
|
|
||||||
)
|
|
||||||
|
|
||||||
context.blockMethods(
|
|
||||||
"Ltv/twitch/android/shared/ads/MultiformatAdsExperiment;",
|
|
||||||
"shouldDisableClientSideLivePreroll", "shouldDisableClientSideVodPreroll",
|
|
||||||
returnMethod = ReturnMethod('Z', "1")
|
|
||||||
)
|
|
||||||
|
|
||||||
// Pretend our player is ineligible for all ads
|
// Pretend our player is ineligible for all ads
|
||||||
with(CheckAdEligibilityLambdaFingerprint.result!!) {
|
with(CheckAdEligibilityLambdaFingerprint.result!!) {
|
||||||
mutableMethod.addInstructions(
|
mutableMethod.addInstructions(
|
||||||
|
@ -95,22 +52,7 @@ class VideoAdsPatch : AbstractAdPatch(
|
||||||
move-result-object p0
|
move-result-object p0
|
||||||
return-object p0
|
return-object p0
|
||||||
""",
|
""",
|
||||||
listOf(ExternalLabel(skipLabelName, mutableMethod.instruction(0)))
|
listOf(ExternalLabel("show_video_ads", mutableMethod.instruction(0)))
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
with(GetReadyToShowAdFingerprint.result!!) {
|
|
||||||
val adFormatDeclined = "Ltv/twitch/android/shared/display/ads/theatre/StreamDisplayAdsPresenter\$Action\$AdFormatDeclined;"
|
|
||||||
mutableMethod.addInstructions(
|
|
||||||
0,
|
|
||||||
"""
|
|
||||||
${createConditionInstructions()}
|
|
||||||
sget-object p2, $adFormatDeclined->INSTANCE:$adFormatDeclined
|
|
||||||
invoke-static {p1, p2}, Ltv/twitch/android/core/mvp/presenter/StateMachineKt;->plus(Ltv/twitch/android/core/mvp/presenter/PresenterState;Ltv/twitch/android/core/mvp/presenter/PresenterAction;)Ltv/twitch/android/core/mvp/presenter/StateAndAction;
|
|
||||||
move-result-object p1
|
|
||||||
return-object p1
|
|
||||||
""",
|
|
||||||
listOf(ExternalLabel(skipLabelName, mutableMethod.instruction(0)))
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,12 +61,24 @@ class VideoAdsPatch : AbstractAdPatch(
|
||||||
mutableMethod.addInstructions(0, """
|
mutableMethod.addInstructions(0, """
|
||||||
${createConditionInstructions()}
|
${createConditionInstructions()}
|
||||||
const/4 v0, 0
|
const/4 v0, 0
|
||||||
:$skipLabelName
|
:show_video_ads
|
||||||
return v0
|
return v0
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Block playAds call
|
||||||
|
with(AdsManagerFingerprint.result!!) {
|
||||||
|
mutableMethod.addInstructions(
|
||||||
|
0,
|
||||||
|
"""
|
||||||
|
${createConditionInstructions()}
|
||||||
|
return-void
|
||||||
|
""",
|
||||||
|
listOf(ExternalLabel("show_video_ads", mutableMethod.instruction(0)))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
SettingsPatch.PreferenceScreen.ADS.CLIENT_SIDE.addPreferences(
|
SettingsPatch.PreferenceScreen.ADS.CLIENT_SIDE.addPreferences(
|
||||||
SwitchPreference(
|
SwitchPreference(
|
||||||
"revanced_block_video_ads",
|
"revanced_block_video_ads",
|
||||||
|
|
|
@ -173,7 +173,6 @@ class SettingsPatch : BytecodePatch(
|
||||||
val GENERAL = CustomCategory("general", "General settings")
|
val GENERAL = CustomCategory("general", "General settings")
|
||||||
val OTHER = CustomCategory("other", "Other settings")
|
val OTHER = CustomCategory("other", "Other settings")
|
||||||
val CLIENT_SIDE = CustomCategory("client_ads", "Client-side ads")
|
val CLIENT_SIDE = CustomCategory("client_ads", "Client-side ads")
|
||||||
val SURESTREAM = CustomCategory("surestream_ads", "Server-side surestream ads")
|
|
||||||
|
|
||||||
internal inner class CustomCategory(key: String, title: String) : Screen.Category(key, title) {
|
internal inner class CustomCategory(key: String, title: String) : Screen.Category(key, title) {
|
||||||
/* For Twitch, we need to load our CustomPreferenceCategory class instead of the default one. */
|
/* For Twitch, we need to load our CustomPreferenceCategory class instead of the default one. */
|
||||||
|
|
Loading…
Reference in a new issue