Zapping should not wait on the network. The app knows which node serves each channel (routes), builds the playback token itself, and opens the stream straight on that node. The panel is only involved for the slow path.
app ──(1) GET playback-routes, every 60 s, in the background──► gateway ─► panel
app ──(2) build token locally (AES-GCM + HMAC, < 1 ms)
app ──(3) GET https://node/<token>~<session_token>──────────────► streaming node
Needs the capabilities client_playback_tokens and playback_routes.
Otherwise use the slow path (7.5) for everything.
7.1 Routes: playback-routes
GET /api/v2/playback-routes
Authorization: Bearer <session_token>
If-None-Match: "<ETag of the previous answer>"
Accept-Encoding: gzip
{
"ttl": 60,
"nodes": {
"3": { "hosts": ["lb1.example.com", "203.0.113.5"], "http_ports": [80],
"https_ports": [443], "prefix": "", "direct": true, "thumbnails": true,
"reports": true },
"5": { "hosts": ["lb2.example.com"], "http_ports": [80], "https_ports": [],
"prefix": "", "direct": true, "thumbnails": false, "reports": false }
},
"default": { "nodes": [3, 5], "spread": 2, "pictures": [3] },
"channels": { "123": { "nodes": [5], "spread": 1 }, "140": { "nodes": [], "spread": 1 } }
}
Refresh every ttl seconds with If-None-Match; 304 means nothing changed.
Send Accept-Encoding: gzip: on a large panel the map is about 260 KB and
about 35 KB compressed. Each encoding has its own ETag.
To play channel id:
- Take
channels[id], ordefaultif it is not listed.nodes: []means the channel is not available right now: show it as unavailable. - Pick one of the first
spreadnodes at random (they are already running it); on failure, continue with the rest in order. - Use the node's
hostsin order (names before IPs),httpswhen it has an HTTPS port, and putprefixbefore the path.https_portslists only ports the node saw open in its last heartbeat andhttp_portsleaves out the ones it saw closed: preferhttpswhenever the node has one. With a reverse proxy,hostsare the proxies' and the node's own IPs are left out. Emptyhostsmeans the node cannot be reached right now (its reverse proxy is down): skip it. - Use app-built tokens on nodes with
direct: true. A node withdirect: falsemay refuse them: use the slow path (7.5) there. - Send playback reports (7.7) only to nodes with
reports: true. pictures(capabilitypicture_routes) lists, in the same order, the nodes ofnodeswhere the channel runs always-on: only those keep its picture (7.6). Missing means no node has one: show the logo.
A web app served over HTTPS cannot load http:// media, and certificates
are not valid for bare IPs. Skip IP hosts for HTTPS and nodes without an
HTTPS port.
Movies and episodes: GET /api/v2/playback-routes?type=vod&ids=4321,4322 (movie ids)
(type=saga for episodes; up to 200 ids):
{ "ttl": 60, "nodes": { "3": { "…": "…" } }, "items": { "4321": [3] } }
Ids with no live node (or that do not exist) are left out of items. The
node checks the line's package when it opens the stream.