feat(twitch): settings for patches (#1142)

This commit is contained in:
Tim Schneeberger 2022-11-29 00:20:58 +01:00 committed by GitHub
parent a334562a27
commit ed56f94f12
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 187 additions and 14 deletions

View File

@ -4,15 +4,23 @@ import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstruction import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.instruction
import app.revanced.patcher.patch.BytecodePatch 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.Patch import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.shared.settings.preference.impl.StringResource
import app.revanced.patches.shared.settings.preference.impl.SwitchPreference
import app.revanced.patches.twitch.ad.audio.annotations.AudioAdsCompatibility import app.revanced.patches.twitch.ad.audio.annotations.AudioAdsCompatibility
import app.revanced.patches.twitch.ad.audio.fingerprints.AudioAdsPresenterPlayFingerprint import app.revanced.patches.twitch.ad.audio.fingerprints.AudioAdsPresenterPlayFingerprint
import app.revanced.patches.twitch.misc.integrations.patch.IntegrationsPatch
import app.revanced.patches.twitch.misc.settings.bytecode.patch.SettingsPatch
@Patch @Patch
@DependsOn([IntegrationsPatch::class, SettingsPatch::class])
@Name("block-audio-ads") @Name("block-audio-ads")
@Description("Blocks audio ads in streams and VODs.") @Description("Blocks audio ads in streams and VODs.")
@AudioAdsCompatibility @AudioAdsCompatibility
@ -23,9 +31,37 @@ class AudioAdsPatch : BytecodePatch(
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
// Block playAds call // Block playAds call
with(AudioAdsPresenterPlayFingerprint.result!!) { with(AudioAdsPresenterPlayFingerprint.result!!) {
mutableMethod.addInstruction(0, "return-void") mutableMethod.addInstructions(
0,
"""
invoke-static { }, Lapp/revanced/twitch/patches/AudioAdsPatch;->shouldBlockAudioAds()Z
move-result v0
if-eqz v0, :show_audio_ads
return-void
""",
listOf(ExternalLabel("show_audio_ads", mutableMethod.instruction(0)))
)
} }
SettingsPatch.PreferenceScreen.ADS.CLIENT_SIDE.addPreferences(
SwitchPreference(
"revanced_block_audio_ads",
StringResource(
"revanced_block_audio_ads",
"Block audio ads"
),
true,
StringResource(
"revanced_block_audio_ads_on",
"Audio ads are blocked"
),
StringResource(
"revanced_block_audio_ads_off",
"Audio ads are unblocked"
),
)
)
return PatchResultSuccess() return PatchResultSuccess()
} }
} }

View File

@ -4,18 +4,25 @@ import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.instruction
import app.revanced.patcher.patch.BytecodePatch 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.Patch import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.shared.settings.preference.impl.StringResource
import app.revanced.patches.shared.settings.preference.impl.SwitchPreference
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.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.misc.integrations.patch.IntegrationsPatch
import app.revanced.patches.twitch.misc.settings.bytecode.patch.SettingsPatch
@Patch @Patch
@DependsOn([IntegrationsPatch::class, SettingsPatch::class])
@Name("block-video-ads") @Name("block-video-ads")
@Description("Blocks video ads in streams and VODs.") @Description("Blocks video ads in streams and VODs.")
@VideoAdsCompatibility @VideoAdsCompatibility
@ -27,24 +34,34 @@ class VideoAdsPatch : BytecodePatch(
CheckAdEligibilityLambdaFingerprint 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 {
// 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(
0, 0,
""" """
${createConditionInstructions()}
const/4 v0, 0 const/4 v0, 0
invoke-static {v0}, Lio/reactivex/Single;->just(Ljava/lang/Object;)Lio/reactivex/Single; invoke-static {v0}, Lio/reactivex/Single;->just(Ljava/lang/Object;)Lio/reactivex/Single;
move-result-object p0 move-result-object p0
return-object p0 return-object p0
""" """,
listOf(ExternalLabel("show_video_ads", mutableMethod.instruction(0)))
) )
} }
// Spoof showAds JSON field // Spoof showAds JSON field
with(ContentConfigShowAdsFingerprint.result!!) { with(ContentConfigShowAdsFingerprint.result!!) {
mutableMethod.addInstructions(0, """ mutableMethod.addInstructions(0, """
${createConditionInstructions()}
const/4 v0, 0 const/4 v0, 0
:show_video_ads
return v0 return v0
""" """
) )
@ -52,9 +69,35 @@ class VideoAdsPatch : BytecodePatch(
// Block playAds call // Block playAds call
with(AdsManagerFingerprint.result!!) { with(AdsManagerFingerprint.result!!) {
mutableMethod.addInstruction(0, "return-void") mutableMethod.addInstructions(
0,
"""
${createConditionInstructions()}
return-void
""",
listOf(ExternalLabel("show_video_ads", mutableMethod.instruction(0)))
)
} }
SettingsPatch.PreferenceScreen.ADS.CLIENT_SIDE.addPreferences(
SwitchPreference(
"revanced_block_video_ads",
StringResource(
"revanced_block_video_ads",
"Block video ads"
),
true,
StringResource(
"revanced_block_video_ads_on",
"Video ads are blocked"
),
StringResource(
"revanced_block_video_ads_off",
"Video ads are unblocked"
),
)
)
return PatchResultSuccess() return PatchResultSuccess()
} }
} }

View File

@ -0,0 +1,9 @@
package app.revanced.patches.twitch.chat.antidelete.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
object ChatUtilCreateDeletedSpanFingerprint : MethodFingerprint(
customFingerprint = { methodDef ->
methodDef.definingClass.endsWith("/ChatUtil\$Companion;") && methodDef.name == "createDeletedSpanFromChatMessageSpan"
}
)

View File

@ -6,13 +6,19 @@ import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.* import app.revanced.patcher.extensions.*
import app.revanced.patcher.patch.* import app.revanced.patcher.patch.*
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.util.smali.ExternalLabel
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.chat.antidelete.annotations.ShowDeletedMessagesCompatibility import app.revanced.patches.twitch.chat.antidelete.annotations.ShowDeletedMessagesCompatibility
import app.revanced.patches.twitch.chat.antidelete.fingerprints.* import app.revanced.patches.twitch.chat.antidelete.fingerprints.*
import org.jf.dexlib2.Opcode import app.revanced.patches.twitch.misc.integrations.patch.IntegrationsPatch
import org.jf.dexlib2.builder.instruction.BuilderInstruction10x import app.revanced.patches.twitch.misc.settings.bytecode.patch.SettingsPatch
@Patch @Patch
@DependsOn([IntegrationsPatch::class, SettingsPatch::class])
@Name("show-deleted-messages") @Name("show-deleted-messages")
@Description("Shows deleted chat messages behind a clickable spoiler.") @Description("Shows deleted chat messages behind a clickable spoiler.")
@ShowDeletedMessagesCompatibility @ShowDeletedMessagesCompatibility
@ -21,25 +27,77 @@ class ShowDeletedMessagesPatch : BytecodePatch(
listOf( listOf(
SetHasModAccessFingerprint, SetHasModAccessFingerprint,
DeletedMessageClickableSpanCtorFingerprint, DeletedMessageClickableSpanCtorFingerprint,
ChatUtilCreateDeletedSpanFingerprint
) )
) { ) {
private fun createSpoilerConditionInstructions(register: String = "v0") = """
invoke-static {}, Lapp/revanced/twitch/patches/ShowDeletedMessagesPatch;->shouldUseSpoiler()Z
move-result $register
if-eqz $register, :no_spoiler
"""
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
// Force set hasModAccess member to true in constructor // Spoiler mode: Force set hasModAccess member to true in constructor
with(DeletedMessageClickableSpanCtorFingerprint.result!!.mutableMethod) { with(DeletedMessageClickableSpanCtorFingerprint.result!!.mutableMethod) {
addInstructions( addInstructions(
implementation!!.instructions.lastIndex, /* place in front of return-void */ implementation!!.instructions.lastIndex, /* place in front of return-void */
""" """
${createSpoilerConditionInstructions()}
const/4 v0, 1 const/4 v0, 1
iput-boolean v0, p0, $definingClass->hasModAccess:Z iput-boolean v0, p0, $definingClass->hasModAccess:Z
""" """,
listOf(ExternalLabel("no_spoiler", instruction(implementation!!.instructions.lastIndex)))
) )
} }
// Disable setHasModAccess setter // Spoiler mode: Disable setHasModAccess setter
with(SetHasModAccessFingerprint.result!!.mutableMethod.implementation!!) { with(SetHasModAccessFingerprint.result!!) {
addInstruction(0, BuilderInstruction10x(Opcode.RETURN_VOID)) mutableMethod.addInstruction(0, "return-void")
} }
// Cross-out mode: Reformat span of deleted message
with(ChatUtilCreateDeletedSpanFingerprint.result!!) {
mutableMethod.addInstructions(
0,
"""
invoke-static {p2}, Lapp/revanced/twitch/patches/ShowDeletedMessagesPatch;->reformatDeletedMessage(Landroid/text/Spanned;)Landroid/text/Spanned;
move-result-object v0
if-eqz v0, :no_reformat
return-object v0
""",
listOf(ExternalLabel("no_reformat", mutableMethod.instruction(0)))
)
}
SettingsPatch.PreferenceScreen.CHAT.GENERAL.addPreferences(
ListPreference(
"revanced_show_deleted_messages",
StringResource(
"revanced_show_deleted_messages_title",
"Show deleted messages"
),
ArrayResource(
"revanced_deleted_messages",
listOf(
StringResource("revanced_deleted_messages_hide", "Do not show deleted messages"),
StringResource("revanced_deleted_messages_spoiler", "Hide deleted messages behind a spoiler"),
StringResource("revanced_deleted_messages_cross_out", "Show deleted messages as crossed-out text")
)
),
ArrayResource(
"revanced_deleted_messages_values",
listOf(
StringResource("key_revanced_deleted_messages_hide", "hide"),
StringResource("key_revanced_deleted_messages_spoiler", "spoiler"),
StringResource("key_revanced_deleted_messages_cross_out", "cross-out")
)
),
"cross-out"
)
)
SettingsPatch.addString("revanced_deleted_msg", "message deleted")
return PatchResultSuccess() return PatchResultSuccess()
} }
} }

View File

@ -8,13 +8,19 @@ import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.patch.BytecodePatch 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.Patch import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.shared.settings.preference.impl.StringResource
import app.revanced.patches.shared.settings.preference.impl.SwitchPreference
import app.revanced.patches.twitch.debug.annotations.DebugModeCompatibility import app.revanced.patches.twitch.debug.annotations.DebugModeCompatibility
import app.revanced.patches.twitch.debug.fingerprints.IsDebugConfigEnabledFingerprint import app.revanced.patches.twitch.debug.fingerprints.IsDebugConfigEnabledFingerprint
import app.revanced.patches.twitch.debug.fingerprints.IsOmVerificationEnabledFingerprint import app.revanced.patches.twitch.debug.fingerprints.IsOmVerificationEnabledFingerprint
import app.revanced.patches.twitch.debug.fingerprints.ShouldShowDebugOptionsFingerprint import app.revanced.patches.twitch.debug.fingerprints.ShouldShowDebugOptionsFingerprint
import app.revanced.patches.twitch.misc.integrations.patch.IntegrationsPatch
import app.revanced.patches.twitch.misc.settings.bytecode.patch.SettingsPatch
@Patch(false) @Patch(false)
@DependsOn([IntegrationsPatch::class, SettingsPatch::class])
@Name("debug-mode") @Name("debug-mode")
@Description("Enables Twitch's internal debugging mode.") @Description("Enables Twitch's internal debugging mode.")
@DebugModeCompatibility @DebugModeCompatibility
@ -37,13 +43,34 @@ class DebugModePatch : BytecodePatch(
addInstructions( addInstructions(
0, 0,
""" """
const/4 v0, 0x1 invoke-static {}, Lapp/revanced/twitch/patches/DebugModePatch;->isDebugModeEnabled()Z
move-result v0
return v0 return v0
""" """
) )
} }
} }
} }
SettingsPatch.PreferenceScreen.MISC.OTHER.addPreferences(
SwitchPreference(
"revanced_debug_mode",
StringResource(
"revanced_debug_mode_enable",
"Enable debug mode"
),
false,
StringResource(
"revanced_debug_mode_on",
"Debug mode is enabled (not recommended)"
),
StringResource(
"revanced_debug_mode_off",
"Debug mode is disabled"
),
)
)
return PatchResultSuccess() return PatchResultSuccess()
} }
} }