Add review, discover, email; rebuild the design system
Three features and a typographic pass over everything. REVIEW. Picking a file and trusting it are different questions, so they now use different numbers. The existing rank decides which candidate to fetch and is right to weigh peer upload slots and queue length -- but none of that says anything about whether the file is the correct recording, and a fast peer must not be able to raise the confidence of a wrong match. So confidence() scores the filename alone: title 0.75, artist 0.25, album +0.05, and a variant tag you did not ask for multiplies by 0.8 AND caps below the auto threshold. Confidence gates the IMPORT, not the download. The transfer completes either way and the file waits in downloads, so approving is instant and rejecting is a delete. Holding the transfer instead would mean the peer is usually gone by the time anyone looks. The two cases it exists for: "02 Creep.flac" in an unsorted folder scores 0.75 -- title exactly right, artist simply absent, the commonest honest case there is -- and must be reviewed rather than binned. And "Creep (Live at Glastonbury)" scores 0.80 with BOTH artist and title perfect; the cap is what stops a live recording auto-filing over the studio version. Ask for "Creep (Acoustic)" and it auto-imports at 0.97, because then the variant is the request. DISCOVER. Related artists seeded from what you have actually imported, plus a recap of top artists, genres and decades. Built on muse's own request history, never on listening data: Navidrome owns play counts and history, and a second source of truth for those would disagree with the one you listen through. EMAIL. Optional, off unless MUSE_SMTP_HOST is set. Sends on import and on review-needed. smtplib is blocking so it runs off the event loop, and every failure is logged and swallowed -- a notification is never worth failing an import over. Google accounts need no configuration, since the identity is an address. Each user owns their own setting under Settings, deliberately not an admin route: an address you cannot change yourself is someone else's chore. DESIGN. A real type scale (display/title/headline/body/callout/caption) whose tracking tightens as size grows, which is the single biggest tell of typography nobody set. Specular top edges on glass surfaces -- blur alone reads as a grey rectangle. A two-part elevation scale, contact shadow plus soft light. Semantic colours are now per-theme: the amber tuned for the dark background failed contrast outright on white, which was exactly the text a reviewer most needs to read. The tab underline became a sliding pill so the eye tracks one object, and Review only appears when something is actually waiting. Add tests/test_matching.py: 13 assertions on the confidence bands rather than the exact scores. 90 tests pass across the three suites. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
cc3490483e
commit
205e0a44b8
23 files changed
+1484
-102
No files matched your search
@@ -184,6 +184,76 @@ can actually serve you (free upload slot, short queue), then filename
|
||||
plausibility, then bitrate. A marginally better file behind 200 queued users
|
||||
loses to a good-enough one available now.
|
||||
|
||||
## Review: when muse isn't sure
|
||||
|
||||
Picking a file and *trusting* it are different questions, so they use different
|
||||
numbers. The rank above decides which candidate to fetch and is right to weigh
|
||||
peer speed and queue length. None of that says anything about whether the file
|
||||
is the correct recording — a fast peer must not be able to raise the confidence
|
||||
of a wrong match. So a second score, **confidence**, is computed from the
|
||||
filename alone:
|
||||
|
||||
| | weight |
|
||||
|---|---|
|
||||
| title present in the filename | 0.75 |
|
||||
| artist present in the filename, folder, or partially | 0.25 |
|
||||
| album name somewhere in the path | +0.05 |
|
||||
| a variant tag you didn't ask for (live, remix, cover, karaoke…) | ×0.8, and capped below auto |
|
||||
|
||||
Then:
|
||||
|
||||
- **≥ 0.95** — filed automatically. Nothing to do.
|
||||
- **0.70 – 0.95** — held in **Review** with the reasons shown.
|
||||
- **< 0.70** — also held, but it will almost certainly be rejected.
|
||||
|
||||
Confidence gates the **import, not the download**. The transfer completes
|
||||
either way and the file waits in the downloads directory: approving is then
|
||||
instant and rejecting is a delete. Holding the *transfer* instead would mean
|
||||
the peer has usually vanished by the time anyone looks.
|
||||
|
||||
The two cases this exists for are worth naming. A file called `02 Creep.flac`
|
||||
in an unsorted folder scores 0.75 — the title is exactly right and the artist
|
||||
is simply absent, which is the commonest honest case there is, so it must land
|
||||
in review rather than be binned. And `Creep (Live at Glastonbury)` scores 0.80
|
||||
with *both* artist and title matching perfectly: the variant cap is what stops
|
||||
a live recording auto-filing over the studio version you asked for. Ask for
|
||||
`Creep (Acoustic)` explicitly and it auto-imports at 0.97, because then the
|
||||
variant is the request.
|
||||
|
||||
Tune with `MUSE_AUTO_CONFIDENCE` and `MUSE_REVIEW_CONFIDENCE`.
|
||||
`tests/test_matching.py` asserts the bands, not the exact scores.
|
||||
|
||||
## Discover
|
||||
|
||||
Recommendations and a personal recap, both built from **muse's own request
|
||||
history** plus Deezer's related-artists graph — never from listening data.
|
||||
Navidrome owns play counts, favourites and history; a second source of truth
|
||||
for those would end up disagreeing with the one you actually listen through.
|
||||
|
||||
So "because you added" seeds off the artists you have imported most, and the
|
||||
recap counts requests, genres and release decades. What you *played* is
|
||||
Navidrome's business.
|
||||
|
||||
## Email
|
||||
|
||||
Off unless `MUSE_SMTP_HOST` and `MUSE_SMTP_FROM` are set. muse writes to you
|
||||
when a request lands in your library, and when a download finished but needs
|
||||
your call in Review.
|
||||
|
||||
```
|
||||
MUSE_SMTP_HOST=smtp.fastmail.com
|
||||
MUSE_SMTP_PORT=587
|
||||
MUSE_SMTP_USER=you@example.com
|
||||
MUSE_SMTP_PASS=an-app-password
|
||||
MUSE_SMTP_FROM=muse@example.com
|
||||
MUSE_SMTP_TLS=starttls # or ssl, or none
|
||||
```
|
||||
|
||||
Each user sets their own address under **Settings**, or turns mail off
|
||||
entirely. Google accounts need no configuration — the identity *is* an email
|
||||
address. Sending runs on a worker thread and every failure is logged and
|
||||
swallowed: a notification is never worth failing an import over.
|
||||
|
||||
## Authentication
|
||||
|
||||
OAuth against GitHub and/or Google, built so this can face the internet.
|
||||
@@ -374,7 +444,14 @@ stat -c "%h" "/data/media/music/<Artist>/<Album> (<Year>)/<NN> - <Title>.flac"
|
||||
| `MUSE_DB` | `/config/muse.db` | job history |
|
||||
| `MUSE_FORMATS` | `flac,mp3` | ordered preference; anything else is rejected |
|
||||
| `MUSE_MIN_MATCH` | `0.45` | filename-to-title similarity floor |
|
||||
| `MUSE_AUTO_CONFIDENCE` | `0.95` | at or above this, import without asking |
|
||||
| `MUSE_REVIEW_CONFIDENCE` | `0.70` | below this, held but probably wrong |
|
||||
| `MUSE_WORKERS` | `3` | concurrent Soulseek searches |
|
||||
| `MUSE_SMTP_HOST` | — | set to enable email; see **Email** above |
|
||||
| `MUSE_SMTP_PORT` | `587` | |
|
||||
| `MUSE_SMTP_USER` / `_PASS` | — | omit for an unauthenticated relay |
|
||||
| `MUSE_SMTP_FROM` | `MUSE_SMTP_USER` | envelope sender |
|
||||
| `MUSE_SMTP_TLS` | `starttls` | `starttls`, `ssl`, or anything else for none |
|
||||
| `MUSE_LOG_LEVEL` | `INFO` | |
|
||||
|
||||
`MUSE_FORMATS` is a preference list, best first — rejecting everything not on
|
||||
@@ -426,7 +503,12 @@ package page → Package settings → Change visibility.
|
||||
| `POST /api/import` | queue many from pasted text |
|
||||
| `POST /api/retry/{id}` | requeue a failed job |
|
||||
| `GET /api/jobs` | request history and state (own, or all for admins) |
|
||||
| `GET /api/review` | downloads held back for a decision |
|
||||
| `POST /api/review/{id}` | `approve` files it, `reject` deletes it |
|
||||
| `GET /api/discover` | related artists, seeded from what you've imported |
|
||||
| `GET /api/recap` | your top artists, genres and decades |
|
||||
| `GET /api/me` | who you are, your role and quota usage |
|
||||
| `PATCH /api/me` | your own email address and notification toggle |
|
||||
| `GET /api/health` | slskd reachability, mount writability |
|
||||
| `GET /api/admin/users` | list users with usage |
|
||||
| `POST /api/admin/users` | invite |
|
||||
|
||||
Reference in new issue
Block a user