Clear-slate project that:
- Streams to YouTube from GitHub-hosted runners (Chromium + Xvfb + FFmpeg → RTMP).
- Hands off every ~55 minutes from
livestream.ymltocontinue-livestream.yml(and back), so the broadcast keeps going across jobs. - Ships a control website to store secrets, design the on-air screen, and start/stop the stream.
Serve the repo root (needed so /web can load /overlay + /config):
python3 -m http.server 8765Open http://127.0.0.1:8765/web/.
In Connect, enter:
- GitHub owner / repo
- A PAT with access to Actions, Secrets, Variables, and Contents on this repository
Credentials stay in your browser localStorage only.
In Secrets, push:
| Secret | Purpose |
|---|---|
YOUTUBE_STREAM_KEY |
YouTube Studio → Go live → Stream key |
YOUTUBE_RTMP_URL |
Optional; default rtmp://a.rtmp.youtube.com/live2 |
STREAM_CONTROL_TOKEN |
Optional PAT used by runners to trigger the next workflow + set variables |
Also create a YouTube live stream (or scheduled premiere) in YouTube Studio and keep it waiting for the encoder. Enabled entries in the Music queue are downloaded by yt-dlp on the runner and supplied to FFmpeg as the stream audio; the runner also accepts local files in config/audio.
In On-air screen, set brand, title, background, optional full-bleed embedded website, and any number of widgets (iframes, ON AIR badge, clock, ticker, custom text).
Each widget has its own:
- Position (X/Y with
%orpx, plus presets like top-left / right-panel / full) - Size (width/height with
%orpx) - Amount — add, duplicate, or remove freely (multiple iframes are supported)
Save scene to repo writes config/stream-config.json.
- Start stream dispatches
livestream.ymland setsSTREAM_ACTIVE=true. - Near the end of each ~55m segment the runner triggers the other workflow so a new job reconnects to the same stream key (short overlap).
- End stream sets
STREAM_ACTIVE=falseand cancels in-progress livestream runs.
| File | Role |
|---|---|
.github/workflows/livestream.yml |
First / odd segments; hands off to continue-livestream.yml |
.github/workflows/continue-livestream.yml |
Even segments; hands off back to livestream.yml |
Manual runs: Actions → workflow → Run workflow.
bash scripts/dev.sh validate-config
bash scripts/dev.sh serve-overlay- GitHub-hosted jobs are capped (~6h max); this design uses ~1h segments with an explicit cross-workflow handoff.
- YouTube must allow encoder reconnect on the same stream key (default for many live events).
- Embedded third-party sites may block iframes (
X-Frame-Options); use a page that allows embedding when choosing “Embed website”. - Prefer a classic/fine-grained PAT as
STREAM_CONTROL_TOKENso runners can reliablygh workflow runthe sibling workflow and update variables.