Jonathan 8922af757c docs: update README for Last.fm, redesign, progress/retry, and pages
Bring the README current with everything shipped since it was written:
Last.fm as a second discovery source + the /lastfm browse page, the
/library grid, The Floor's three-phase progress + retry, and the
Pressing Plant design system. Add a "Running it" quick-start. Fix a
pre-existing inaccuracy: slskd is an external daemon reached via
config, not a compose service (stack is db + web + worker).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 23:53:30 +02:00

Lyra

Self-hosted, multi-source music acquisition and library tool — a replacement for Lidarr + NZBget. Lyra discovers, ranks, downloads, tags, and organizes music across sources of differing quality: Qobuz (lossless/hi-res), Soulseek (P2P), and YouTube (universal lossy fallback), with recommendation-driven discovery via ListenBrainz and Last.fm (Spotify's recommendation/related-artists APIs were retired for new apps, so discovery is MetaBrainz-native and MBID-clean — no Spotify).

Status

Built in three slices:

  1. Acquisition engine done. Resolve a request against MusicBrainz, match/rank across Qobuz/Soulseek/YouTube, download the best source into an isolated staging dir, verify completeness, tag (mutagen), and atomically promote the clean album into Artist/Album (Year)/## Title.ext.
  2. Library manager done. Watched artists (live MB search + follow), per-release monitor toggles + auto-monitor-future, a wanted list with retry + quality-upgrade window, and a worker "monitor" that discovers new releases and auto-grabs through the acquisition pipeline. Plus a library scan that ingests existing on-disk albums as have + monitored + followed, and a per-artist studio-only / show-all release-type filter.
  3. Discovery done. Recommendation-driven finding of new music via ListenBrainz similar-artists and Last.fm artist.getSimilar (both MBID-native), behind a pluggable SimilaritySource interface — Last.fm registers as a second source automatically once its API key is set, and cross-source scores are summed per candidate. A background sweep (and a "Discover now" button) aggregates artists similar to the ones you follow into a manual review feed of suggested artists and albums at /discover; Follow and Want reuse the slice-2 follow / wanted flows, Dismiss is permanent. Plus a web-side seed-search box. Every suggestion and seed-search result opens a read-only artist preview (/discover/artist/[mbid]) — discography, per-album tracklists, and "in library" / "monitored" badges — where you can Follow or Want before committing. No Spotify (its recommendation APIs are dead for new apps).

Alongside the three slices:

  • Last.fm browse (/lastfm) — your Last.fm top artists and albums (by period), with a "hide items already in my library" toggle; each artist opens a modal of your most-played songs and albums, and every album is one click to Want.
  • Library (/library) — a cover-art grid of everything on disk, filterable, each album opening a tracklist modal.
  • The Floor (home) — a live queue of in-flight acquisitions with three-phase progress (Searching → Downloading → Finishing), a live download percentage, a per-job "pressing ticket" (source · format · tracks · elapsed), and a Retry button on anything that needs attention.

The whole UI runs a hand-rolled "Pressing Plant" design system (warm-paper theme, self-hosted Fraunces serif for prose vs. system mono for machine data, light/dark aware).

Operational notes: the monitor and the discovery sweep are both off by default — set monitor.enabled=true (or Settings → Monitor, + optional monitor.* tuning) to activate auto-grab/upgrade, and discover.enabled=true (or Settings → Discovery, + optional discover.* tuning) to activate the scheduled discovery sweep. The /discover "Discover now" button and seed-search work with the sweep off. Credentials (Qobuz, Soulseek, Last.fm) are entered in Settings and persist across docker compose up -d --build rebuilds (don't use down -v; secrets are encrypted at rest with LYRA_SECRET_KEY). Tests run against a separate lyra_test database (a guard blocks the live DB). Deferred hardening + the full roadmap live in the implementation-plan "Notes" sections under docs/superpowers/plans/.

Architecture

The docker compose stack is three services on a home server:

  • db — Postgres, the shared source of truth.
  • web — the Next.js app: UI + API (search, request, queue, progress, settings).
  • worker — the Python worker: all source integration (streamrip, yt-dlp, slskd client, mutagen; MusicBrainz + ListenBrainz + Last.fm for metadata and discovery), running the six-stage acquisition pipeline plus the background monitor and discovery sweeps.

Soulseek support talks to an external slskd daemon (an off-the-shelf headless Soulseek client) — the worker reaches it via the slskd.url + slskd.api_key credentials set in Settings, so run slskd separately rather than as part of this stack.

A shared /music volume is the library, with a separate /staging volume for in-progress downloads (point STAGING_DIR at a fast local disk when MUSIC_DIR is a network share).

See docs/superpowers/specs/ for the full design.

Running it

cp .env.example .env          # then edit: set LYRA_SECRET_KEY (openssl rand -base64 32) and MUSIC_DIR
docker compose up -d --build  # web on http://localhost:8770 ; NEVER `down -v` (wipes the Postgres volume)

The web entrypoint runs prisma migrate deploy on every rebuild, so schema changes reach the live DB automatically. Enter Qobuz / Soulseek / Last.fm credentials in Settings (they persist across rebuilds), then follow an artist or request an album to feed The Floor.

S
Description
Self-hosted multi-source music acquisition tool replacing Lidarr (Qobuz/Soulseek/YouTube/Spotify)
Readme 2.5 MiB
Languages
Python 50.7%
TypeScript 45.4%
CSS 3.6%
Dockerfile 0.2%
Shell 0.1%