Products BeaconMCPs
Company About Blog
Appearance

Renaming the Last.fm tile

Beacon used to have a Last.fm tile. It now has a Now Playing tile with ListenBrainz as a second source, and the rename was the move worth writing about.

Beacon's Last.fm tile is now a Now Playing tile, and it supports either Last.fm or ListenBrainz. Both APIs return the same structure (a track, an artist, an album, cover art, and a flag for "is this playing now or just last played"), so the render half of the tile is identical; only the fetch-and-normalize step branches on which service the user picked.

Internally, the widget's kind went from "lastfm" to "now-playing", and a new source field carries the actual service — lastfm or listenbrainz. The widget's kind and its data source are separate fields now, where they used to be one.

That separation matters for the third source that doesn't exist yet: Spotify via a worker, a generic JSON endpoint, whatever. That future addition becomes a new value of source, not a new widget, and the migration to support it is already written.

The migration itself was zero-touch: any existing widget with a Last.fm API key and no source field defaults to source: "lastfm" on next load. Users who set up the old Last.fm tile six months ago see their tile still working, just with a slightly different label in the builder.

ListenBrainz is the open alternative, run by the MetaBrainz Foundation. Unlike Last.fm, Beacon can pull its data in without an API key or OAuth dance. The ListenBrainz project refreshingly requires a username only, has public read endpoints, and requires no credentials stored on disk. It's actually a cleaner fit for Beacon's static page construction (no worker, no server-side secrets) than any auth-gated service, and a reasonable place to invest the second-source slot.

The Last.fm-only version of the tile was always a proof of concept. I shipped it knowing the widget needed to grow into other sources: ListenBrainz first, then probably Spotify via worker, maybe Apple Music at another future point, and then a generic endpoint someday. The rename happened on the schedule I'd planned for it, before the third source could force my hand.