A small live dashboard pulling pixelbrix on Last.fm into one page. Lives at /music/. Built before the discovery tool — the dashboard is the surface you check casually; the discovery tool is where you go when you want to dig.
What it shows
- Now playing — current track if I’m listening, or “not scrobbling right now”. Refreshes a few times a minute. Pulls from
user.getRecentTracksand treats the first track as live if it’s flaggednowplaying. - Stat bar — total scrobbles, lifetime artists, “loved” count. Three numbers, updated lazily.
- Top artists / albums / tracks with a period selector — 7d / 1mo / 3mo / 6mo / 1yr / all. The default is 1mo because that’s the window where my taste signal is strongest. Bars on the artist list scale to the maximum count in the current period; tabular numbers in the count column. Album art comes from Last.fm’s “extralarge” image if it’s there, otherwise a placeholder fill.
- Hour-of-week heatmap — 7 rows (Sun → Sat) by 24 columns (00 → 23). Each cell is opacity-encoded; the densest cells are when I actually listen, which turns out to be predictably evening-skewed across most of the week and Sunday-afternoon-skewed on weekends. Generated by
buildHeatmap()walking the recent-tracks pages.
How it’s built
Vanilla React, no state library, no fetching framework. The component owns its own state, fires Promise.all for the parallel period-independent fetches at mount, and re-fetches on period changes. All data lives in src/lib/lastfm.ts as typed wrappers around the Last.fm REST API. The API key is exposed via PUBLIC_LASTFM_API_KEY because Last.fm read endpoints are unauthenticated for public profiles — there is nothing to leak.
The heatmap is the most interesting piece of the build. Last.fm’s API does not return scrobbles in a “by hour” form; it returns paginated recent-tracks. buildHeatmap walks 5 pages (approximately the last 1,000 scrobbles), groups by (day-of-week, hour-of-day), and writes into a 7×24 grid. The opacity scale is tuned for the typical max — visually saturating at ~50 plays per cell.
Caveats
- The “now playing” indicator is only as fresh as Last.fm’s scrobble propagation; there’s a lag of seconds-to-minutes between hitting play and the dot turning on
- The heatmap window is the last ~1,000 scrobbles, not a sliding 30-day or 90-day window — the “shape” of my listening is therefore biased toward whatever cadence I’ve recently been at
- Period changes refetch top-N for that period; the dashboard caches nothing across mounts. A page reload re-fetches everything
Companion tooling
The discovery tool at /music/discover/ sits on top of the same Last.fm history but answers a different question. The dashboard says what’s happening now; discovery says what to play next, given everything that’s happened before.