better descriptions
This commit is contained in:
@@ -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,6 +85,9 @@ 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)]
|
||||||
|
[#: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]{
|
[#: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
|
||||||
@@ -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?] {
|
||||||
|
|||||||
Reference in New Issue
Block a user