Don't turn it loose
cuz it's a mother - James Brown
A lot of backend adjustment was required to support some new app features. Here they be!
Sharing Backend
Kapell’s backend “sharing” /l/ tooling — which powers link sharing for links to
James Brown (on Kapell) — has been expanded to support new targets within Kapell’s client: sets and searches.
Classical Works
I don’t know a lot about classical music, but I know that Beethoven’s Fifth is a “work” that many others have performed. This is a first-class concept in MusicBrainz, but in Apple Music you can’t go to just the work and find all the performances of it.
Apple’s music feed doesn’t report anything related to classical movements, etc so instead I’ve built up Kapell’s backend to have a MusicBrainz work node and connected it to the many performances of (for example) Beethoven’s Fifth. This powers some new classical features in the app, letting you find the ones in Apple’s catalog.
This maps around 220,000 performances across 188,000 albums, about 138,000 of them complete.
Artists By Genre
Apple’s artist feed carries no genres, so Kapell now decides its own primary artist genres: the genres on at least half of an artist’s release groups, plus their most common one. This took a few iterations to do cleanly, tweaking the criteria that control which genres an artist gets.
Additionally, the catalog index behind genres can now be entered by Apple artist: an artist’s albums and songs, either as the primary artist or as appears on. Appears on is deliberately narrow, counting only album-level featured artists, which is how Apple’s own “Appears On” view behaves. Set search also takes several album types at once, so “Singles & EPs” is one query rather than two. This gives us a lot of flexibility for search views (and faceting) in the app.
Artist Resolution
Some artists exist in MusicBrainz but I can’t confidently tie them to an Apple artist. Artist search can now include those, and where there’s a near-miss match with agreeing names the graph offers a probableAppleId. It’s presentation-only; nothing joins on it. That covers 27,448 artists today. I tried some other approaches but I wasn’t comfortable with the accuracy, so this stays.
There’s also another round of the artist-matching guards from the last platform post: performers were still occasionally resolving to a same-named composer from before recorded music was common (the cutoff moved from 1900 to 1960), and band members to their bandmates.
Housekeeping
- Indexes. An audit found about 1 GB of GIN indexes that no query could use, since every reader looked those rows up by key anyway. They were also rebuilt every day. Cleaned that!
- Rate limiting moved from the web server into the API itself, per client IP, ahead of key lookup. Same limits as before, better telemetry and I no longer have to maintain a weird Caddy build.
The Website
Not API, but platform-adjacent: every page on this site now has a Markdown twin next to it, and there’s an /llms.txt index, so agents can read the docs and blog without scraping HTML. There’s also a press page with a fact sheet, descriptions and screenshots for anyone writing about Kapell.