Files.

Pictures, videos, fonts and documents that change without a new release live in the project's file library, filled through the HTTP API and shown in the portal under Data › Files. Every device syncs it and serves it to the app under /storage/.

Working — describes ArdaPlayer v1.2.3

Using a file

app/index.html excerpt
<img src="/storage/menu/tea.webp" alt="Tea">
<video src="/storage/adverts/autumn.mp4" autoplay muted loop></video>
  • A file is served at /storage/ + its path in the library, exactly as the portal shows it.
  • A record usually carries the path: store "image": "menu/tea.webp" in the record and build '/storage/' + item.image in the app.
  • The files are read-only content: the player checks them, refetches anything changed and removes what the library deleted. Do not write into storage/ on your desk; it is the player's.
  • A stopped download resumes where it was; files are content-addressed, so nothing is fetched twice.
  • File sync runs on its own, so datasets and the outbox never wait behind a large upload.

A file that has not arrived yet

The app can start before every file is down. A picture whose file has not landed answers 404 until it does. The 'files' event says which paths arrived, so you can redraw exactly those:

app/app.js
Arda.on('files', function (p) {
  // p = {done, total, fetched, fetchedBytes, totalBytes, failed, complete, landed}
  if (p.totalBytes) gauge(Math.round(100 * p.fetchedBytes / p.totalBytes));
  (p.landed || []).forEach(function (path) {
    // path is under /storage/, e.g. "menu/tea.webp"
    var imgs = document.querySelectorAll('img[data-file="' + path + '"]');
    for (var i = 0; i < imgs.length; i++) imgs[i].src = '/storage/' + path + '?v=' + Date.now();
  });
  if (p.complete) console.log('files up to date:', p.done, 'of', p.total, p.failed ? '(' + p.failed + ' failed)' : '');
});
  • Progress events come about once a second during a transfer; complete: true comes exactly once at the end of every sweep, even one that fetched nothing.
  • landed lists the paths that arrived since the previous event.
  • From v1.2.2 a sweep that left files behind (failed) tries them again by itself within seconds; before, they waited for the next connection.
  • Arda.db.status().files answers the same numbers at any time (null before the first sweep).

Files the app cannot start without

app/manifest.json
{
  "datasets": [ { "key": "menu", "needForBoot": true } ],
  "files": { "needForBoot": ["logos", "menu"] }
}
  • "*" means every file, a word means one folder, a list means those folders.
  • Those folders are fetched first. The app starts once the boot datasets are current and those files are present; everything else keeps arriving behind it.
  • The device's boot screen shows one bar for both ("downloading datasets n / N · downloading files x MB of y MB"), and the portal marks the folders as needed at boot.
  • Arda.db.status().files carries the boot half too: bootDone, bootTotal, bootBytes, bootTotalBytes, bootComplete.

On your desk

A local run has no file library: /storage/ serves whatever is in the folder's storage/ directory, which you may fill by hand to try layouts. With "device": true the folder syncs the project's files like a device.

Checked: the event payload, including landed, is from the player's internal/client/files.go; the manifest passes ArdaForm's pack-time parser. A local run serving a hand-placed file from storage/ (200) and a missing one as 404 was observed. Not verified against a device here: the redraw example on a slow connection.