Files
rkt-web-player/scribblings/rkt-web-player.scrbl
T

103 lines
4.7 KiB
Racket

#lang scribble/manual
@(require (for-label racket/base
racket/contract
rkt-web-player
rkt-web-player/player-agent
rkt-web-player/users))
@title{RKT Web Player}
@author{Hans van Dijkema}
@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.
@defproc[(run-web-player
[music-paths (listof (or/c path-string?
(list/c string? path-string?)))]
[#:allowed-agent-ids allowed-agent-ids (listof string?) null]
[#:users users (listof (cons/c string? string?)) null]
[#:trusted-proxies trusted-proxies (listof string?)]
[#:session-seconds session-seconds exact-positive-integer? 604800]
[#:listen-ip listen-ip string? "127.0.0.1"]
[#:port port exact-positive-integer? 8080]
[#: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] {
Treats every entry in @racket[music-paths] as a separate music library. A
two-element list supplies an explicit display name and path. The
@racket[allowed-agent-ids] list contains the 64-character application IDs that
may register as polling playback agents. All agents are denied when it is empty.
The function
starts the web interface on @racket[listen-ip] and @racket[port]. Directory
contents are browsed one level at a time. Metadata and recursive contents are
only read when the user adds or plays a selected item.
The @racket[dlna-port] is used to publish local audio files to a selected
network renderer. Set @racket[local-output?] to @racket[#f] to omit the
server's own @tt{racket-audio} output. When no other renderer is available, the
player waits for discovery or playback-agent registration. Playlist tabs are
atomically persisted in
@racket[playlist-keystore]; @racket[#f] disables playlist persistence. Player
resources are closed when the web server exits. The default is
@tt{data/playlists.keystore} below the installed rkt-web-player collection.
Each username owns an ordered GUID index and separate playlist values.
It also owns an independent playback pipeline and a durable interface-language
preference. Different outputs can play concurrently. Selecting an output that
another user owns stops the previous backend and transfers that output. The web
interface supports Dutch, English, German, French and Spanish; browser language
is the initial default and a manual choice is stored per username.
When @racket[users] is non-empty, every browser client must authenticate.
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.
The default listen address only exposes the interface to the local computer.
Use a LAN address deliberately if other devices should control the player.
}
@defmodule[rkt-web-player/users]
@defproc[(make-password-hash [password string?]) string?] {
Creates a salted Argon2id password hash suitable for a value in the INI
@tt{[users]} section. Passwords must contain at least twelve characters.
}
@defproc[(password-hash-valid? [password string?]
[encoded string?]) boolean?] {
Checks a password against an encoded Argon2id hash.
}
@defmodule[rkt-web-player/player-agent]
@defproc[(run-player-agent) any/c] {
Starts the graphical polling playback agent. The agent keeps a generated
256-bit application identifier in a user-specific INI file, registers with the
configured RKT Web Player server, downloads assigned tracks over HTTP, and
plays them with @tt{racket-audio}. Its configured display name is authoritative
and is followed by the server. Importing the module does not start the GUI; the
function must be called explicitly.
The GUI and optional tray use Dutch, English, German, French or Spanish based
on the operating-system language, with English as fallback.
}
@defproc[(run-player-agent-cli [#:server-url server-url
(or/c string? #f) #f]
[#:name name (or/c string? #f) #f]
[#:config-file config-file
(or/c path-string? #f) #f]) void?] {
Starts a headless playback agent using the same audio and gapless-prefetch
runtime as the GUI. Missing keyword values are read from the normal agent INI
file. The procedure runs until interrupted.
}