Repository navigation
Dashboard HTTP API
The web dashboard is a static page talking to a small JSON API
on the same port. The API can also be used directly — from a script, a
home-automation system or curl — for example to read the current HDR format
or to switch VS10 modes.
The API is an internal interface of the dashboard. It is stable in practice but not versioned; check this page after updates.
Base URL: http://<box-ip>:<port> (port 8099 by default). The server
listens on IPv6 and IPv4, e.g. http://[fd00::20]:8099.
Send the access token in the X-TinyPPI-Token header. Only the header
counts: a token query parameter is ignored since 2.15.1, because an
address ends up in histories and logs.
curl -H 'X-TinyPPI-Token: ABCD2345' http://192.168.1.20:8099/api/stateA browser cannot send a header with an EventSource or an <img>, so the
page trades the token for a read session cookie first (see
POST /api/session). The cookie counts as
the token for the read routes only. Scripts simply send the header on every
request.
| Route type | Token required |
|---|---|
GET /api/hello |
never |
Other GET routes ("readers") |
only with Require the token for reading too on, from a client beyond the home network (see Dashboard Security), or under an untrusted Host name (see Dashboard Security); the read session cookie counts as the token |
POST /api/session |
always (the header), but not Allow VS10 switching |
All other POST routes ("writers") |
always (the header — the cookie does not count), and Allow VS10 switching from the dashboard must be on |
Errors are JSON: {"error": "<message>"}.
| Status | Body | Meaning |
|---|---|---|
| 400 |
bad body length, bad JSON, unknown mode, command failed, playback failed, update failed, watched required, no title named
|
The request was not understood or the action failed. |
| 401 | token required |
Missing or wrong token (in the header). |
| 403 | control disabled |
A write with Allow VS10 switching off. |
| 403 | library disabled |
The film/series library is switched off (or control is off). |
| 404 |
no such route, no such artwork, no artwork, no such series
|
Unknown path, or nothing to return. |
| 429 |
too many wrong tokens (+ retry_ms, Retry-After) |
The address (beyond the home network: its IPv6 /64) is locked out for guessing. |
| 503 |
too many streams / shutting down (+ retry_ms) |
All six stream slots are taken, or Kodi is shutting down. |
| 503 | library unavailable |
The video database could not be read. |
Start-up information for the page. No token, no player state.
{
"name": "TinyPPI",
"version": "2.15.1",
"auth_read": false,
"control": true,
"library": true,
"series": true,
"interval_ms": 200,
"strings": { "...": "localized UI strings" }
}| Field | Meaning |
|---|---|
auth_read |
Whether this request would need the token to read (setting, client beyond the home network, or untrusted host). |
control |
Allow VS10 switching from the dashboard. |
library / series
|
Whether the film / series shelves are offered (each needs its setting and control). |
interval_ms |
How often a watched snapshot is rebuilt (200 ms). |
The current snapshot, once. Use it for polling when you don't want a stream.
While something plays the snapshot contains, among others:
| Key | Content |
|---|---|
seq |
Snapshot sequence number. |
playing, paused
|
Player state. |
title, filename
|
Title; the file name only when Show file name is on. |
hdr_type |
Source format: "" (SDR), hdr10, hdr10plus, hlg, dolbyvision. |
effective |
The type the overlay layout follows (differs during VS10 conversion). |
output_type |
The format actually being output. |
time, duration, finish
|
Position, duration, and the clock time it ends at (box's regional format). |
metrics |
Cache, frame rate and other figures for the metric tiles. |
groups |
The overlay's rows as cards: [{id, title, rows: [{id, label, value, detail}]}]. Card ids: video, processing, audio, system, hdr, dv, metadata. |
metadata |
The Dolby Vision metadata list (only for Dolby Vision, with Show the Dolby Vision metadata view on). |
vs10 |
{"options": [{"mode", "label"}], "output": "…"} — the switchable modes for this source and the current output. |
art |
Tags of the playing title's artwork (used in /api/art URLs). |
media |
year, genre, show, season, episode. |
controls |
What the remote can offer: audio tracks, subtitles, chapters … |
session |
{seq, switches, warnings} — when seq changes, re-read /api/history. |
library |
The library version; when it changes, re-read the shelves. |
control |
Same as in /api/hello. |
streams_full |
Whether a stream request would currently be refused. |
With nothing playing: playing: false, empty groups/metadata, plus last
— the summary of the title that ended within the last ten minutes
(title, position, ago, switches, warnings, peak, events).
Example — read the source format with jq:
curl -s http://192.168.1.20:8099/api/state | jq -r '.hdr_type, .output_type'A Server-Sent Events stream of snapshots. One stream slot of six is held while connected.
| Event | Data |
|---|---|
state |
The first frame: a complete snapshot (as /api/state). |
delta |
Every following frame: only what changed (see below). |
bye |
{"retry_ms": 20000} — the server is stopping; wait before reconnecting. |
: ping (comment)
|
Heartbeat every 15 s on an idle stream. |
A delta frame has the shape:
{
"seq": 1234,
"set": { "time": "01:12:45", "metrics": { "...": "..." } },
"del": ["some_key"],
"groups": { "rows": [["<row id>", "<value>", "<detail>"]] },
"metadata": { "rows": [[17, "<value or cells>"]] }
}-
set— top-level keys whose value changed, sent whole. -
del— top-level keys that disappeared. -
groups/metadata— either{"rows": [...]}with only the changed rows (while the card/row layout is unchanged), or the complete new list when the layout changed.
Frames come at most five times a second, and only when something moved.
curl -N -H 'X-TinyPPI-Token: ABCD2345' http://192.168.1.20:8099/api/streamThe chart and event history of the current (or just finished) title:
{
"now": 4380.2, "step": 1.0,
"t": [0.0, 1.0, "..."], "max": [812.3, "..."], "avg": [96.1, "..."],
"events": [{"t": 1203.4, "pos": "00:20:03", "kind": "audio", "...": "..."}],
"seq": 7, "switches": 3
}t is seconds since playback started; max / avg are L1 peak and average in
nits (null outside Dolby Vision). Event kinds: vs10, mode, audio,
subtitle, fps, temperature, cpu.
The film library: {"movies": [...], "count": N, "tag": "…"}. Each film:
id, title, poster (tag), and when known year, duration (seconds),
watched, resume, rating, added. The response has an ETag; send it
back as If-None-Match to get a cheap 304 Not Modified.
The series library: {"shows": [...], "count": N, "tag": "…"}.
The episodes of one series: {"tvshowid", "title", "episodes": [...], "count", "tag"}.
404 no such series means the library changed; reload /api/series.
Films and episodes stopped part-way, newest first (up to 30):
{"items": [{"kind": "movie" | "episode", ...}], "count", "tag"}.
Artwork: kind is poster, fanart or thumb. Without an id, the playing
title's artwork. With a v tag the answer is cacheable for a week
(immutable); the tag must be plain hex (as the snapshot and the lists give
it), anything else is ignored and the answer is not cached. Images are served
from Kodi's texture cache where possible.
Trades the token for the read session cookie the page's stream and pictures
use. Needs the token in the header and a JSON body ({}); works with
Allow VS10 switching off.
curl -i -X POST -H 'X-TinyPPI-Token: ABCD2345' -H 'Content-Type: application/json' \
-d '{}' http://192.168.1.20:8099/api/sessionThe answer is {"ok": true} with
Set-Cookie: tinyppi_session=…; Path=/api/; HttpOnly; SameSite=Strict. The
cookie is valid for the read routes only, ends with the browser session, and
ends for everyone when the dashboard's server restarts (a new token
included).
All take a JSON body (max 4 KB), need the token in the header and Allow VS10 switching.
curl -X POST -H 'X-TinyPPI-Token: ABCD2345' -H 'Content-Type: application/json' \
-d '{"mode": "hdr10"}' http://192.168.1.20:8099/api/modeAccepted modes are exactly the dashboard's buttons: original_sdr, hdr10,
dv, original_hdr, sdr8, original_dv. The call returns at once
({"ok": true, "mode": "hdr10"}); the switch runs in the background, and a
newer request replaces one still waiting. For sdr10 and original_hlg use
RunScript(script.tinyppi,run_mode,…) (see
Launching and Keymaps).
Body: {"action": "<action>", "value": <value>}.
| Action | Value | Effect |
|---|---|---|
playpause |
— | Toggle pause. |
stop |
— | Stop playback. |
seek |
seconds, −3600 … 3600 | Relative seek. |
seek_percent |
0 … 100 | Absolute seek (relative to the EPG event on live TV). |
volume_up / volume_down / mute
|
— | Sent as remote actions (CEC-friendly). |
volume |
0 … 100 | Absolute Kodi volume (kept for older clients). |
chapter_previous / chapter_next
|
— | Chapter skip; fails without at least two chapters. |
audio |
stream index 0 … 64 | Select an audio track. |
subtitle |
index 0 … 64, or −1 | Select and enable a subtitle; −1 turns subtitles off. |
curl -X POST -H 'X-TinyPPI-Token: ABCD2345' -H 'Content-Type: application/json' \
-d '{"action": "seek", "value": 30}' http://192.168.1.20:8099/api/command{"movieid": 123} or {"episodeid": 456}; add "resume": false to start from
the beginning (anything else resumes).
{"movieid": 123, "watched": true} — or tvshowid (every episode) or
episodeid. watched must be a boolean.
{"movieid": 123} or {"episodeid": 456}.
/, /index.html, /metadata, /metadata.html, /manifest.webmanifest,
/icon.png, /fanart.png, and the page's own css/, js/ and icons/
files. They are served gzip-compressed (when the browser accepts it) with an
ETag, so a revisit is answered with 304.
User guide
- Installation
- Getting Started
- Launching and Keymaps
- The TinyPPI Overlay
- Dolby Vision Metadata View
- VS10 Output Modes
- Codec Logos
- Channel Layout Graphic
- IMAX Detection
- Colors and Themes
Web dashboard
Reference
Developers
Project