5.0 KiB
5.0 KiB
music — frontend spec
React (vite). Dark theme by default, blue accent. Web UI is v1; backend is API-first so a mobile app can reuse the same endpoints later.
Theme
- Dark by default. Blue accent (
--accent: #2D7FF9or similar; pick one and define tints like kdrive's accent system). - Reuse the design-token approach from kdrive (CSS vars, Geist font). This is a distinct app with its own palette but shared visual language.
- Animations: tasteful — now-playing bar slide-up, queue/lyrics panel slide-in, album art crossfade on track change, subtle hover/press states, progress bar smoothing, shuffle/loop button state transitions.
Layout
- Left sidebar: nav (Artists / Albums / Songs / Favorites / Recently played / Vibe), profile/avatar (opens settings modal).
- Main: list/grid views per section.
- Bottom now-playing bar (persistent): cover thumb, title, artist + feats, prev / play-pause / next, volume slider, shuffle toggle, loop toggle (off → all → one), progress/seek bar, lyrics button, queue button.
Views
Artists
- List/grid of artists (image if enriched, else monogram). Click → artist page: header (image, name, genres), albums, all tracks.
Albums
- Grid of album covers (sort: name / year / artist). Click → album page: cover, title, artist, year, ordered tracklist, play / shuffle album.
Songs
- Virtualized list (library can be large): title, artist, album, duration, play count, favorite toggle. Sort by title/artist/added/plays. Fuzzy search box.
Favorites / Recently played
- Favorites: from
/api/favorites. Recently played: from/api/history.
Vibe
- "Start a vibe" from current track / an artist / a genre. Calls
/api/vibe. Shows the mixed queue; recommendation candidates are visually tagged subtly (small dot/"suggested") but interleaved, not grouped.
Player controls (now-playing bar)
- Global shuffle button (prominent, maybe in topbar or sidebar too): one tap →
GET /api/shuffle/all→ loads entire library shuffled as queue, starts playing. The headline feature. - Prev / Play-Pause / Next.
- Loop toggle: cycles off → loop-all (current queue/album) → loop-one (single track). Distinct icons per state.
- Volume slider.
- Seek bar: draggable, shows elapsed/total.
- Cover + title + artist + feats: feats rendered subtly after artist (e.g. "Artist · feat. X, Y").
- Lyrics button: opens lyrics panel.
- Queue button: opens queue panel.
Playback engine (client)
- Web Audio /
<audio>with/api/stream/{id}(range-enabled). - Playback modes from prefs:
- basic: sequential.
- gapless: preload next track, start without silence (dual audio elements or Web Audio buffering).
- crossfade: fade out current / fade in next over
crossfade_ms. - interstitial: play the configured interstitial track between every song (the gag mode).
- Log plays to
POST /api/historywithcompletedonce threshold reached (≥50% or final 10s).
Lyrics panel
- Slide-in panel. Calls
/api/lyrics/{track_id}. - Synced (LRC): auto-scroll, highlight active line, tap a line to seek.
- Falls back to plain text or "no lyrics found".
- Provider chain handled server-side (Musixmatch → LRCLIB), frontend just renders.
Queue panel
- Slide-in. Shows prev tracks (history within session) and next tracks (upcoming).
- Reorder (drag), remove, jump-to.
- Queue resets on session end (no persistence — per the decision).
Favorites / dislike
- Heart toggle on tracks/now-playing →
POST /api/favorite/{id}. - Dislike control (e.g. thumbs-down in now-playing context menu) →
POST /api/dislike/{id}. Track hides immediately. A toast confirms. - When a dislike reminder fires (server sweep), the app surfaces a toast: "You disliked '' — deleting in 24h. Undo?" with an Undo action calling
DELETE /api/dislike/{id}. (Also delivered via ntfy out-of-app.)
Settings modal (avatar click)
- Appearance: theme (dark default, allow light), blue accent + maybe a couple alt accents.
- Playback: mode (basic/gapless/crossfade/interstitial), crossfade ms (when crossfade), interstitial track picker (when interstitial).
- Recommendations: enable/disable vibe acquisition, max candidates (read-only display of the cap), Last.fm key field, MusicBrainz UA.
- Library: reindex button (
POST /api/library/reindex), enrich button (POST /api/enrich). - Persist via
/api/prefs.
Search
- Global fuzzy search (topbar) →
/api/search, grouped results: Artists / Albums / Songs. Handles Cyrillic/mixed scripts (display original, match normalized).
API-first note
- All state lives behind the documented endpoints so a future mobile client reuses them. No frontend-only business logic that the API can't reproduce. Keep auth simple for v1 (WG-gated, like the rest); leave room for token auth later for mobile over the tunnel.
Deploy
- Same pattern as kdrive: vite build → served by the FastAPI app (or its own static mount). nginx vhost via the panel:
music.kvmx.ru(replaces the swingmusic/navidrome entry) →http://localhost:<port>.