Files
vibesonic/README.md
T
owenandClaude Sonnet 5 789bf91eed Complete Phase 4: security hardening, player/playlist/admin UI, docs
Security:
- New internal/netguard package: podcast feed/enclosure fetching now
  refuses to dial non-public IPs (loopback/RFC1918/link-local/cloud
  metadata/CGNAT), validated per-connection including across redirects,
  closing an SSRF gap where a malicious or compromised feed URL could
  probe the server's internal network. Configurable via
  VIBESONIC_PODCASTS_ALLOW_PRIVATE_NETWORKS for intentional LAN feeds.
- Podcast episode downloads capped at 4GB (was unbounded, disk-exhaustion risk)
- Cover art decoding now rejects images above a 40-megapixel budget
  before full decode (decompression-bomb guard)
- HTTP server sets ReadHeaderTimeout (slowloris hardening)
- Admin folder-scan redirect now validated as same-site instead of
  trusting the raw Referer header (open-redirect fix)
- Legacy Subsonic token/salt auth now uses a constant-time comparison

Web UI completion:
- Persistent player: shuffle and repeat (off/all/one) controls, wired
  into queue advance/prev logic and persisted like other player state
- Admin user-permissions form: adminRole toggle (with a guard against
  demoting the last remaining admin) and per-user music-folder access
  checkboxes, backed by existing schema/enforcement that was previously
  unreachable from the UI
- Playlist M3U8 import/export

Docs: added docs/client-compatibility.md (honest tracking template —
no client testing has been performed), docs/deployment.md,
docs/security.md, docs/backup.md; refreshed README and cross-links;
added a footnote in docs/subsonic-compatibility.md distinguishing
spec-standard from VibeSonic-original OpenSubsonic extensions.

Also added Go fuzz tests for the external-auth CIDR/IP parser and the
LRC lyrics parser.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014r98AtcBbevpscWLsfwVvv
2026-08-23 09:18:17 -05:00

123 lines
5.3 KiB
Markdown

# VibeSonic
VibeSonic is a lightweight, self-hosted music/media server written in
Go. Single binary, SQLite storage, server-rendered Bootstrap 5
templates, dark mode by default, minimal JavaScript, no external
services (no Redis, no message broker, no microservices).
It implements the **original Subsonic REST API through version
1.16.1**, in full, plus a set of **OpenSubsonic extensions**, so it
works with existing Subsonic/OpenSubsonic client apps, alongside a
complete server-rendered web UI for browser use. See
[`docs/subsonic-compatibility.md`](docs/subsonic-compatibility.md) for
the endpoint-by-endpoint matrix and
[`docs/client-compatibility.md`](docs/client-compatibility.md) for
real-client testing status.
## Features
- SQLite storage (WAL mode, foreign keys, versioned migrations)
- Native authentication (Argon2id, HTTP-only session cookies, CSRF) and
optional Navidrome-style external authentication via a trusted
reverse-proxy header, gated on the real TCP peer address — see
[`docs/external-auth.md`](docs/external-auth.md)
- A library scanner: multiple music folders, incremental rescans,
new/changed/deleted/renamed detection, bounded worker pool
- Real metadata extraction via `ffprobe` (multi-artist/genre,
MusicBrainz IDs, ReplayGain, embedded artwork/lyrics, sort fields)
- Direct streaming with HTTP range support, plus real ffmpeg-backed
transcoding (mp3/opus/aac) and HLS segmenting, bounded concurrency,
cancelled on client disconnect
- Structured lyrics: plain, line-synced, and (where the source
provides it) word/syllable-level timing, exposed via the
`songLyrics` OpenSubsonic extension and rendered in the web player
with click-to-seek and active-line highlighting
- Sonic similarity: real audio-feature analysis (tempo, loudness,
spectral shape, chroma) computed during scanning, used for
similar-track lookups and path-finding between songs
- Optional MusicBrainz/Cover Art Archive metadata enrichment (off by
default — VibeSonic works fully offline otherwise)
- Podcasts (RSS subscriptions, bounded background downloads, restart
recovery), Internet radio stations, shares (public, no-login-required
links), bookmarks, and multi-device play queues
- A real jukebox backed by `mpv`'s JSON IPC — server-side playback, not
a simulation; cleanly unavailable if `mpv` isn't installed
- API keys, with the full Subsonic per-user permission model
(admin/settings/stream/download/upload/playlist/cover art/comment/
podcast/share/jukebox/video-conversion roles, plus per-user music
folder access)
- A server-rendered, dark-mode, keyboard-friendly web UI covering
browsing, search, playlists (including M3U import/export),
favorites, a persistent player with shuffle/repeat and the Media
Session API, and a full admin section
- `/healthz` and `/readyz`
## Quick start
```
go build -o vibesonic ./cmd/vibesonic
VIBESONIC_SESSION_SECRET=$(openssl rand -hex 32) ./vibesonic
```
Then open `http://localhost:8080` — on a fresh database you'll land on
the setup wizard, which creates the administrator account, your first
music folder, and kicks off the first scan.
`ffmpeg`/`ffprobe` should be on `PATH` (or pointed to via
`VIBESONIC_FFMPEG_PATH`/`VIBESONIC_FFPROBE_PATH`) for metadata reading,
cover art extraction, and transcoding/HLS to work. `mpv` should be on
`PATH` (or pointed to via `VIBESONIC_MPV_PATH`) for the jukebox to be
available — without it, `jukeboxControl` returns a clear "unavailable"
error rather than pretending to work.
Point any Subsonic/OpenSubsonic client at `http://<host>:8080` (base
URL only, no `/rest` suffix — clients construct that themselves) with a
VibeSonic username/password, or an API key generated from account
settings.
### Docker
```
docker compose up -d
```
See [`docker-compose.yml`](docker-compose.yml) — mount your music
directory read-only at `/music` and set `VIBESONIC_SESSION_SECRET`.
Docker is convenient but never required; see
[`docs/deployment.md`](docs/deployment.md) for running natively.
### systemd
See [`systemd/vibesonic.service`](systemd/vibesonic.service) and
[`docs/deployment.md`](docs/deployment.md) for install steps and
reverse-proxy examples (Caddy/nginx/Traefik).
## Configuration
VibeSonic is configured entirely through `VIBESONIC_*` environment
variables — see [`docs/configuration.md`](docs/configuration.md) for the
full list and defaults. There is no separate config file.
## Documentation
- [`docs/architecture.md`](docs/architecture.md) — how the pieces fit together
- [`docs/configuration.md`](docs/configuration.md) — every environment variable
- [`docs/external-auth.md`](docs/external-auth.md) — trusted reverse-proxy authentication
- [`docs/subsonic-compatibility.md`](docs/subsonic-compatibility.md) — protocol endpoint/extension status
- [`docs/client-compatibility.md`](docs/client-compatibility.md) — real-client testing tracker
- [`docs/deployment.md`](docs/deployment.md) — native/Docker/systemd/reverse-proxy deployment
- [`docs/security.md`](docs/security.md) — security-relevant design decisions
- [`docs/backup.md`](docs/backup.md) — what to back up and how (SQLite WAL caveats included)
## Development
```
go fmt ./...
go vet ./...
go test ./...
```
Most tests exercise real SQLite databases and, where relevant, the real
`ffmpeg`/`ffprobe` binaries (skipped automatically if not installed).
No mocks are used for the database.