Skip to content

v1.6.5

Choose a tag to compare

@MichelleFindlay MichelleFindlay released this 26 Sep 15:53
· 16 commits to main since this release
ddf7008

New features

  • MCP server (mcp.php) — expose this account's data as tools an MCP-compatible AI client (Claude, ChatGPT/OpenAI, or anything else speaking the standard) can call: get_now_playing, list_scrobbles (individual listening history with exact dates/times), top_artists, top_tracks, genre_breakdown, lifetime_stats, and one widget_* tool per insight widget. Gated behind a bearer API key (mcp_api_key in config.php, blank/disabled by default). Falls back honestly — "available": false plus current backfill coverage — rather than fabricating data when the local history doesn't reach far enough back yet.
  • Local library sync — cron.php now builds a compressed local snapshot of your full scrobble history (artist + track + timestamp), paced in bounded batches across runs. Once a period is covered, Favourite Tracks/Trending/Genre Breakdown compute from it directly with exact calendar boundaries (real Jan 1, real 1st-of-month, real Monday) instead of Last.fm's approximate rolling windows, and with zero live API calls.
  • Genre Breakdown, rebuilt: once local history covers a period, it scores every distinct artist scrobbled (not a capped sample) with no "Other" catch-all. Optionally filtered down to Spotify's own genre vocabulary when Spotify credentials are configured, collapsing near-duplicate spellings (Rnb/R&B, Dnb/Drum N Bass/Drum & Bass) onto one entry. A "Show: all / above 1% / 2% / 5%" dropdown keeps a long genre list from making the page too tall.
  • Before They Were Famous, verified — each candidate is checked against Spotify's own artist search before inclusion, filtering out soundtrack/compilation scrobbles where the "artist" is really an album or production title (e.g. "Monster High the Movie"). Both this widget and Obscurity Index also now filter out multi-artist scrobble credits ("Artist A, Artist B & Artist C"), which Last.fm otherwise treats as one low-listener "artist".
  • Distance Listened — each comparison now shows a progress bar for the fractional remainder (e.g. "~74 flights, 64%") instead of a bare decimal.
  • BPM Average — the plain pulsing dot is now an animated ECG-style heart-monitor trace, scrolling at the real average-BPM's beat interval.
  • YouTube quota protection — a local 24-hour call counter (youtube_daily_limit, default 100) so quick-listen lookups can't exceed the free API quota.

Fixes

  • ListenLinks caching bug: a failed Spotify/YouTube request (auth hiccup, network error) was being cached as a permanent "no match" for 30 days — indistinguishable from a genuine miss. Now only a completed API response gets cached, so a transient failure retries fresh next time instead of freezing a track's button on "Search" for a month.

Architecture

  • Genre tag scoring and Spotify's Client Credentials auth are now shared, reusable pieces (lib/Spotify.php), used by both quick-listen links and the new artist/genre verification.
  • LibrarySync's artist/track query methods are now public with an optional upper time bound, plus new rawScrobbles()/coverage() methods for arbitrary date-range queries — the foundation the MCP server's list_scrobbles tool is built on.
  • Genre tag coverage (for the uncapped local Genre Breakdown) and scrobble history backfill both grow via their own paced background jobs in cron.php, never a live lookup burst.

Documentation

  • README additions: Local library sync, Genre verification (including an honest note that Spotify's genre vocabulary is a fixed, dated list since Spotify retired the live endpoint), and a full MCP server section with step-by-step connection instructions for the Claude app, Claude Code, the OpenAI API, and ChatGPT's current OAuth-only limitation.