mostlyright.finance.transcripts.capture.q4
Q4 browser-webcast capture adapter.
Q4 (events.q4inc.com / *.q4cdn.com) is the widest large-cap coverage
provider (~50% of the S&P 500). Its browser-webcast template exposes a static
progressive MP4 at
https://static.events.q4inc.com/edited-recordings/{eventId}/{uuid}.mp4 that
answers a plain ranged GET with 206 and no cookies, with any referer or none:
the guest form gates the page, not the asset.
Capture path (public, no circumvention):
: 1. cold ranged-GET the static static.events.q4inc.com/.../*.mp4 directly
with a User-Agent only — no cookie, token, or Authorization header. The
replay path needs no guest-page navigation, because the guest form gates the
page rather than the asset. An injected client is still accepted for later
gated providers (such as the Notified MX gate), but the static asset does not
need one.
2. extract audio to a transient temp file and return an
AudioArtifact whose cleanup() deletes it (never persisted).
The Q4 analyst dial-in template is a telephone bridge with no HTTP media, so
CaptureNotAvailableError is raised and the caller routes to dial-in
capture or skips, rather than producing empty audio.
This is the replay path: the static MP4 exists only after the call. The
live-during-call Q4 endpoint (Amazon IVS playback.live-video.net) is reached
through live().
Classes
Section titled “Classes”| Class | Description |
|---|---|
Q4CaptureAdapter() | Q4 browser-webcast replay capture over the public guest path. |
class mostlyright.finance.transcripts.capture.q4.Q4CaptureAdapter
Section titled “class mostlyright.finance.transcripts.capture.q4.Q4CaptureAdapter”Bases: CaptureAdapter
Q4 browser-webcast replay capture over the public guest path.
capture(event, , client=None, transport=None, tmp_dir=None, **_)
Section titled “capture(event, , client=None, transport=None, tmp_dir=None, **_)”Cold-fetch the Q4 static MP4 and extract transient audio.
event carries ticker / call_id / media_url (the sniffed
static.events.q4inc.com/.../*.mp4 currentSrc). When media_url is
absent the event is the analyst dial-in template (no HTTP media) —
CaptureNotAvailableError is raised.
client may be an injected httpx.Client (a guest-flow session for
later gated providers). transport is the explicit transport the cold
media fetch rides on; tests pass an httpx.MockTransport directly.
The cold media fetch is always issued through a fresh User-Agent-only
client built here (from transport when given). It deliberately does not
inherit the injected client’s cookies or default headers, so no cookie,
token, or Authorization header can leak onto the asset GET — the guest form
gates the page, not the asset. When only client is given with no
explicit transport, the media fetch reuses that client’s transport via
httpx.Client._transport so a mock host still serves the request,
but starts from a clean header set and empty cookie jar.
media_url is validated (https plus a Q4 media host) before any fetch;
an unvalidated cold GET would be an SSRF sink. The media fetch uses
generous timeouts rather than httpx’s flat 5s default, which would abort a
full MP4 stream at the read deadline. A borrowed transport — from an
injected client or the explicit transport param — is never closed
here; only a transport this method created itself is, because closing a
borrowed shared transport would break the caller’s injected client.
A 2xx/206 carrying a zero-byte body (an expired or edited replay that
answers the range but serves no media) raises
CaptureNotAvailableError instead of writing an empty MP4 that
flows to STT: the byte count is tracked during the stream loop and an empty
result fails loud.
The fetch is also bounded on size and total time. media_url is external
event data and the SSRF allowlist bounds only the host, not the object
size, so an asset over _MAX_MEDIA_BYTES is rejected up front from
its declared Content-Range/Content-Length and, as a backstop,
aborted mid-stream once the written bytes exceed the cap. A slow-drip
source that never trips the per-operation read timeout is aborted at the
_MEDIA_TOTAL_TIMEOUT wall-clock deadline. All abort paths unlink
the partial MP4 via the outer finally, so an oversized or slow asset
can never fill the ingest host’s temp disk or flow to STT.
- Return type:
AudioArtifact - Parameters:
detect(url)
Section titled “detect(url)”Return True when url is a Q4 webcast/asset host.