feat(Prime Video): Add Skip ads patch (#4824)

This commit is contained in:
hoodles
2025-05-06 00:40:45 -07:00
committed by GitHub
parent 0cf7a4c6be
commit bb672c4674
23 changed files with 244 additions and 0 deletions

View File

@ -420,6 +420,14 @@ public final class app/revanced/patches/pixiv/ads/HideAdsPatchKt {
public static final fun getHideAdsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
public final class app/revanced/patches/primevideo/ads/SkipAdsPatchKt {
public static final fun getSkipAdsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
public final class app/revanced/patches/primevideo/misc/extension/ExtensionPatchKt {
public static final fun getSharedExtensionPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
public final class app/revanced/patches/protonmail/signature/RemoveSentFromSignaturePatchKt {
public static final fun getRemoveSentFromSignaturePatch ()Lapp/revanced/patcher/patch/ResourcePatch;
}

View File

@ -0,0 +1,33 @@
package app.revanced.patches.primevideo.ads
import app.revanced.patcher.fingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
internal val enterServerInsertedAdBreakStateFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC)
parameters("Lcom/amazon/avod/fsm/Trigger;")
returns("V")
opcodes(
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CONST_4,
Opcode.CONST_4
)
custom { method, classDef ->
method.name == "enter" && classDef.type == "Lcom/amazon/avod/media/ads/internal/state/ServerInsertedAdBreakState;"
}
}
internal val doTriggerFingerprint = fingerprint {
accessFlags(AccessFlags.PROTECTED)
returns("V")
opcodes(
Opcode.IGET_OBJECT,
Opcode.INVOKE_INTERFACE,
Opcode.RETURN_VOID
)
custom { method, classDef ->
method.name == "doTrigger" && classDef.type == "Lcom/amazon/avod/fsm/StateBase;"
}
}

View File

@ -0,0 +1,45 @@
package app.revanced.patches.primevideo.ads
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.primevideo.misc.extension.sharedExtensionPatch
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
@Suppress("unused")
val skipAdsPatch = bytecodePatch(
name = "Skip ads",
description = "Automatically skips video stream ads.",
) {
compatibleWith("com.amazon.avod.thirdpartyclient"("3.0.403.257"))
dependsOn(sharedExtensionPatch)
// Skip all the logic in ServerInsertedAdBreakState.enter(), which plays all the ad clips in this
// ad break. Instead, force the video player to seek over the entire break and reset the state machine.
execute {
// Force doTrigger() access to public so we can call it from our extension.
doTriggerFingerprint.method.accessFlags = AccessFlags.PUBLIC.value;
val getPlayerIndex = enterServerInsertedAdBreakStateFingerprint.patternMatch!!.startIndex
enterServerInsertedAdBreakStateFingerprint.method.apply {
// Get register that stores VideoPlayer:
// invoke-virtual ->getPrimaryPlayer()
// move-result-object { playerRegister }
val playerRegister = getInstruction<OneRegisterInstruction>(getPlayerIndex + 1).registerA
// Reuse the params from the original method:
// p0 = ServerInsertedAdBreakState
// p1 = AdBreakTrigger
addInstructions(
getPlayerIndex + 2,
"""
invoke-static { p0, p1, v$playerRegister }, Lapp/revanced/extension/primevideo/ads/SkipAdsPatch;->enterServerInsertedAdBreakState(Lcom/amazon/avod/media/ads/internal/state/ServerInsertedAdBreakState;Lcom/amazon/avod/media/ads/internal/state/AdBreakTrigger;Lcom/amazon/avod/media/playback/VideoPlayer;)V
return-void
"""
)
}
}
}

View File

@ -0,0 +1,5 @@
package app.revanced.patches.primevideo.misc.extension
import app.revanced.patches.shared.misc.extension.sharedExtensionPatch
val sharedExtensionPatch = sharedExtensionPatch("primevideo", applicationInitHook)

View File

@ -0,0 +1,9 @@
package app.revanced.patches.primevideo.misc.extension
import app.revanced.patches.shared.misc.extension.extensionHook
internal val applicationInitHook = extensionHook {
custom { method, classDef ->
method.name == "onCreate" && classDef.endsWith("/SplashScreenActivity;")
}
}