mostlyright.finance.transcripts.capture.base
Capture-adapter ABC + the transient audio artifact.
The provider-aware webcast capture contract. Each adapter
``detect“s the webcast URLs it handles and
``capture“s an earnings event into an
AudioArtifact — a TRANSIENT temp file that is DELETED after
transcription (legal guardrail: captured audio is never stored-and-served
only text / derived facts survive).
The ABC is structured so the live-during-call seam slots in cleanly
(Wave 5) adds a live() override for the Amazon-IVS live path
(playback.live-video.net → audio_only rendition). This plan is the
VOD/replay path only (the static MP4 exists only AFTER the call), so live()
is intentionally NOT on the ABC yet — the shape (detect + capture +
AudioArtifact) is the seam it will extend.
Classes
Section titled “Classes”AudioArtifact(audio_path, ticker, call_id, …) | A captured-audio handle whose backing file is TRANSIENT. |
|---|---|
CaptureAdapter() | Provider-aware webcast capture contract. |
Exceptions
Section titled “Exceptions”LiveCaptureUnsupported([message, …]) | A capture adapter has NO live-during-call edge (W5). |
|---|
class mostlyright.finance.transcripts.capture.base.AudioArtifact(audio_path, ticker, call_id, source_media_url, is_transient=True)
Section titled “class mostlyright.finance.transcripts.capture.base.AudioArtifact(audio_path, ticker, call_id, source_media_url, is_transient=True)”Bases: object
A captured-audio handle whose backing file is TRANSIENT.
audio_path points at a temp file extracted from the captured webcast
media. is_transient is True by design — the file MUST be deleted
after transcription (never persisted or served). cleanup() unlinks it;
the artifact is also a context manager, so with adapter.capture(...) as a
guarantees the audio is gone on exit even if transcription raises.
source_media_url / call_id / ticker carry the capture lineage for
audit (which asset produced these bytes) without retaining the bytes.
audio_path: str
Section titled “audio_path: str”call_id: str
Section titled “call_id: str”cleanup()
Section titled “cleanup()”Delete the transient audio file (idempotent — safe to call twice).
FileNotFoundError (the idempotent double-call, or an already-cleaned
artifact) is suppressed SILENTLY. Any OTHER OSError (e.g.
PermissionError on a read-only mount) is suppressed but LOGGED at
error level: it must NOT propagate out of __exit__ (that would MASK
the original exception the with block was raising — the transcription
error the caller must see), but it means copyrighted earnings audio has
SURVIVED on disk (a violation), so it cannot pass silently — the
log line names the path an operator must reap manually.
- Return type:
None
is_transient: bool
Section titled “is_transient: bool”source_media_url: str
Section titled “source_media_url: str”ticker: str
Section titled “ticker: str”class mostlyright.finance.transcripts.capture.base.CaptureAdapter
Section titled “class mostlyright.finance.transcripts.capture.base.CaptureAdapter”Bases: ABC
Provider-aware webcast capture contract.
Concrete adapters (Q4CaptureAdapter, later Notified / GlobalMeet /
ChorusCall / self-hosted) implement detect() (does this adapter handle
the URL?) and capture() (event → transient AudioArtifact). A
live() override is added to the fleet in for the live-during-call
IVS path; this VOD/replay contract is the seam it extends.
abstractmethod capture(event, **kwargs)
Section titled “abstractmethod capture(event, **kwargs)”Capture event to a transient AudioArtifact.
MUST stay on the public path (no auth/DRM/captcha circumvention —)
and MUST return an artifact whose backing file is transient. Raise
CaptureNotAvailableError when the
provider template exposes no cold-fetchable HTTP media (e.g. a dial-in
bridge) rather than emitting empty audio.
- Return type:
AudioArtifact - Parameters:
abstractmethod detect(url)
Section titled “abstractmethod detect(url)”Return True iff this adapter handles url’s webcast provider.
live(manifest_url, session=None)
Section titled “live(manifest_url, session=None)”Follow the provider’s LIVE edge, yielding (pcm_frame, spoken_at) (W5).
Reserved live-during-call seam. A concrete adapter with a fetchable live
HLS edge would OVERRIDE this to open a rolling-window live capturer
against manifest_url and stream PCM frames into the streaming STT.
Audio is a TRANSIENT frame stream — the generator yields decoded
PCM into the consumer; it NEVER writes audio to disk or serves it.
The ABC DEFAULT raises LiveCaptureUnsupported: a provider with no
live edge (dial-in bridge, SABR/YouTube, Lumi/VOD-only) has no live path,
and the runner routes it to the authoritative post-call batch ledger
instead. session carries any header-gated context (Origin/
Referer/UA/token) a provider needs; Q4/IVS needs none.
exception mostlyright.finance.transcripts.capture.base.LiveCaptureUnsupported(message=”, , error_code=None, source=None, request_id=None)
Section titled “exception mostlyright.finance.transcripts.capture.base.LiveCaptureUnsupported(message=”, , error_code=None, source=None, request_id=None)”Bases: EarningsError
A capture adapter has NO live-during-call edge (W5).
ENGINE-LOCAL exception: it subclasses the core EarningsError so
callers filter it with the rest of the earnings-pipeline errors, but it is
deliberately NOT added to packages/core — the live seam is engine-only and
must never touch the parity surface (research() / merge/* /
_live/_sources.py). Raised by CaptureAdapter.live() (the ABC default)
for providers whose template has no fetchable live HLS edge — a dial-in bridge
(telephone), a SABR/YouTube stream we have not proven, or a Lumi/VOD-only
provider. The runner routes such a provider to the post-call batch path only
never opening a live session.
- Parameters:
- Return type: None
default_error_code: str
Section titled “default_error_code: str”Subclass override — the stable string enum surfaced via error_code.