Obbystreams API Reference
API
The API is JSON over HTTP. Guarded routes require either:
x-obbystreams-token: <token>obbystreams_token=<token>cookie
Tokens come from dashboard.session_token in the YAML config.
Login
POST /api/auth/login
content-type: application/json
{"password":"dashboard-password"}
Success:
{"ok":true,"token":"configured-session-token"}
The response also sets obbystreams_token.
Health
GET /api/health
No auth is required.
Successful ready response:
{
"ok": true,
"ready": true,
"checks": {
"managed_process": true,
"links_configured": true,
"playlist_ready": true,
"playlist_fresh": true
},
"health": {
"state": "healthy",
"level": "ok",
"message": "Stream is producing fresh HLS output."
}
}
The endpoint returns 503 when checks fail.
Status
GET /api/status
x-obbystreams-token: <token>
Returns:
- sanitized config
- managed process metrics
- existing unmanaged stream processes
- HLS metrics
- health assessment
- recent events
- recent logs
- recent errors
- runtime counters
Config
Read sanitized config:
GET /api/config
x-obbystreams-token: <token>
Update stream config:
PUT /api/config
content-type: application/json
x-obbystreams-token: <token>
{
"encoder": "auto",
"bitrate": "6M",
"audio_bitrate": "192k",
"public_hls_url": "https://live.example/stream/ufc.m3u8",
"links": ["https://example.com/live.m3u8"]
}
Accepted keys:
linksencoderbitrateaudio_bitrateoutput_dirpublic_hls_urlauto_recoverauto_restart_on_exitwatchdog_restart_cooldownstartup_grace_secondsplaylist_stale_seconds
Some changes restart a running stream automatically.
Links
links are now a compatibility view over structured stream sources. New cockpit features should use source endpoints.
Add:
POST /api/links
content-type: application/json
x-obbystreams-token: <token>
{"url":"https://example.com/live.m3u8"}
Remove:
POST /api/links/remove
content-type: application/json
x-obbystreams-token: <token>
{"url":"https://example.com/live.m3u8"}
Links must be HTTP(S), are deduplicated, and are normalized before being written to config.
Sources
Sources are guarded cockpit records with stable IDs, labels, type, URL, enabled state, and optional private headers. Headers are used by the proxy/ffmpeg path and are not returned by public endpoints.
List configured source status:
GET /api/sources
x-obbystreams-token: <token>
Switch the running cockpit preference to a source:
POST /api/sources/activate
content-type: application/json
x-obbystreams-token: <token>
{"id":"source-2"}
Recover a sour-signal source by scraping a replacement playlist:
POST /api/sources/recover-soursignal
content-type: application/json
x-obbystreams-token: <token>
{"id":"sour-signal-main"}
Private IPTV Automation
Private IPTV routes are guarded cockpit routes. They manage automatic discovery of the official/private ffmpeg source from the authenticated provider playlist. They do not create public watcher sources.
Read runtime state:
GET /api/private-iptv
x-obbystreams-token: <token>
Force an immediate refresh:
POST /api/private-iptv/refresh
content-type: application/json
x-obbystreams-token: <token>
{}
The refresh flow:
- Fetches
private_iptv.provider_urlor usesprivate_iptv.playlist_url. - Parses M3U
#EXTINFrows. - Scores UFC/MMA/fight-day candidates and rejects placeholders such as “No Scheduled Event”, 24/7, replay, and stale rows.
- Probes candidate playback for bad-but-valid responses: HTML block pages, empty playlists, dead variants, ended tiny windows, and unreadable segments.
- Writes accepted private entries to
stream.sourcesusing the configured auto-source prefix. - Disables auto-created private candidates when inactive. Managed ffmpeg stays live by default unless
keep_stream_live_when_inactiveis explicitly false.
Private sour-signal playback probes are connection-budget aware. POST /api/private-iptv/refresh respects the budget unless the body includes {"force_probe": true}.
Provider cookies and sensitive headers are redacted from config/status responses.
Public watcher endpoints:
GET /api/public-configured-sources
GET /api/public-streams
GET /api/news
GET /api/live
GET /api/viewers
POST /api/viewers
/api/public-configured-sources returns the synthetic server-1 managed source for the official ffmpeg output.
/api/public-streams returns separately managed pasted public internet streams. Each item includes url plus a CORS-safe playback_url that points through /api/proxy-hls. These records are not official ffmpeg sources and do not affect stream.sources. Public records may carry server-side headers such as Referer, Origin, or User-Agent; the proxy applies those headers while keeping browser playback on s.obby.ca.
/api/news returns visible ObbyWatcher news/changelog entries managed by the cockpit. Entries are plain text fields with title, body, tone, pinned, timestamps, and optional link_url; hidden entries stay available in cockpit config but are excluded from the public endpoint.
Operator-only news management:
POST /api/news
content-type: application/json
x-obbystreams-token: <token>
{"title":"Main card live","body":"Use Server 1 first; public backups are available.","tone":"info","visible":true,"pinned":true}
POST /api/news/remove
content-type: application/json
x-obbystreams-token: <token>
{"id":"news-1781990000000"}
The current production public source inventory and nested-playlist notes live in public_srcs.md.
Stream Actions
Start:
POST /api/stream/start
content-type: application/json
x-obbystreams-token: <token>
{"kill_existing":true}
Start with one-off links:
{"kill_existing":true,"links":["https://example.com/live.m3u8"]}
Stop:
POST /api/stream/stop
x-obbystreams-token: <token>
Restart:
POST /api/stream/restart
content-type: application/json
x-obbystreams-token: <token>
{"kill_existing":true}
ArangoDB
GET /api/arango
x-obbystreams-token: <token>
Returns whether the configured ArangoDB endpoint is reachable from the app.
NVIDIA SMI
GET /api/nvidia-smi
x-obbystreams-token: <token>
Returns cached NVIDIA GPU telemetry. The collector runs at most once every five seconds and reports:
- GPU name, UUID, driver, pstate, clocks, temperature, utilization, memory, and power.
- NVENC encoder session count, average FPS, and average latency when supported.
- Compute and
pmonprocess rows. - Whether an ffmpeg/NVENC process appears active.
- Command summaries for failed optional
nvidia-smiqueries.
If nvidia-smi is unavailable, the route still returns ok: true with available: false so the frontend can display degraded GPU telemetry without breaking the dashboard.
Stream Control (persistent)
POST /api/stream/start
POST /api/stream/stop
POST /api/stream/restart
stop persists stream.operator_stopped: true (kills ffmpeg AND idles both
scrapers until an explicit start); start and restart clear it. The flag
survives supervisor ticks and full restarts. stop responds with
{"ok": true, "stopped": <bool>, "operator_stopped": true}. Current state is
exposed at runtime.operator_stopped in GET /api/status.
Blacklist
GET /api/blacklist
POST /api/blacklist { "url"?, "id"?, "label"?, "channel"?, "reason"? }
POST /api/blacklist/remove { "url"? , "id"? }
POST /api/blacklist persists a block (matching by URL, URL-without-query, id,
channel, or label) and immediately strips matching entries from public_sources
and stream.sources. Blocked sources are filtered from every scraper cycle and
every viewer-facing list. add requires at least one of url/id/label/channel
(400 otherwise). See Persistent Stop & Source Blacklist.
HLS Proxy
GET /hls/ufc.m3u8
GET /hls/ufc123.ts
The proxy:
- Serves files from
stream.output_dirwhen present. - Rewrites relative playlist segment paths to
/hls/*. - Falls back to
stream.public_hls_url. - Falls back to the hardcoded fight stream URL used by the existing deployment.
The HLS proxy is intentionally unauthenticated so the browser player can load media once the dashboard shell is open.