From 365a7b8317b5dfaaae09ca56cd91660b4b54ec0a Mon Sep 17 00:00:00 2001 From: Hans Dijkema Date: Thu, 3 Sep 2026 23:29:16 +0200 Subject: [PATCH] better descriptions --- scribblings/rkt-web-player.scrbl | 188 ++++++++++++++++++++++++++++++- 1 file changed, 182 insertions(+), 6 deletions(-) diff --git a/scribblings/rkt-web-player.scrbl b/scribblings/rkt-web-player.scrbl index df05e7b..280d437 100644 --- a/scribblings/rkt-web-player.scrbl +++ b/scribblings/rkt-web-player.scrbl @@ -8,14 +8,70 @@ rkt-web-player/users)) @title{RKT Web Player} -@author{Hans van Dijkema} +@author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]] @defmodule[rkt-web-player] -RKT Web Player combines local playback through @tt{racket-audio} -with UPnP and Sonos discovery and playback through -@tt{racket-audio-dlna}. The user interface is served to a web -browser by Racket's web server. +RKT Web Player is a central music server for a trusted network. It makes one +or more configured music libraries available through a web interface and +plays that music on different kinds of renderers: the server's own audio +device, UPnP devices, Sonos groups, and player agents. The package also +provides those player agents as GUI and headless CLI applications, so a +computer without UPnP support can become a network renderer of its own. The +central server and each agent communicate over HTTP; the agent downloads its +assigned tracks and plays them on its local audio device. + +@section{What the player provides} + +The central server is the heart of the application. Its main features are: + +@itemlist[ + @item{Multiple named music libraries, including local and UNC/network paths.} + @item{Lazy directory browsing: startup reads only the library roots, while + recursive contents and audio metadata are read when needed.} + @item{Playback of the central library through the server's local audio + device, discovered UPnP renderers, Sonos groups, or registered agents.} + @item{Playlist tabs with adding, removing, reordering, renaming and + drag-and-drop support. Tracks from different libraries can share a + playlist.} + @item{Gapless network playback where the renderer or playback agent supports + preloading the next track, with a server-side fallback.} + @item{Transport controls, seeking, volume, repeat mode and live playback + status.} + @item{Embedded album art and adjacent @tt{cover}, @tt{folder} and + @tt{front} JPEG/PNG artwork.} + @item{Per-user playlists, language preference and playback pipeline, with + shared physical outputs that can be transferred between users.} + @item{Dutch, English, German, French, Spanish, Italian, Swedish, Norwegian, + Finnish and Icelandic interfaces.} + @item{Optional Argon2id browser authentication and a separate default-deny + allowlist for playback agents.} +] + +The browser is a thin remote control, not a second player. It polls a complete +JSON state snapshot once per second and sends commands to the central server; +playlists, preferences and playback state are kept there. The server exposes +the browser application under the root URL and its JSON API under @tt{/api}. +The API includes state, discovery, playback commands, preferences, artwork and +the agent registration, polling and media routes. + +@subsection{Player agents} + +A player agent is an additional renderer implemented by this package. It runs +on a computer connected to speakers, registers with the central server, polls +for commands, downloads the selected music and plays it locally. Agents do not +open an inbound network port. The package supplies two forms: + +@itemlist[ + @item{The GUI agent, with a desktop window and system-tray integration.} + @item{The headless CLI agent, suitable for a small always-on computer or a + machine without a graphical desktop.} +] + +The server treats each registered agent as an output alongside UPnP and Sonos +renderers. The server can prefetch the next track to an agent for gapless +transitions. A 256-bit application ID identifies the agent; the server's +@tt{[playback-agents]} allowlist decides which agents may connect. @defproc[(run-web-player [music-paths (listof (or/c path-string? @@ -29,7 +85,10 @@ browser by Racket's web server. [#:dlna-port dlna-port exact-positive-integer? 8734] [#:local-output? local-output? boolean? #t] [#:playlist-keystore playlist-keystore (or/c path-string? #f)] - [#:launch-browser? launch-browser? boolean? #t]) any/c] { + [#:log-file log-file path-string?] + [#:log-retention-days log-retention-days exact-positive-integer? 7] + [#:log-level log-level symbol? 'debug] + [#:launch-browser? launch-browser? boolean? #t]) any/c]{ Treats every entry in @racket[music-paths] as a separate music library. A two-element list supplies an explicit display name and path. The @@ -60,10 +119,127 @@ Sessions have a sliding idle timeout; an active browser cookie is renewed once half of @racket[session-seconds] has elapsed. Playback-agent endpoints continue to use their separate application-ID allowlist. +Logging is written to @racket[log-file]. Files are rotated after +@racket[log-retention-days] days, and @racket[log-level] selects the +@tt{simple-log} level. The default log file is +@tt{data/rkt-web-player.log} below the installed collection. The +@racket[playlist-keystore], @racket[log-file] and @racket[log-level] arguments +are useful when embedding the player; the command-line entry point can also +read these values from an INI file. + The default listen address only exposes the interface to the local computer. Use a LAN address deliberately if other devices should control the player. } +@section{Command line and INI configuration} + +The package entry point accepts one or more music directories: + +@verbatim{ +racket main.rkt MUSIC-DIRECTORY [...] +racket main.rkt --config rkt-web-player.ini --no-browser +} + +The @tt{--config} option reads defaults from an INI file. The file is normally +named @tt{rkt-web-player.ini} and is read from the current directory when the +server is started with @tt{--config}. Relative paths are interpreted in the +process's working directory. + +Command-line values for @tt{--listen-ip}, @tt{--port}, @tt{--dlna-port}, +@tt{--playlist-keystore}, @tt{--log-file} and @tt{--no-browser} override the +corresponding defaults. Logging retention, log level, authentication and the +playback-agent allowlist are configured in the INI file. Libraries configured +under @tt{[libraries]} use the INI key as their display name and the value as +the root directory. The legacy @tt{[library] paths} setting accepts a +semicolon-separated list and is also supported. A complete example is: + +@verbatim{ +[server] +listen-ip=127.0.0.1 +port=8080 + +[player] +dlna-port=8734 +local-output=true +playlist-keystore=data/playlists.keystore + +[logging] +log-file=data/rkt-web-player.log +log-retention-days=7 +log-level=debug + +[authentication] +trusted-proxies=127.0.0.0/8;::1/128 +session-seconds=604800 + +[playback-agents] +; 64 hexadecimal characters, copied from an agent +0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef=true + +[users] +; Generate hashes with make-password-hash or set-user. +hans=$argon2id$v=19$m=19456,t=2,p=1$... +} + +The @tt{[server]} section controls the browser server. The default +@tt{listen-ip} is @tt{127.0.0.1}, so the interface is local-only by default; +@tt{0.0.0.0} or a LAN address makes it reachable from other machines. +@tt{port} defaults to @tt{8080}. + +The @tt{[player]} section controls playback. @tt{dlna-port} defaults to +@tt{8734} and must be reachable by network renderers when they play files +published by the server. @tt{local-output=true} (the default) adds the +server's own audio device as an output. @tt{playlist-keystore} selects the +keystore for playlist tabs and language preferences; omission uses +@tt{data/playlists.keystore} below the installed collection. When embedding +the player through @racket[run-web-player], passing @racket[#f] disables +persistence. + +The @tt{[logging]} section controls the rotating log file. The default file is +@tt{data/rkt-web-player.log}, retention defaults to seven days, and the default +level is @tt{debug}. The level is passed to @tt{simple-log}; use a level +supported by that package. + +The @tt{[playback-agents]} section is a default-deny allowlist. Each key must +be the complete 64-character hexadecimal application ID of an agent and a +value other than @tt{false} permits registration. An empty section rejects all +agents. This ID is a shared bearer credential, not a replacement for HTTPS. + +The @tt{[authentication]} section enables browser login when @tt{[users]} has +at least one entry. Each user value is an Argon2id hash, not a plaintext +password. @tt{session-seconds} defaults to seven days and is a sliding idle +timeout. @tt{trusted-proxies} is a semicolon-separated list of IP addresses or +CIDR ranges whose forwarded client address may be trusted; keep it limited to +the actual reverse proxy. The application does not terminate TLS, so use +HTTPS at the reverse proxy before exposing an authenticated instance beyond a +trusted LAN. + +Create a password hash with @racket[make-password-hash], or run +@racket[set-user] in the directory containing the INI file. The +@racket[set-user] procedure updates @tt{rkt-web-player.ini} interactively. + +@subsection{Playback-agent INI file} + +The GUI and CLI agents use a separate private INI file named +@tt{rkt-web-player-agent.ini} in the user's Racket configuration directory. +It contains the following values: + +@verbatim{ +[server] +url=http://127.0.0.1:8080 + +[agent] +name=My playback +app-id=64 hexadecimal characters +} + +The agent generates @tt{app-id} once and reuses it so the server allowlist +continues to work. The GUI writes the server URL and display name; the CLI can +override them with @tt{--server} and @tt{--name}. Use @tt{--config} with the +CLI to select another agent INI file and therefore another identity. Agents +make only outbound HTTP requests: they register and poll the server, download +assigned tracks, and play them locally. They do not open an inbound port. + @defmodule[rkt-web-player/users] @defproc[(make-password-hash [password string?]) string?] {