Sign inSign up

znowf0x/zenhoot

By znowf0x

•Updated about 1 month ago

Remote library server for the ZenHoot music player. https://zenhoot.znowsoft.com

Image
0

1.2K

znowf0x/zenhoot repository overview

⁠ZenHoot Server

Remote library server for the ZenHoot⁠ music player. Point it at a folder of music, and every ZenHoot install you own can browse and stream that library over your network.

Your files stay where they are. The server reads them, indexes them, and serves them — nothing is uploaded anywhere, and no account is needed to run it.

docker run -d --name zenhoot \
  -p 9555:9555 \
  -v /path/to/your/music:/music:ro \
  -v ./zenhoot-cache:/cache \
  -e DESTRUCTIVE_LOCALHOST_ONLY=false \
  -e ZENHOOT_API_TOKEN=change-me-to-a-long-random-string \
  znowf0x/zenhoot:latest

Then add a remote source in ZenHoot pointing at http://<this-host>:9555.

A ready-made compose file lives in the repository as docker-compose.example.yml.

⁠Tags

TagMeaning
latestNewest release
1.0.0An exact version — use this if you want reproducible deploys
1.0Newest patch of 1.0
1Newest release of major 1

Built for linux/amd64 and linux/arm64, so it runs on a NAS or a Raspberry Pi as well as on a server.

⁠Volumes

PathPurpose
/musicYour library. Mount it :ro — the server only reads it unless you edit tags from the app.
/cacheArtwork cache and the library index. Persist this, or every recreate triggers a full rescan.

The cache directory has to be writable by the container. See PUID/PGID below.

⁠Environment

⁠Access control
VariableDefaultWhat it does
ZENHOOT_API_TOKEN(unset)Shared secret. Clients send it as X-API-Token. Set a long random one.
DESTRUCTIVE_LOCALHOST_ONLYtrueWhen true, library-modifying requests are refused unless they came from this machine.
ALLOWED_ORIGINS(unset)Extra browser origins allowed to call the API, comma separated. Loopback and the app's own schemes are always allowed. * disables the check.

Read this one. The default DESTRUCTIVE_LOCALHOST_ONLY=true is what protects a server that has no token. The moment you set it to false — which you must, to reach the server from another device — that protection is gone and ZENHOOT_API_TOKEN is the only thing left. Setting false without a token leaves a server that any unauthenticated request on your network can rewrite.

A token can also be set from the app after first launch; it is stored in /cache/server-auth.json.

⁠Paths and identity
VariableDefaultWhat it does
PUID1000User id the server runs as. Set it to the owner of your cache directory (id -u).
PGID1000Group id, likewise (id -g).
PORT9555Port inside the container.
MUSIC_DIR/musicWhere the library is mounted.
CACHE_DIR/cacheWhere the index and artwork cache live.

The container starts as root only long enough to adopt PUID/PGID, then drops to that user for the server process itself. Pass --user to Docker to skip this entirely if you would rather manage it yourself.

⁠Performance
VariableDefaultWhat it does
SCAN_CONCURRENCYCPU count, capped at 8Files parsed in parallel during a scan. Lower it on a NAS with spinning disks; raise it on fast NVMe. Hard maximum 32.
⁠Optional enrichment keys

Both of these are optional, and both are yours — ZenHoot ships with no API key of its own, because any key inside a distributed image can be read straight back out of it.

Without either key the server still finds lyrics through LRCLIB and artwork through MusicBrainz, Cover Art Archive and iTunes. Neither needs an account.

VariableAddsGet one
ACOUSTID_API_KEYIdentifies files by what they sound like, for tracks whose tags are wrong or missingacoustid.org/new-application⁠
GENIUS_API_KEYA second lyrics source behind LRCLIB — mostly older, rarer and non-English tracksgenius.com/api-clients/new⁠ (copy the Client Access Token)

fpcalc (Chromaprint), which AcoustID fingerprinting needs, is already installed in this image — the key is the only missing piece.

Keys are read from the environment at startup and are never written into the image or the cache.

⁠Health

The image carries a healthcheck against GET /health, which returns {"ok":true,"uptime":N}. First boot of a large library indexes before it serves, so the check allows a 40 second start period.

⁠Notes

  • Stopping is graceful: SIGTERM reaches the server directly and it shuts down in well under a second.
  • Logs go to stdout — docker logs zenhoot.
  • Scans are incremental. A file that cannot be read in one pass keeps its previous entry rather than vanishing from your library.

© ZNOWSOFT, LLC. ZenHoot is proprietary software; this image is distributed for use with the ZenHoot player.

Tag summary

Content type

Image

Digest

sha256:d13b6281d…

Size

105.4 MB

Last updated

about 1 month ago

docker pull znowf0x/zenhoot