Skip to content

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().

ClassDescription
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 True when url is a Q4 webcast/asset host.

  • Return type: bool
  • Parameters: url (str)