Repository navigation
Releases: lmdevv/music
Release list
[music] 0.3.0
Roles and library access, playlist sharing, Jams (listening together from a link), autoplay, and a performance pass across the server and the web app.
curl -fsSLO https://raw.githubusercontent.com/lmdevv/music/v0.3.0/deploy/docker/compose.yaml
MUSIC_VERSION=0.3.0 MUSIC_DIR=/path/to/music PUBLIC_URL=http://<host>:8080 docker compose up -dNixOS: the module's default image is now ghcr.io/lmdevv/music:0.3.0, and the CLI is nix run github:lmdevv/music/v0.3.0#cli. See docs/homelab.md and docs/operations.md.
Upgrading from 0.2.0
Change the tag and recreate the container. The database is backed up to /data/backups/pre-0.3.0-…-from-0.2.0-….zip before migrating, and an older image refuses to start on migrated data. To roll back, run /app/bin/restore <zip>, then start 0.2.0. CI tests the upgrade and the rollback from both 0.1.0 and 0.2.0, checking that accounts, songs, playlists, the queue and search survive and that songs stream afterwards.
-
Library folders must be inside
MUSIC_ROOTS. The default is/music. If you mounted a library anywhere else in the container, setMUSIC_ROOTS(comma-separated absolute paths) on the container orservices.music.extraEnvironment, or that library's scans are refused and it stops streaming./proc,/sys,/devand/are always refused. -
Each library claims its folder. Before scanning, the media service resolves the folder, including symlinks and bind mounts, and the library that was added first keeps it. Two libraries can no longer index the same files through different paths. After the upgrade every library is claimed in a quick pass, so streaming resumes within seconds and full rescans follow.
-
Existing sign-ins keep working. The first account becomes the server's owner, and other admins stay admins.
-
API changes for scripts and older CLIs:
queue.removeandplayback.jumptake a queue entry ID, not a track ID or index.- Playlist rows for songs you can't read have
track: null. - Queue entries can carry
withheld: true.
Use the 0.3.0 CLI (
nix run …#clior the image'smusicbinary).
Roles, people and library access (#22)
- Roles:
- The server's owner can do anything.
- Admins manage people, invites and their own libraries.
- Members listen, and guests hear only what is shared with them.
- People settings: suspend, remove, and change roles. Admins can make reset links instead of anyone needing email.
- Library access: each library is private, restricted to named people, or shared with everyone. Only a library's owner can widen access.
- When an admin is demoted or suspended: the server's owner can narrow access to their libraries, but can't widen it.
- Sign-in:
- Generic errors, with rate limits.
- Password resets and suspensions end every session.
- A reset also turns off that person's API keys.
Sharing, queue and autoplay (#27)
- Queue entries have stable IDs, so two devices editing the queue can't hit the wrong row. The queue can be reordered and shows who added each song.
- Autoplay is on by default and can be turned off. It adds songs like what's playing, from libraries you can read.
- Playlists can be reordered, renamed and described, and shared with people as viewer or collaborator, or with everyone. "Shared with you" appears in the sidebar.
- Copy link works on albums, artists, playlists and songs.
- Names are stripped of control and invisible characters, and the CLI escapes anything it prints from the server.
Jams (#28)
- Start a Jam and share its link or QR code. Everyone hears the host's queue and can listen along on their own device, in sync.
- The host decides who can join (open, approval or locked), how many songs each person can add, whether people can control playback, and who can move or remove songs. The host can remove people and make a new link.
- Guest accounts from a Jam link are an admin setting, off by default. They are rate-limited, need approval once anyone has been removed, and are deleted when the Jam ends.
- What members can hear: only the songs in the Jam's queue, through 5-minute stream links. During a Jam, autoplay never pulls from libraries that were shared only with the host.
Performance (#29, #30)
On a 20,000-song library:
| 0.2.0 | 0.3.0 | |
|---|---|---|
| Full first scan | 34.3 s | 20.6 s |
| No-op rescan | 3.6 s | 1.2 s |
| Documents an open browser re-reads during a 2,000-file scan | 16,679 | 4,966 |
| Entry JavaScript (gzip) | 218 KiB | 159 KiB |
| Playing a song with ~1,300 song rows loaded | 3.6 s of long tasks | ≤ 75 ms |
| Opening a 1,000-song playlist | 1.94 s | 0.79 s |
| Memory after 30 s of fast scrolling through Songs | 676 MB | 38 MB |
Long lists render only the rows near the screen. Heavy panels load on demand. Scan batches read about 40 documents instead of about 630, and art cleanup no longer sweeps everything after each scan.
Web polish (#26)
- Errors no longer stop playback, and wrong-password errors stay out of the console.
- Design tokens replace raw values.
- Focus is kept when you remove a queue row.
- Accessibility fixes in dialogs.
- Ctrl+J moves down in the command menu.
- The "Play on" picker works across phone and desktop layouts.
Known limitations
- The server's owner can always reach every library's files. "Only you" hides a library from other members and admins, not from the owner who runs the machine.
- Old links keep working for a while after access is removed: stream links for up to 6 hours (5 minutes for Jam-only access), and cover-art links for up to about 14 days.
- Find in page doesn't reach song rows far off screen.
- New screens (People, sharing, Jams) haven't had a Paper design pass yet.
- Library and list pages left open across the upgrade error once; reload them.
[music] 0.2.0
Homelab-ready hardening of [music], plus a round of backend, media, and player fixes.
curl -fsSLO https://raw.githubusercontent.com/lmdevv/music/v0.2.0/deploy/docker/compose.yaml
MUSIC_VERSION=0.2.0 MUSIC_DIR=/path/to/music PUBLIC_URL=http://<host>:8080 docker compose up -dNixOS: add the flake and set services.music = { enable = true; publicUrl = "…"; musicDirs = [ "/srv/music" ]; };. The module's default image is ghcr.io/lmdevv/music:0.2.0. The CLI is nix run github:lmdevv/music/v0.2.0#cli. See docs/homelab.md and docs/operations.md.
Upgrading from 0.1.0
Change the tag and recreate the container. Before anything else, the container backs up the database to /data/backups/pre-0.2.0-…-from-0.1.0-….zip, then migrates. To go back, restore that backup first with /app/bin/restore <zip>, then start 0.1.0. An older image now refuses to start on data a newer version has migrated, instead of running over it. This upgrade path is tested in CI.
Deploy and homelab (#21, #25)
- Backup before every upgrade, the newest 5 kept (
BACKUP_KEEP), plus a restore helper. - Images are published only after every CI check passes. Tags are
X.Y.Z,X.Yandlatest(amd64 and arm64), and these tags never move to an older build. - No service runs as root.
- The Convex instance secret no longer appears in any process's arguments (ADS-115).
/healthzchecks Caddy, the media service and the database.- Clean
docker stopin a few seconds. - Starting with
TZset works again. - Readable logs.
- A homelab
compose.yamlthat works on Docker 20.10+, with reverse-proxy and Tailscale notes. - Flake
packages.cli. - Module options:
image,imageFile,pull,autoUpdate,backend,uid/gid,extraEnvironment, and namedmusicDirs. - A NixOS VM test in CI.
- CLI keys can come from
--key-stdin,MUSIC_API_KEYor a hidden prompt. Plain http to a non-local server needs--insecure. - CI now runs the security, CLI, media and browser suites that used to be skipped.
Backend (#23)
- The queue stays consistent across removals and shuffle.
- Playback position updates read 2 documents instead of about 1,000.
- Deleting a library is batched and cleans up playlists, likes, plays and queues.
- Songs whose files went missing show as "Unavailable" rows.
- Liked songs page past 1,000.
- Overlapping library folders are refused.
- A scan that keeps crashing is capped.
- Daily cleanup.
- Members' lists page only over the libraries they can read (ADS-112).
Media and player (#24)
- An empty or unmounted library folder no longer marks the library missing.
- Renames and moves keep likes, plays and playlist entries.
- No leaked file handles.
- The watcher restarts on its own.
- Replaced and disc-folder cover art is picked up, and unused art is cleaned up.
- Fixed a transcoder timeout.
- Expired stream URLs are re-signed, so pausing for 6 hours no longer breaks playback.
- Recovery when the browser's audio buffer is full.
Known limitations
- Library and list pages left open across the upgrade error once; reload them.
- Signed stream URLs stay valid for up to 6 hours after access is removed.
[music] 0.1.0
The first release of [music]: self-hosted music for people and agents.
docker run -d --name music -p 8080:8080 -v music-data:/data -v /path/to/music:/music:ro \
-e PUBLIC_URL=http://localhost:8080 ghcr.io/lmdevv/music:0.1.0Open http://localhost:8080, create the admin account, and add /music as a library.
What's in it
- One container (linux/amd64, linux/arm64) with self-hosted Convex, the media service, the web app, and Caddy on one port; a NixOS module that runs it.
- Library scan of your existing files and tags, watched for changes, with artwork.
- Web app for desktop and phone, light (Apple Music feel) and dark (Spotify feel): home, albums, artists, songs, search, playlists, likes, history, Now Playing, queue, command menu (⌘K), settings, and admin.
- Lossless and gapless playback: FLAC in fragmented MP4 through a Media Source Extensions engine, measured sample-accurate in Chromium and within one sample in Firefox; AAC for data saver; HTML audio fallback.
- Live handoff and remote control between your devices.
- Multi-user accounts with invites, shared or private libraries, and API keys.
- The
musicCLI generated from the command registry, and an agent skill inskills/music.
Demo videos
music-demo-desktop.mp4 (1 min): first-run setup, real scan, play, Now Playing, search, command menu, like, playlist, API key, dark mode. music-demo-phone.mp4: the same account on a phone while the desktop plays. Demo music is CC licensed; credits in docs/demo-music.md.
Known gaps
- Safari and iOS are untested. Firefox and Chromium are tested.
- The first play of an uncached lossy file waits for its transcode (a few seconds). The next song is prepared ahead.
- The NixOS module runs the container rather than native systemd units.
- No lyrics, offline downloads, or native apps yet. Those come in V1.