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>
This commit is contained in:
@@ -4,8 +4,8 @@ Self-hosted, multi-source music acquisition and library tool — a replacement f
|
|||||||
Lidarr + NZBget. Lyra discovers, ranks, downloads, tags, and organizes music across
|
Lidarr + NZBget. Lyra discovers, ranks, downloads, tags, and organizes music across
|
||||||
sources of differing quality: **Qobuz** (lossless/hi-res), **Soulseek** (P2P), and
|
sources of differing quality: **Qobuz** (lossless/hi-res), **Soulseek** (P2P), and
|
||||||
**YouTube** (universal lossy fallback), with recommendation-driven discovery via
|
**YouTube** (universal lossy fallback), with recommendation-driven discovery via
|
||||||
**ListenBrainz** (Spotify's recommendation/related-artists APIs were retired for new
|
**ListenBrainz** and **Last.fm** (Spotify's recommendation/related-artists APIs were
|
||||||
apps, so discovery is MetaBrainz-native and MBID-clean — no Spotify).
|
retired for new apps, so discovery is MetaBrainz-native and MBID-clean — no Spotify).
|
||||||
|
|
||||||
## Status
|
## Status
|
||||||
|
|
||||||
@@ -22,8 +22,10 @@ Built in three slices:
|
|||||||
existing on-disk albums as have + monitored + followed, and a per-artist
|
existing on-disk albums as have + monitored + followed, and a per-artist
|
||||||
studio-only / show-all release-type filter.
|
studio-only / show-all release-type filter.
|
||||||
3. **Discovery** — ✅ **done**. Recommendation-driven finding of new music via
|
3. **Discovery** — ✅ **done**. Recommendation-driven finding of new music via
|
||||||
**ListenBrainz** similar-artists (MBID-native), behind a pluggable
|
**ListenBrainz** similar-artists and **Last.fm** `artist.getSimilar` (both
|
||||||
`SimilaritySource` interface. A background sweep (and a "Discover now" button)
|
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
|
aggregates artists similar to the ones you follow into a manual review feed of
|
||||||
suggested **artists** and **albums** at `/discover`; **Follow** and **Want**
|
suggested **artists** and **albums** at `/discover`; **Follow** and **Want**
|
||||||
reuse the slice-2 follow / wanted flows, **Dismiss** is permanent. Plus a
|
reuse the slice-2 follow / wanted flows, **Dismiss** is permanent. Plus a
|
||||||
@@ -33,27 +35,62 @@ Built in three slices:
|
|||||||
Follow or Want before committing. No Spotify (its recommendation APIs are dead
|
Follow or Want before committing. No Spotify (its recommendation APIs are dead
|
||||||
for new apps).
|
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
|
**Operational notes:** the monitor and the discovery sweep are both **off by
|
||||||
default** — set `monitor.enabled=true` (+ optional `monitor.*` tuning) in the
|
default** — set `monitor.enabled=true` (or Settings → Monitor, + optional `monitor.*`
|
||||||
`Config` table to activate auto-grab/upgrade, and `discover.enabled=true` (or
|
tuning) to activate auto-grab/upgrade, and `discover.enabled=true` (or
|
||||||
Settings → Discovery, + optional `discover.*` tuning) to activate the scheduled
|
Settings → Discovery, + optional `discover.*` tuning) to activate the scheduled
|
||||||
discovery sweep. The `/discover` "Discover now" button and seed-search work with the
|
discovery sweep. The `/discover` "Discover now" button and seed-search work with the
|
||||||
sweep off. Credentials are entered in Settings and persist across
|
sweep off. Credentials (Qobuz, Soulseek, Last.fm) are entered in Settings and persist
|
||||||
`docker compose up -d --build` rebuilds (don't use `down -v`). Tests run against a
|
across `docker compose up -d --build` rebuilds (don't use `down -v`; secrets are
|
||||||
separate `lyra_test` database (a guard blocks the live DB). Deferred hardening + the
|
encrypted at rest with `LYRA_SECRET_KEY`). Tests run against a separate `lyra_test`
|
||||||
full roadmap live in the implementation-plan "Notes" sections under
|
database (a guard blocks the live DB). Deferred hardening + the full roadmap live in
|
||||||
|
the implementation-plan "Notes" sections under
|
||||||
[`docs/superpowers/plans/`](docs/superpowers/plans/).
|
[`docs/superpowers/plans/`](docs/superpowers/plans/).
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
Three Docker containers on a home server:
|
The `docker compose` stack is three services on a home server:
|
||||||
|
|
||||||
- **Next.js app** — UI + API (search, request, queue, progress, settings).
|
- **db** — Postgres, the shared source of truth.
|
||||||
- **Python worker** — all source integration (streamrip, yt-dlp, slskd client,
|
- **web** — the Next.js app: UI + API (search, request, queue, progress, settings).
|
||||||
mutagen; MusicBrainz + ListenBrainz for metadata and discovery), running the
|
- **worker** — the Python worker: all source integration (streamrip, yt-dlp, slskd
|
||||||
six-stage acquisition pipeline plus the background monitor and discovery sweeps.
|
client, mutagen; MusicBrainz + ListenBrainz + Last.fm for metadata and discovery),
|
||||||
- **slskd** — off-the-shelf headless Soulseek daemon.
|
running the six-stage acquisition pipeline plus the background monitor and discovery
|
||||||
|
sweeps.
|
||||||
|
|
||||||
**Postgres** is the shared source of truth; a shared `/music` volume is the library.
|
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/`](docs/superpowers/specs/) for the full design.
|
See [`docs/superpowers/specs/`](docs/superpowers/specs/) for the full design.
|
||||||
|
|
||||||
|
## Running it
|
||||||
|
|
||||||
|
```sh
|
||||||
|
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.
|
||||||
|
|||||||
Reference in New Issue
Block a user