Files
rkt-web-player/README.md
T
2026-08-27 17:51:39 +02:00

221 lines
8.6 KiB
Markdown

# rkt-web-player
Een audioplayer met webinterface, gebouwd op de bestaande Racket-pakketten:
- `racket-audio` voor lokale weergave en metadata;
- `racket-upnp` en `racket-sonos` voor ontdekking van netwerkspelers;
- `racket-audio-dlna` voor het publiceren en afspelen van lokale bestanden;
- `racket-mimetypes`, `simple-ini` en `simple-log` voor ondersteunende taken.
## Starten
De gekoppelde ontwikkelpackages kunnen direct worden gebruikt:
```console
racket main.rkt D:\Muziek
```
Standaard opent de speler `http://127.0.0.1:8080/`. Iedere opgegeven map wordt
een afzonderlijke muziekbibliotheek. Bij het starten wordt alleen de inhoud van
de eerste rootmap gelezen; er vindt geen recursieve bibliotheekscan plaats.
```console
racket main.rkt --port 8090 --no-browser D:\Muziek D:\Podcasts
```
Met een klein INI-bestand zijn vaste defaults mogelijk:
```ini
[server]
listen-ip=127.0.0.1
port=8080
[player]
dlna-port=8734
[libraries]
muziek=D:\Muziek
podcasts=D:\Podcasts
[playback-agents]
7b4776ef27104e8eb9f7ea2c622ce76ca23de4260b0f94e6880d321017b32a0e4=true
[authentication]
local-networks=127.0.0.0/8;::1/128;10.0.0.0/8;172.16.0.0/12;192.168.0.0/16
trusted-proxies=127.0.0.0/8;::1/128
session-seconds=43200
[users]
hans=$argon2id$v=19$m=19456,t=2,p=1$...
```
Start dat bestand met `racket main.rkt --config rkt-web-player.ini`. Iedere key
onder `[libraries]` is de zichtbare bibliotheeknaam; de waarde is de lokale of
UNC-rootmap. Het oudere `[library] paths=D:\Muziek;D:\Podcasts` blijft eveneens
ondersteund.
Zodra `[users]` minstens één gebruiker bevat, toont de webinterface voor
niet-lokale clients een eigen loginvenster. Wachtwoorden staan uitsluitend als
Argon2id-hash in de INI. Maak zo'n hash vanuit Racket:
```racket
#lang racket/base
(require rkt-web-player/users)
(displayln (make-password-hash "een lang en uniek wachtwoord"))
```
`local-networks` bepaalt welke clients zonder login mogen werken.
`trusted-proxies` bepaalt uitsluitend van welke directe peers de laatste
`X-Forwarded-For`-waarde wordt geaccepteerd. Laat die lijst zo klein mogelijk;
bij Apache op dezelfde machine zijn loopbackadressen voldoende. Zonder
gebruikers is authenticatie uitgeschakeld en blijft het oude gedrag behouden.
## Werking
De interface volgt de informatiearchitectuur van `rktplayer`, maar is
responsive en geschikt voor muis, toetsenbord en touch. Links staat de lazy
mappenbrowser met trackinformatie; rechts staan playlisttabs en de huidige
playlist. Een map wordt pas recursief gelezen wanneer die met **afspelen** of
**toevoegen** wordt gekozen. Trackmetadata wordt eveneens pas op dat moment
geladen. Bij de huidige track toont de webinterface embedded album-art uit de
audio-tags. Als die ontbreekt, worden naast het audiobestand ook `cover`,
`folder` en `front` met een JPEG- of PNG-extensie geprobeerd.
De webinterface praat met een kleine JSON-API onder `/api`. Lokale weergave
wordt pas geïnitialiseerd bij het eerste afspeelcommando. De knop naast de
uitvoerkeuze start UPnP-discovery; gevonden Sonos-zones worden als logische
groepen aangeboden en niet nogmaals als losse UPnP-renderers.
Voor UPnP- en Sonos-weergave publiceert de server ook de volgende playlisttrack
en stelt deze vooraf in als `NextAVTransportURI`. Een renderer die dit
ondersteunt kan daardoor zelf zonder serverronde naar de volgende track
overgaan. De server volgt de nieuwe URI en playlistindex. Renderers zonder
betrouwbare next-ondersteuning krijgen na het natuurlijke trackeinde een
servergestuurde fallback. Een expliciet stopcommando start nooit de volgende
track.
Playlisttabs kunnen worden toegevoegd, geselecteerd, hernoemd door dubbel te
klikken en verwijderd. Tracks kunnen worden afgespeeld, verwijderd en met
drag-and-drop verplaatst. De tabs zijn in deze versie alleen in het geheugen
aanwezig en worden niet na een herstart hersteld.
De server luistert standaard alleen op localhost. Geef alleen bewust een
LAN-adres aan `--listen-ip`. Configureer gebruikersauthenticatie voordat de
webinterface via een publiek bereikbare reverse proxy wordt aangeboden.
Externe gebruikers krijgen na succesvolle aanmelding een willekeurige 256-bit
sessiecookie met `Secure`, `HttpOnly` en `SameSite=Strict`. Sessies verlopen na
de ingestelde inactiviteitsduur en worden niet over een serverherstart heen
bewaard. Na vijf mislukte pogingen vanaf hetzelfde clientadres wordt aanmelden
vijf minuten geblokkeerd. De `/api/agent/*`-routes gebruiken geen
gebruikerssessie: daarvoor blijft de afzonderlijke playback-agent-allowlist
gelden.
## Windows playback agent
Een lichte playback agent kan op een Windows-laptop draaien en meldt zichzelf
via HTTP bij de centrale RKT Web Player aan. De agent opent geen inkomende
netwerkpoort. Hij pollt de server voor opdrachten en rapporteert daarbij zijn
actuele afspeelstatus.
Start vanuit de broncode:
```console
racket player-agent.rkt
```
Dezelfde GUI kan vanuit een ander Racket-programma worden gestart:
```racket
#lang racket/base
(require rkt-web-player/player-agent)
(run-player-agent)
```
De GUI bewaart de server-URL, de gekozen naam en een eenmalig gegenereerde
256-bit applicatie-ID in `rkt-web-player-agent.ini` in de gebruikersspecifieke
Racket-configuratiemap. Vul als server bijvoorbeeld `http://192.168.1.10:8080`
in. De naam wordt in dezelfde agent-GUI ingesteld. Na registratie verschijnt
de agent met die naam als uitvoer van type `AGENT`; de server volgt latere
naamswijzigingen bij registratie en polling. De server laat een agent alleen
toe wanneer zijn volledige applicatie-ID vooraf als key onder
`[playback-agents]` staat en de waarde niet `false` is. Een onbekende ID krijgt
HTTP 403 en wordt niet als uitvoerpunt aangemaakt. De agent toont in dat geval
zijn ID en meldt dat de serverbeheerder deze eerst aan de INI moet toevoegen.
Onder **Afspelen** toont de agent het playlistnummer, de huidige track en
bestandsnaam, afspeeltoestand, verstreken en totale tijd, bitdiepte,
samplefrequentie, kanaalaantal en decoderformaat.
Een geselecteerde track wordt volledig naar een tijdelijk bestand gedownload
voordat `racket-audio` de weergave start. Tijdens het afspelen stuurt de server
al een `prefetch`-opdracht voor de volgende playlisttrack. De agent bewaart
daardoor maximaal het huidige en het volgende bestand lokaal. Bij de overgang
opent de agent het vooraf opgehaalde bestand direct bij decoder-EOF. Daardoor
blijven polling en netwerkvertraging buiten het tijdkritische audiopad en kan
`racket-audio` de volgende track achter de nog uitspelende uitvoerbuffer zetten.
De server wordt bijgewerkt zodra het nieuwe music-id werkelijk hoorbaar is en
stuurt vervolgens de daaropvolgende prefetch. Tijdelijke bestanden worden
opgeruimd zodra ze niet meer nodig zijn en bij afsluiten van de agent.
### Systeemvak
De GUI gebruikt optioneel de open-source SDL3-tray-API. Als zowel het Racket-
pakket `sdl3` als de native SDL3-, SDL3_image- en SDL3_ttf-libraries aanwezig
zijn, sluit de vensterknop de agent naar het systeemvak. Het menu bevat
**RKT Web Player Agent openen** en **Afsluiten**. Zonder SDL3 blijft de agent
gewoon werken en sluit de vensterknop het proces af. Er wordt geen PowerShell-
proces of externe tray-helper gestart.
```console
raco pkg install sdl3
```
SDL3 is bewust geen verplichte package-dependency: de agent blijft daardoor
klein voor gebruikers die geen systeemvak nodig hebben. Op Windows moeten de
bijbehorende native DLL's daarnaast vindbaar zijn, bijvoorbeeld naast het
gebouwde executable of via `PATH`.
### CLI playback agent
De headless agent gebruikt exact dezelfde polling-, download-, audio- en
gapless-prefetchkern als de GUI-agent:
```console
racket player-agent-cli.rkt
racket player-agent-cli.rkt --server https://muziek.example.nl --name "Werkkamer"
```
GUI en CLI gebruiken standaard hetzelfde gebruikersspecifieke
`rkt-web-player-agent.ini`, dus ook hetzelfde application-ID. Met `--config`
kan de CLI een afzonderlijk INI-bestand en daarmee een afzonderlijke identiteit
gebruiken. Bij het starten worden naam, server en application-ID afgedrukt;
stoppen gaat met `Ctrl+C`.
Vanuit Racket is de headless variant eveneens beschikbaar:
```racket
(require rkt-web-player/player-agent)
(run-player-agent-cli #:server-url "https://muziek.example.nl"
#:name "Werkkamer")
```
De allowlist voorkomt dat een onbekende agent zich als uitvoerpunt registreert
of opdrachten en tijdelijke media ontvangt. Het applicatie-ID is een gedeeld
toegangstoken en vervangt geen transportbeveiliging of gebruikersauthenticatie.
Gebruik de agent en server alleen op een vertrouwd LAN zolang de HTTP-server
geen TLS heeft.
## Controleren
```console
raco test private/users.rkt private/library.rkt private/player.rkt \
private/player-agent-config.rkt
raco setup --check-pkg-deps rkt-web-player
```