Skip to content

Manager API

foonerd edited this page Oct 1, 2026 · 39 revisions

Manager API

The Manager is a web application the plugin serves on the player, on port 5582 unless the settings page moved it. Its page uses the routes below; so can anything else on the network: a script, a home automation system, a second page. There is no login, as with Volumio's own interface: the API is for the network the player is on.

Every route is under /api and answers JSON, except the page itself and the pictures and files it serves. Bodies are JSON with Content-Type: application/json, except the uploads, which take the file (a zip, a backup zip, a font) as the raw body. An error is { "error": "<code>", "message": "..." } with a 4xx or 5xx status; a code that starts with GLASS. is the key of one of the plugin's strings, which /api/i18n translates.

curl http://volumio.local:5582/api/status
curl -X POST -H 'Content-Type: application/json' -d '{"mode":"random","interval":60}' http://volumio.local:5582/api/meter

The page and its strings

Route Answer
GET / The page.
GET /api/i18n?lang=xx { "lang": "xx", "strings": { ... } }: the plugin's strings in that language, English behind them. Without lang, the player's language.

Status

Route Answer
GET /api/status The Status tab's data, below.
GET /api/diagnose { "symptoms": [...] }: the symptoms the guided diagnosis knows: no-meters, not-moving, restarts, touch, screen, artwork, remotes, slow, other.
POST /api/diagnose { "symptom" } runs the checks for it and answers { "symptom", "found": bool, "findings": [{ "check", "kind": "cause" | "note" | "ok", "key", "with": {...}, "go" }] }, likely causes first: key names the string (MANAGER_<key> in the strings), with the values it fills in, go the Manager's tab where it is set or null. 400 bad-symptom for one it does not know.
GET /api/diagnose/capture Where a report's capture stands: { "state": "idle" }, or { "state": "capturing" | "sending", "symptom", "startedAt", "until", "from", "to" }, the times in milliseconds and as the journal writes them by the player's clock.
POST /api/diagnose/capture { "symptom" } starts a capture: the checks are run and kept, the log level is raised to verbose, the display starts again, and the level goes back by itself after ten minutes. 409 capturing while one is under way.
POST /api/diagnose/capture/finish { "text" } ends it: the player's system log is sent through Volumio's submitter, the level goes back, and the report's parts come back: { "symptom", "startedAt", "endedAt", "from", "to", "text", "diagnosis", "log": { "link" } }, or "log": { "error": "not-sent" | "no-reply", "said", "kept": bool } when the log could not be sent, kept saying the file stayed on the player. 409 not-capturing.
POST /api/diagnose/capture/cancel Ends a capture with no report; the level goes back.
GET /api/diagnose/log The system log Volumio's submitter kept on the player when it could not send it, as a download; 404 no-log when there is none.
{
  "version": "0.7.40",
  "arch": "arm",
  "binary": true,
  "running": true,
  "display": "0",
  "headless": false,
  "timeout": 5,
  "activeTheme": "1280x720_g5_710_Turntables",
  "meter": { "theme": "...", "mode": "random", "names": [], "available": ["..."], "onTitle": false, "interval": 60 },
  "channel": { "clients": 1, "status": "play", "service": "mpd", "title": "...", "artist": "..." },
  "showing": { "theme": "1280x720_g5_710_Turntables", "meter": "142G5_01_Pioneer Gold", "rate": 30 },
  "logging": { "level": "warn", "targets": [], "levels": ["error", "warn", "info", "verbose", "trace"], "targetsAvailable": ["audio", "channel", "display", "remotes", "themes", "artwork", "manager", "settings"] },
  "performance": { "profile": "auto", "auto": "standard", "values": { "frameRate": 30, "rotationQuality": "medium", "rotationFps": 8, "transitions": true }, "valuesProfile": "standard", "board": { "model": "Raspberry Pi 5 Model B Rev 1.1", "cores": 4, "arch": "aarch64", "class": "pi5" }, "governor": true },
  "fonts": { "styles": { "light": { "kind": "builtin", "value": "builtin" }, "regular": { "kind": "builtin", "value": "builtin" }, "bold": { "kind": "custom", "value": "My Sans.ttf" }, "italic": { "kind": "builtin", "value": "builtin" }, "digi": { "kind": "builtin", "value": "builtin" } }, "uploaded": 1 },
  "themes": { "meterBase": "/data/INTERNAL/glass/templates", "meters": 40, "spectrumBase": "/data/INTERNAL/glass/templates_spectrum", "spectrum": 18 },
  "sharing": { "shared": true, "roots": ["/data/INTERNAL/glass/templates", "/data/INTERNAL/glass/templates_spectrum"] },
  "artwork": { "enabled": true, "keyMode": "project", "interval": 10, "order": "random", "cachedArtists": 12 },
  "cardash": { "enabled": true, "mode": "clock", "dayTheme": "...", "nightTheme": "...", "period": "day", "next": { "at": "<ISO time>", "period": "night" } },
  "interactive": "theme",
  "face": { "pages": 1, "frames": true, "hops": 1234 },
  "sheet": { "player": { "volumio": "4.204", "hardware": "pi", "board": "Raspberry Pi 5 Model B Rev 1.1", "backendUptimeS": 5400, "build": { "commit": "a19ee43", "built": "<ISO time>" } }, "addresses": [{ "name": "eth0", "address": "192.168.1.20" }], "screen": { "size": "1280x720", "mouse": false, "since": "<ISO time>" }, "audio": { "tapInChain": true, "output": "...", "service": "mpd", "trackType": "flac", "samplerate": "44.1 kHz", "bitdepth": "16 bit" }, "housekeeping": { "newestBackup": { "name": "before-0.7.43", "at": "<ISO time>" }, "problems": [] } },
  "upgrade": { "last": { "from": "0.7.42", "to": "0.7.43", "at": "<ISO time>", "phase": "done" }, "previous": { "version": "0.7.42", "at": "<ISO time>", "bytes": 69804357 } },
  "themeSize": "1280x720",
  "measured": true,
  "remotes": { "enabled": true, "serving": true, "ports": { "frames": 5580, "channel": 5581, "beacon": 5579, "manager": 5582 }, "receiving": 1, "connected": 1, "problem": null },
  "manager": { "port": 5582, "url": "http://volumio.local:5582/", "uptimeS": 780 },
  "catalog": { "fetchedAt": "...", "updated": "...", "count": 179, "installed": 1 },
  "rings": [ { "name": "glasstap.glass.7297.0", "tag": "glass", "pid": 7297, "rate": 44100, "channels": 2, "seq": 12345, "writtenAgoMs": 19, "live": true } ],
  "diskFree": 932000000000,
  "hostname": "volumio",
  "legacy": false,
  "language": "en",
  "jobs": 0
}
Field Meaning
binary Whether the display binary for this player's processor is in place.
running Whether the display is up (its run flag stands).
showing The meter the player's own display shows at the moment, as it last reported it, or null.
display, headless The X display chosen, and whether the player has no screen of its own.
measured While the player reports play: whether a live ring exists, so what plays passes the tap.
rings Every ring under /dev/shm, with its stream and how long ago it was written; live within three seconds.
remotes Whether remotes are served, the ports, how many receive frames, how many are connected, any problem the daemon or the channel reported.
fonts Each text style's face as /api/fonts reports it, without the lists, and how many fonts were uploaded.
themes The two theme folders and how many themes (folders with a meters.txt) and spectrum twins (with a spectrum.txt) each holds.
sharing Whether the theme folders are editable over the network share, and the folders.
artwork The artist fanart switch and settings, and how many artists have pictures cached.
cardash Car Dash as /api/cardash reports it: the settings, the period now and the next switch.
face The Face tab's feed: pages connected, frames whether the daemon's socket is connected, hops passed on since the start.
sheet The status sheet's own rows: player (volumio, hardware, board, backendUptimeS, build as { commit, built } from the zip or null), addresses (each interface's name and IPv4 address, loopback left out), screen (size from the X server or empty, mouse, since the display started), audio (tapInChain, output, service, trackType, samplerate, bitdepth), housekeeping (newestBackup as { name, at } or null, problems the last three warning or error lines).
upgrade last as the System tab reports it (from, to, at, phase) or null, and previous.
themeSize The theme on show's size from its folder name, WxH, or empty.
interactive The interactive controls setting: theme, on or off.
legacy Whether PeppyMeter Screensaver is enabled.
jobs Jobs still running.

Themes

Route What it does
GET /api/themes { "active": "...", "meterBase": "...", "spectrumBase": "...", "themes": [ ... ] }. Each theme: folder, meters (the section names), spectrum (whether a spectrum twin exists), width, height, bytes, active, previews (none, stale, fresh, queued, rendering), catalog (the catalog entry it came from, or null).
POST /api/themes/:folder/activate Puts the theme on show. { "ok": true, "active": "...", "changed": true }. 400 with invalid, not_found or no_config.
DELETE /api/themes/:folder Removes the theme from both trees and its previews. { "ok": true, "switchedTo": "..." } names the theme put on show when the removed one was. The last theme is refused.
GET /api/themes/:folder/previews { "folder", "state", "meters": [ { "meter", "url", "thumb" } ] }: the rendered pictures and their addresses.
POST /api/themes/:folder/render Draws the previews unless fresh. Body { "force": true } draws again, { "wait": true } answers when done, with the same answer as previews. 404 when the theme has no meters.txt; 500 render-failed with the reason.
GET /api/themes/:folder/preview/:meter The rendered picture, PNG; ?thumb=1 the thumbnail. 404 until rendered.
POST /api/themes/:folder/tailor Body { "width", "height", "stretch": false }: a copy of the theme cut to that size on the player, its shape kept and the copy centred, or stretched to the screen's shape with stretch, installed beside the original with its spectrum twin (a copy of that name is replaced) and its previews drawn. 202 with the job, kind tailor. 400 bad-size (64 to 7680 by 64 to 4320), 404 without a meters.txt. The Tailor page has what the cutter does.
POST /api/themes/:folder/package Body { "settle": 3 } (1 to 30 seconds a meter): the theme as the Catalog takes it, a zip with the theme, its twin and a preview.png of every meter shown for settle seconds each. 202 with the job, kind package; the zip comes from GET /api/jobs/:id/file when the job is done. 404 without a meters.txt.
GET /api/themes/:folder/files The theme's files with checksums: { "folder", "files": [ { "path", "sha256", "bytes" } ], "spectrum": { "folder", "files": [ ... ] } } or "spectrum": null. What a remote display syncs from.
GET /api/themes/:folder/file?tree=templates&path=... One file of the theme, from templates or templates_spectrum, only from inside the folder.

A folder name is one the display accepts: letters, digits, spaces, dots, underscores, brackets, plus and hyphens, starting with a letter or digit. Anything else is refused with bad-folder.

Car Dash

Route What it does
GET /api/cardash { "enabled", "mode": "clock" | "sun", "dayTheme", "nightTheme", "dayAt": "07:00", "nightAt": "20:00", "offsetMin", "lat", "lon", "location": { "lat", "lon", "source": "zone" | "manual" | "none", "zone" }, "sun": { "rise", "set" } | null, "bySun", "period": "day" | "night" | null, "next": { "at": "<ISO time>", "period" } | null, "active" }: the settings, the place the sun is reckoned from, today's sunrise and sunset when the sun decides, which period it is now, when the next switch comes and what it brings, and the theme on show.
POST /api/cardash The settings to set: enabled, mode, the two themes, the two times (HH:MM), offsetMin (-180 to 180), lat and lon (both or neither, empty for the zone's place). Applied at once: the period's theme goes on show when it is not, and the timer is set for the next switch. 400 bad-time, same-time, bad-theme (a theme must be installed; both when on), bad-location, bad-offset, or no-location (by the sun with no place known for the zone and none given). Answers with ok and the state as set.

The meter selection

Route What it does
GET /api/meter { "theme", "mode": "random" | "list" | "single", "names": [...], "available": [...], "onTitle": false, "interval": 60 }.
POST /api/meter The same fields to set: mode, names (for list and single), onTitle, interval (15 to 1000 seconds). Answers with ok and the selection as set. The display moves to the new selection at once; a remote that follows the player follows it.

The catalog

Route What it does
GET /api/catalog { "fetchedAt", "updated", "source", "error", "entries": [ ... ] }. Reads the index when none is kept. Each entry: name, kind (meters, spectrum, both), category, width, height, bytes, units (the folders the zip holds, with install, folder, from, kind, names), thumb (a route below, or null), preview (the collection's picture), state (absent, installed, update, present).
POST /api/catalog/refresh Reads the index again; the same answer. 502 with the index's error when it could not be read.
GET /api/catalog/thumb/:name The entry's thumbnail, cached for a day.
POST /api/catalog/install { "name": "..." } starts an install; 202 with { "ok": true, "job": { ... } }. 404 not-found for a name not in the index.

Uploads and jobs

Route What it does
POST /api/upload?name=file.zip The theme zip as the request body (or the name in an X-File-Name header). 202 with the job. 413 too-large above 512 MB, 400 empty or bad-name.
GET /api/jobs { "jobs": [ ... ] }, newest first, the last fifty.
GET /api/jobs/:id { "job": { ... } }.
GET /api/jobs/:id/file A finished package job's zip, as an attachment named after the theme. 404 for any other job, or before it is done; the file goes when the plugin starts again.

A job:

{
  "id": 3, "kind": "install", "name": "1280x720_Reloop_RL7000",
  "state": "unpacking", "progress": { "done": 812000, "total": 1300000 },
  "folders": [ { "install": "templates", "folder": "1280x720_Reloop_RL7000", "kind": "meters", "files": 12, "bytes": 1300000, "names": ["..."] } ],
  "error": null, "startedAt": "...", "endedAt": null
}
kind state in order
install, upload queued, downloading (install only), checking, unpacking, rendering, then done or failed
upgrade, rollback queued, downloading or staging, verifying, backing-up, applying, restarting, or failed
tailor queued, cutting, unpacking, rendering, then done or failed; folders names the copy and its twin.
package queued, packaging, then done or failed; progress counts the meters shown of the theme's count, settle is the seconds a meter, and file the zip's path on the player when done.

error on a failed job is { "error": "<code>", "message": "..." }: checksum, size, bad-theme, units-differ, network, and the like. Installs, uploads and upgrades run one at a time; a job waits in queued for its turn.

Artwork

Route What it does
GET /api/artwork { "enabled", "keyMode": "personal" | "project", "personalKey", "interval", "order": "sequential" | "random", "transition": "none" | "fade" | "merge", "transitionMs", "unlimited", "maxImages" }.
POST /api/artwork The same fields to set; answers with ok and the settings as set.
POST /api/artwork/clear-cache Drops the cached fanart copies. { "ok": true }.

Fonts

Route What it does
GET /api/fonts styles: for each of light, regular, bold, italic and digi, { "kind": "builtin" | "custom" | "player" | "other", "value" } (the uploaded or player font's file name, or the configured value as it stands); builtIn: which styles have their built-in face on this player; player: { "path", "fonts": [names] }, the fonts under the meter configuration's font.path; custom: [{ "name", "bytes" }], the uploaded fonts.
POST /api/fonts { "styles": { "<style>": "builtin" | "<player font name>" | { "custom": "<uploaded font name>" } } }; a style not given keeps its value. Writes font.<style> in the meter configuration and restarts the display. Answers with ok and the settings as set; bad-font names a font the player does not have.
POST /api/fonts/upload?name=<file name> The font file as the request body, at most 64 MB. Kept on the player under a plain name with the extension its bytes say (TrueType or OpenType, one face per file; not-a-font otherwise); a name already there is replaced. Answers with ok, name and the settings.
DELETE /api/fonts/custom/:name Removes an uploaded font; removed names it and freed lists the styles that were set in it and went back to the built-in face. 404 not-found.

The network share

Route What it does
GET /api/sharing { "shared": false, "roots": ["/data/INTERNAL/glass/templates", "/data/INTERNAL/glass/templates_spectrum"] }: whether the theme folders are writable from computers on Volumio's Internal Storage share, and the folders.
POST /api/sharing { "shared": true } makes every theme folder writable over the share, now and for themes installed later; false makes them readable only. Answers with ok, changed and the state.

The face

Route What it does
GET /api/face/events An event stream (text/event-stream) for the Face tab: hop events carry the frames daemon's datagrams in base64, plugin events the lines the displays hear (state, infinity, config, showing, each a JSON object with its kind), the last of each first on connection, and feed events { "frames": true | false } say whether the daemon's socket is connected. The daemon's stream is one upstream connection the manager shares between every page and opens only while a page is connected. 503 no-face before the plugin has started the feed.
GET /face/glass-face.wasm The browser module: the display's pipeline compiled to WebAssembly. 404 no-module when the release has none.
GET /face/face-page.js The Face tab's script, the page's side of the module's contract.
POST /api/face/command { "name", "value" }: a command as a display sends it down the channel (toggle, play, pause, stop, next, previous, seek, volume, random, repeat), run the same way; the Face tab sends what a tap or a drag on a control asked for. Answers { "ok": true, "name" }; 400 bad-command for a name that is not a word of lower-case letters.
GET /api/face/picture?at=<location> A picture for the face, fetched from the player itself: at is a path under the player's own /albumart route with its query (the album art the player reports, or /albumart?sectionimage=<reference> for a fanart picture), proxied to the player as given, or an absolute address, accepted only when it is the very one the player reports as the playing track's album art. Anything else, a non-image answer, an answer that is not 200 or one declared over 32 MB is 404 not-found; a player that does not answer within eight seconds is 502 unreachable.
GET /api/face/fanart?artist=<name>&uri=<track> The artist's fanart set as the display asks the plugin for it: success, images (references for /albumart?sectionimage=), interval_ms, transition, transition_ms, order, source; success: false with an error when there is none, or no artist.
GET /anymote Anymote: the face on a page of its own, filling the window, with a full-screen button.
GET /anymote/manifest.json, GET /anymote/icon.svg The web manifest (display: fullscreen, landscape) and icon, so a phone keeps Anymote on its home screen as a full-screen app.

Interactive controls

Route What it does
GET /api/touch { "interactive": "theme" | "on" | "off" }: whether a theme's indicators and buttons act when tapped, as the theme says, for every theme, or never.
POST /api/touch { "interactive": "theme" | "on" | "off" } sets it; the display starts again with the change and remotes hear it. Answers with ok, changed and the value.
GET /api/screen { "driver", "rotation": 0 | 90 | 180 | 270, "pointer": "auto" | "show" | "hide", "pointerShown": bool, "kioskActive": bool, "free": bool, "fact": {...}, "now": {...}, "probe": {...} }: the settings (driver is the key as kept, drawn by fact since 0.7.83), the pointer as resolved, whether the screen is Glass's (free), the fact behind it (xserver, kiosk as systemd states it, kioskEnabled, touchDisplay, displayConfiguration, panel), what the display draws on now (now.display.running, now.display.driver and now.display.renderer as the display reported, now.wouldDraw), and the probe: board, connectors (name, status, native size, portrait), inputs (touch, mice, keyboards, remotes), backlights, holders (kiosk, xserver, touchDisplay, displayConfiguration), touchDisplayAngle, suggestion (rotation, pointer, panel).
GET /api/screen/probe The probe alone, read afresh.
POST /api/screen/touch { "mapping": "auto" | "overrides" | "calibrated", "swap", "flipX", "flipY" } sets the touch mapping; calibrated is refused with MANAGER_TOUCH_NOT_CALIBRATED until a calibration is kept. The display starts again with the change. Answers with the touch settings: mapping, the switches, matrix and calibration (state none, waiting, done or failed, with worst in pixels or error).
POST /api/screen/calibrate Asks the display for a calibration: five targets on the screen. The state is read back through GET /api/screen under touch.calibration.
POST /api/screen { "rotation", "pointer" } sets them, the pointer resolved from the probe; a driver in the body is ignored, the screen being drawn by fact. The display starts again with the change. Answers with ok and the values.

Settings the manager owns

Route What it does
GET /api/settings { "themeTagRules": "...", "doNotDeleteThemes": false, "managerPort": 5582, "managerHost": "" }.
POST /api/settings themeTagRules and doNotDeleteThemes to set. The port and address are set on the settings page.

Where the theme goes on the screen

Route What it does
GET /api/display { "fit": false, "position": "center" | "manual", "x": 0, "y": 0 }: whether the theme is scaled to the screen with its shape kept, and where it goes, centred or with its top left at x, y. The Appearance tab's Display section and the Settings page's Meter Position and Fit to screen are the same keys.
POST /api/display The same fields to set; the meter configuration is written, the displays hear of the change, and the player's display starts again with it. 400 GLASS.MANAGER_BAD_REQUEST for a position that is not center or manual, or coordinates out of 0 to 7680 by 4320. Answers with ok and the placement as set.

The old plugin's themes

Route What it does
GET /api/legacy { "present", "themes", "bytes", "installed" }: whether PeppyMeter Screensaver's folder still holds a templates tree, how many theme folders and how many bytes in both trees, and whether that plugin is still installed. The System tab shows its panel while present.
POST /api/legacy/wipe Removes that folder's templates and templates_spectrum trees, nothing else. Answers with ok, removed (the trees removed) and the state after.

Backups

Route What it does
GET /api/backups { "backups": [ { "name", "created", "pluginVersion" } ] }, newest first.
POST /api/backups { "name": "..." } creates one; answers with the list. 400 with the plugin's backup codes when the name is bad or taken, or storage is short.
POST /api/backups/:name/restore Restores it; { "ok": true }. 400 with the plugin's codes when the backup is damaged or from a newer version.
DELETE /api/backups/:name Removes it; answers with the list.
GET /api/backups/:name/download The backup as glass-backup-<name>.zip: manifest.json, config.json, peppymeter_config.txt, spectrum_config.txt.
POST /api/backups/upload?name=file.zip The zip as the request body becomes a backup, named by its manifest or by the file, with a number when the name is taken; the four files may sit at the zip root or under one folder. { "ok": true, "name": "...", "backups": [ ... ] }. 400 bad-backup when the files are not all there, or with the plugin's codes when they do not parse; 413 when too large.

Upgrades

Route What it does
GET /api/update { "current", "latest": { "version", "notes", "bytes", "sha256", "url", "publishedAt" }, "checkedAt", "available", "previous": { "version", "at", "bytes" }, "last": { "from", "to", "phase", "ok", "error", "at" } }. Reads GitHub when the last look is older than a day; with an error field when it could not, and the last known values.
POST /api/update/check Reads the latest release now. 502 when GitHub could not be read.
POST /api/update/install Upgrades to the latest release; 202 with the job. 400 up-to-date, 409 busy while an upgrade runs. The backend restarts a few seconds after the job reaches restarting; the job is gone with it, and GET /api/status answers with the new version once it is up.
POST /api/update/rollback Puts the kept previous version back the same way. 400 no-previous.

Logging

Route What it does
GET /api/logging { "level": "warn", "targets": [], "levels": [...], "targetsAvailable": [...] }.
POST /api/logging level and targets to set; applied at once for the plugin, at the next start of the display and the daemon. Answers with the settings as set. The System tab's Logging panel uses these.
GET /api/logs?lines=300 { "lines": [...], "total": n }: the last Glass lines from the player's journal, newest last, 20 to 3000. With download=1, the lines as a text file named after the player and the time. 500 journal when the journal could not be read.

Performance

Route What it does
GET /api/performance { "profile": "auto", "auto": "standard", "values": { "frameRate", "rotationQuality", "rotationFps", "transitions" }, "valuesProfile": "standard", "board": { "model", "cores", "arch", "class" }, "profiles": { ... }, "governor": true, "showing": { "theme", "meter", "rate" } }. showing.rate is the rate the display runs at, which the governor may have lowered.
POST /api/performance { "profile": "auto" | "full" | "standard" | "light" | "minimal" | "custom", "governor": true }, either or both: applies the profile's values to the meter configuration and the settings page, and the display starts again with them; custom only records the choice; governor turns the frame rate governor on or off. Answers with changed and the same as the GET. 400 bad-profile.

Remote displays

Route What it does
GET /api/remote/status { "ports": { "enabled", "frames", "channel", "beacon", "manager" }, "beacon": { ... as sent ... }, "serve": { "at", "port", "rate", "ring", "sent", "subscribers": [ { "address", "id", "name", "release", "sent", "since" } ] } or null, "serving", "errors": { "serve", "channel" }, "headless", "remotes": [ { "id", "name", "release", "screen", "page", "address", "since" } ] }.
GET /api/remote/settings { "enabled", "framesPort", "channelPort", "beaconPort", "managerPort" }.
POST /api/remote/settings enabled, framesPort, channelPort, beaconPort to set; applied at once. 400 GLASS.MANAGER_RM_PORTS_INVALID or GLASS.MANAGER_RM_PORTS_CLASH. Answers with ok, changed and the settings as set.
GET /api/remote/config What a remote syncs: version, release, theme, meter, files.meter and files.spectrum (the configuration texts), assets.fonts, assets.icons, assets.webfonts and assets.custom (name, sha256, bytes): the plugin's fonts, the format icons (the plugin's own, then Volumio's beside its web application), the player's web fonts (the font files in the directory the meter configuration's font.path names) and the uploaded fonts.
GET /api/remote/asset/font/:name, GET /api/remote/asset/icon/:name, GET /api/remote/asset/webfont/:name, GET /api/remote/asset/custom/:name One of the plugin's fonts, one of the format icons (the plugin's own before Volumio's, as the display looks), one of the player's web fonts, or one of the uploaded fonts.
GET /api/remote/track-file?uri=...&name=... One picture from the playing track's folder: uri as the player reports the track, name a plain file name with a picture extension. Only files inside that folder under /mnt, up to 32 MB. 404 not-found otherwise.

The Remotes page has the wire between the player and a remote, and the remote's own page API.

Errors

Status When
400 A bad name, folder, meter or body; a refused change, with the reason in error.
404 No such theme, preview, entry, job, backup, asset or route.
409 An upgrade while one runs.
413 An upload above the limit.
500 A render that failed, or a cache that could not be cleared.
502 The catalog's index, a thumbnail or GitHub could not be read.

Clone this wiki locally