ini file support and cover art

This commit is contained in:
2026-08-27 13:33:34 +02:00
parent 744a2815f1
commit 84891adb89
13 changed files with 422 additions and 79 deletions
+29 -17
View File
@@ -81,7 +81,9 @@ audio metadata extraction. Its principal domain types are:
- `music-library`: a stable generated ID, display name, and absolute root path;
- `browser-entry`: the name, kind, and root-relative path of a visible item;
- `track`: the absolute source file and its display/playback metadata.
- `track`: the absolute source file and its display/playback metadata;
- `artwork`: MIME type and bytes read on demand from embedded tags or a
conventional cover file beside the track.
Library loading is deliberately lazy:
@@ -155,7 +157,13 @@ server creates an opaque media token; the agent downloads that track to a
temporary file and uses `racket-audio` for local playback. A stable 256-bit
application ID and the agent-owned display name are persisted in its local INI
file. The server follows the name advertised by the agent and does not own a
separate name mapping.
separate name mapping. Registration is default-deny: the application ID must
be present in the server's `[playback-agents]` INI section. Unknown IDs receive
HTTP 403 and cannot register, poll, or download agent media.
The server sends the next playlist item as a prefetch command. The agent keeps
only the current and next downloads and queues the prefetched decoder at EOF,
keeping network and polling latency outside the gapless transition.
### 3.5 Device discovery
@@ -176,7 +184,7 @@ are recorded in the shared player error field.
### 3.6 HTTP and browser layers
[`private/server.rkt`](private/server.rkt) uses Racket's servlet web server. It
serves static assets from [`public/`](public/) and exposes three JSON endpoints:
serves static assets from [`public/`](public/) and exposes these API endpoints:
| Method | Route | Responsibility |
| --- | --- | --- |
@@ -186,10 +194,12 @@ serves static assets from [`public/`](public/) and exposes three JSON endpoints:
| `POST` | `/api/agent/register` | Register or refresh a polling playback agent. |
| `POST` | `/api/agent/poll` | Accept agent state and acknowledgements and return its next command. |
| `GET` | `/api/agent/media/:app-id/:token` | Download the track currently assigned to an agent. |
| `GET` | `/api/artwork/:artwork-id` | Return embedded or adjacent artwork for a playlist track. |
Responses use `Cache-Control: no-store`. Command failures are returned as HTTP
400 JSON responses with an `error` property. Unexpected failures are currently
reported through the same client-facing mechanism.
JSON responses use `Cache-Control: no-store`; artwork has a private cache
header. Command failures are returned as HTTP 400 JSON responses with an
`error` property. Unauthorized agents receive HTTP 403 with the stable
`agent-not-authorized` error code.
[`public/app.js`](public/app.js) implements a framework-free client. It:
@@ -274,7 +284,9 @@ file:
- web listen address, defaulting to `127.0.0.1`;
- web port, defaulting to `8080`;
- DLNA media publication port, defaulting to `8734`;
- one or more library root paths.
- named library root paths under `[libraries]` (the legacy semicolon-separated
setting remains supported);
- allowed 256-bit playback-agent IDs under `[playback-agents]`.
Command-line network settings override INI values. Library paths from both
sources are combined and de-duplicated.
@@ -285,17 +297,17 @@ state, and all other mutable state.
## 7. Security and operational boundaries
The service has no authentication, authorization, TLS termination, CSRF
protection, or per-user state. Anyone who can reach the HTTP port can inspect
the exposed library names and control the shared player. The default localhost
binding is therefore an important security boundary. Binding to a LAN address
should be an explicit deployment decision and should use an external trusted
network boundary or authenticated reverse proxy when untrusted clients are
possible.
The browser API has no user authentication, TLS termination, CSRF protection,
or per-user state. Anyone who can reach the HTTP port can inspect the exposed
library names and control the shared player. The default localhost binding is
therefore an important security boundary. Binding to a LAN address should be an
explicit deployment decision and should use an external trusted network
boundary or authenticated reverse proxy when untrusted clients are possible.
Playback-agent IDs are random identifiers and media URLs additionally contain
an opaque per-track token. They prevent accidental cross-agent media access but
must not be treated as authentication when transported over unencrypted HTTP.
Playback-agent registration and polling are authorized against a default-deny
INI allowlist. Media URLs additionally contain an opaque per-track token. The
random application ID therefore acts as a shared bearer credential, but must
not be treated as strong authentication when transported over unencrypted HTTP.
The configured library roots define the intended filesystem boundary. Clients
operate on opaque indexes instead of sending paths directly. The DLNA backend