better descriptions

This commit is contained in:
2026-09-03 23:29:16 +02:00
parent a5a53b7efc
commit 365a7b8317
+182 -6
View File
@@ -8,14 +8,70 @@
rkt-web-player/users)) rkt-web-player/users))
@title{RKT Web Player} @title{RKT Web Player}
@author{Hans van Dijkema} @author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]]
@defmodule[rkt-web-player] @defmodule[rkt-web-player]
RKT Web Player combines local playback through @tt{racket-audio} RKT Web Player is a central music server for a trusted network. It makes one
with UPnP and Sonos discovery and playback through or more configured music libraries available through a web interface and
@tt{racket-audio-dlna}. The user interface is served to a web plays that music on different kinds of renderers: the server's own audio
browser by Racket's web server. 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 @defproc[(run-web-player
[music-paths (listof (or/c path-string? [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] [#:dlna-port dlna-port exact-positive-integer? 8734]
[#:local-output? local-output? boolean? #t] [#:local-output? local-output? boolean? #t]
[#:playlist-keystore playlist-keystore (or/c path-string? #f)] [#: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 Treats every entry in @racket[music-paths] as a separate music library. A
two-element list supplies an explicit display name and path. The 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 half of @racket[session-seconds] has elapsed. Playback-agent endpoints continue
to use their separate application-ID allowlist. 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. The default listen address only exposes the interface to the local computer.
Use a LAN address deliberately if other devices should control the player. 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] @defmodule[rkt-web-player/users]
@defproc[(make-password-hash [password string?]) string?] { @defproc[(make-password-hash [password string?]) string?] {