feat(twitch): remove block-embedded-ads patch (#1164)

This commit is contained in:
Ushie 2022-12-01 00:36:21 +03:00 committed by GitHub
parent d93b480057
commit a43d149660
9 changed files with 30 additions and 224 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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. */