Files
LlamaCasty/TASKS/research-youtube-api.md
gramps 87509bcf99 docs: restructure TASKS.md into a catalog — one file per task in TASKS/
TASKS.md is now the index (status table, open items, research pointer).
33 files: 32 task files + 1 research facts file. The full take-saga
narrative and all design decisions are preserved verbatim; the catalog
makes the queue readable without opening every task body. Schema and
AGENTS.md updated to reflect the new layout.
2026-09-05 16:31:46 -07:00

3.6 KiB

ytLlive — YouTube Live API research facts (authoritative)

Catalog: TASKS.md · memory map: schema.md.

YouTube Live API — research facts (authoritative, v3 build)

Lifecycle: created → ready → [testing] → live → complete (transitional liveStarting / testStarting).

  1. liveBroadcasts.insert requires: snippet.title, snippet.scheduledStartTime, status.privacyStatus, status.selfDeclaredMadeForKids (COPPA).
  2. liveStreams.insert requires: snippet.title, cdn.frameRate, cdn.ingestionType, cdn.resolution. None of the four (except title) can ever change after creation — changing them means delete + recreate the stream. This is the hard constraint behind the quality grey-out.
  3. Title / description / privacy: editable at any time, including while live (liveBroadcasts.update, part=snippet,status).
  4. contentDetails (DVR, recordFromStart, monitorStream, embed, latency): editable only in created / ready.
  5. Transition to live only allowed when the bound stream's status.streamStatus == active.

Two features that reshape the design

  1. enableAutoStart / enableAutoStop — instant one-click go-live, no transition call. With enableAutoStart=true we never call transition(live): the broadcast auto-goes-live the moment the encoder starts. Combined with enableMonitorStream=false (our preview pane replaces YouTube's monitor stream — the thing that forces a testing stage), the flow is create → bind → Start Stream → encoder starts → YouTube brings it live. No testing, no transition polling, no liveStarting stuck-state handling.
  2. cdn.resolution=variable / cdn.frameRate=variable — free auto step-down. YouTube auto-detects what we send; since we ARE the encoder we can drop bitrate/resolution on the fly with zero API calls. Declaring an explicit resolution instead (e.g. 1080p) requires a new stream, which can't happen mid-broadcast. Variable is the enabler for the whole auto step-down feature. (Claim-check 2026-09-01: the enabler is real, the governor is not built — the drop-side policy ships as TASK 33, v1 per the complete-v1 ruling.)

Compliance gotchas (maps perfectly to report-by-exception)

  1. liveStreams.status.healthStatus: good | ok | bad | noData plus configurationIssues[] with type + severity (info|warning|error). Literally built for report-by-exception — poll it, render nothing on good/ok, surface a banner only on warning/error. No need to invent our own health logic.
  2. Encoder must comply or YouTube flags it: keyframes ≤ 4s (gopSizeLong), closed GOP, H.264, audio AAC/MP3 @ 44.1/48kHz, mono/stereo only.
  3. Error codes to handle: errorStreamInactive, invalidTransition, redundantTransition, liveStreamDeletionNotAllowed, liveStreamModificationNotAllowed, liveBroadcastBindingNotAllowed.

Tips we should take advantage of

  1. Reusable streams (isReusable=true): one stream per channel, cache its ingestion URL + stream name, reuse for every broadcast. No rebinding dance each go-live. This is exactly the manual-stream-key baseline.
  2. Backup ingestion address: YouTube provides a simultaneous-push backup — future hardening, not v1.
  3. recordFromStart + enableDvr default true → every live is auto-recorded and immediately replayable. Free VOD archive, matches the v0.2 recording goal.
  4. latencyPreference: normal | low | ultraLow — for homelab streamers talking to chat, low (or ultraLow, capped at 1080p) is a real feature.
  5. Broadcast ID == Video ID — one ID to track everything.