tv librarian
tvLibrarian · sources · schema v1International live-TV source. Pick a country on the 2D world map (or the country list) → a channel list (filtered to playable HLS streams) → tune a channel and its live picture streams in as an UNTAINTED video texture (validated under the app's COEP require-corp headers: famelack HLS plays + yields a clean WebGL2 texture, so VIDEO out is a real downstream-usable texture, not play-only) plus stereo audio_l/audio_r from the stream's audio track. The "random" button (and the random/next CV trigger inputs) jump channels for happy-accident channel-surfing. Gate outputs: channel_changed pulses on each tune (trigger), stream_online holds high while the stream actually plays (gate). Dead/geo-blocked/unlicensed-pulled streams fail cleanly → marked "unavailable" + auto-skipped, never a hang or a tainted texture. Channel selection persists on the node + syncs to rack-mates (everyone tunes to the same stream). LEGAL: streams are THIRD-PARTY public streams, NOT hosted by patchtogether — this is a player pointed at the same iptv-org-derived directory many "free live TV" sites use; an in-card disclaimer + attribution (Famelack, MIT-licensed dataset fetched at runtime; iptv-org) ship with it, geo-blocked entries are honored/marked, and dead links are filtered. Plan + legal posture: .myrobots/plans/tv-librarian-module-2026-06-14.md.
the faceplate
inputs
| id | cable | what it does |
|---|---|---|
next | gate | Trigger (gate cable, edge:'trigger'): a rising edge advances to the NEXT channel in the current country's list, wrapping to the first. Level-while-high does nothing; it fires once per rising edge. Patch a clock here to channel-surf in time. gate / trigger; modulates cv_next (summed directly (the destination DSP scales it)); trigger — fires once per rising edge |
random | gate | Trigger (gate cable, edge:'trigger'): a rising edge tunes a RANDOM channel from the current country (picked from the OTHERS when more than one exists, so it reliably changes). Fires once per rising edge, not while held. gate / trigger; modulates cv_random (summed directly (the destination DSP scales it)); trigger — fires once per rising edge |
outputs
| id | cable | what it does |
|---|---|---|
video | video | The live stream's frame as a video texture (untainted/downstream-usable for streams that send CORS/ACAO). Dim near-black gradient when nothing is tuned. RGB video stream |
audio_l | audio | Left channel of the tuned stream's stereo audio (split from the stream's MediaElementSource). Silent (gain-0 constant source) when no stream is playing. audio signal |
audio_r | audio | Right channel of the tuned stream's stereo audio. Silent (gain-0 constant source) when no stream is playing. audio signal |
channel_changed | gate | Trigger out (gate cable, edge:'trigger'): one short rising-edge pulse each time a new channel is tuned. Patch into a downstream clock/reset/sample-and-hold. gate / trigger; trigger — fires once per rising edge |
stream_online | gate | Gate out (gate cable, edge:'gate'): held high while the stream is actually playing, low while loading, idle, or unavailable. gate / trigger; gate — acts while the level is high (reacts to both edges) |
params
| id | label | range | default | curve |
|---|---|---|---|---|
gain | Gain | 0..2 | — | linear |
cv_next | Next | 0..1 | 0 | linear |
cv_random | Random | 0..1 | 0 | linear |
controls
| control | what it does |
|---|---|
| Next | Next (hidden synthetic param, 0 to 1, default 0): the CV bridge writes the next input's gate level here; the card polls readParam and edge-detects a rising edge (<0.5 → >=0.5) to advance one channel. Not a user-facing knob. |
| Random | Random (hidden synthetic param, 0 to 1, default 0): the CV bridge writes the random input's gate level here; the card polls readParam and edge-detects a rising edge to tune a random channel. Not a user-facing knob. |
| Gain | Gain — declared output-level param (0 to 2, linear; default 1.0). NOTE: the passthrough shader does not currently read it (no uGain uniform / draw() never applies it), so it is carried on the module but inert in v1 — it does not yet brighten or scale the video output. |
source
tv-librarian.ts on GitHub.