owenandClaude Sonnet 5 e48f063f03 Add structured lyrics storage and indexing (line/word timing, byte offsets)
Adds database.InsertLyrics/GetSongStructuredLyrics storing multiple
lyrics entries per song with per-line start times and, when the
source provides it, word-level cues carrying precomputed UTF-8 byte
offsets. library.IndexLyrics wires this into the scanner: embedded
plain-text tags are stored unsynced, and a same-basename sidecar .lrc
(plain or Enhanced) is parsed and stored synced, with word cues when
present. IndexFile now takes the media file's absolute path so lyrics
indexing can locate sidecar files.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014r98AtcBbevpscWLsfwVvv
2026-08-23 08:16:42 -05:00
2026-08-22 23:45:46 -05:00
2026-08-22 23:45:46 -05:00

VibeSonic

VibeSonic is a lightweight, self-hosted music/media server written in Go. It follows the same philosophy as other small Vibe* tools: a single Go binary, SQLite storage, server-rendered Bootstrap 5 templates, dark mode by default, minimal JavaScript, and no external services (no Redis, no message broker, no microservices, nothing Kubernetes-specific).

This is Phase 2 of 4. Phase 1 built the foundation (config, schema, auth, scanner, metadata, streaming, cover art, web UI shell). Phase 2 adds a complete implementation of the original Subsonic REST API through version 1.16.1 under /rest/* — every endpoint, backed by real data, including transcoding, HLS, a real mpv-backed jukebox, and a real podcast subsystem. See docs/subsonic-compatibility.md for the full endpoint-by-endpoint matrix. OpenSubsonic extensions are not yet implemented (Phase 3).

Features

Phase 1: foundation

  • SQLite storage (WAL mode, foreign keys, versioned migrations) with a schema already modeling artists, albums, songs, genres, contributors, playlists, favorites, ratings, scrobbles, playback history, bookmarks, play queues, shares, podcasts, internet radio, and settings
  • Native authentication: Argon2id password hashing, HTTP-only signed session cookies, CSRF-protected forms, session revocation
  • Optional Navidrome-style external authentication via a trusted reverse proxy header, gated on the real TCP peer address (never on spoofable X-Forwarded-For/X-Real-IP/Forwarded headers)
  • A library scanner supporting multiple music folders, incremental rescans, new/changed/deleted/renamed file detection, and a bounded worker pool — never a blind full rebuild
  • Real metadata extraction via ffprobe (multi-artist, multi-genre, MusicBrainz IDs, ReplayGain, embedded artwork/lyrics, sort fields, and more)
  • Stable, opaque, URL-safe IDs that survive restarts and rescans
  • Direct media streaming with HTTP range request support, correct MIME types, and no full-file buffering
  • Cover art discovery (embedded artwork or folder images) with a resized-image disk cache
  • A server-rendered, dark-mode, keyboard-friendly web UI: browsing, search, playlists, favorites, a persistent bottom player, and an admin section (users, music folders, scanner status, system settings)
  • /healthz and /readyz

Phase 2: Subsonic REST API

  • All 76 endpoints of the original Subsonic API through 1.16.1 — browsing (filesystem and ID3), search, playlists, favorites/ratings/ scrobbling, sharing, user management with the full permission model, bookmarks, play queue, chat, and library scan status
  • Real ffmpeg-backed transcoding (mp3/opus/aac) and HLS segmenting for stream/hls, bounded concurrency, killed on client disconnect
  • A real podcast subsystem: RSS feed refresh, bounded background downloads, restart recovery, downloaded episodes stream like any other song
  • A real jukebox backed by mpv over its JSON IPC socket — server-side playback, not a simulation; administratively unavailable (with a clear error) if mpv isn't installed
  • Both original Subsonic auth modes (token/salt and password, including enc: hex), verified against an AES-256-GCM-encrypted credential kept separate from the Argon2id hash used for native login — see docs/subsonic-compatibility.md
  • /rest/* authentication is entirely independent of the browser session/CSRF/external-auth flow

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.

Docker

docker compose up -d

See docker-compose.yml — mount your music directory read-only at /music and set VIBESONIC_SESSION_SECRET.

systemd

See systemd/vibesonic.service.

Configuration

VibeSonic is configured entirely through VIBESONIC_* environment variables — see docs/configuration.md for the full list and defaults. There is no separate config file.

Documentation

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.

S
Description
A vibe-coded Subsonic server meant to solve my issues with existing solutions.
Readme
627 KiB
Languages
Go 88.7%
HTML 7.7%
JavaScript 2.7%
CSS 0.8%
Dockerfile 0.1%