I’ve been thinking about adding last.fm integration to my site for a while now, but I’ve never been able to fit it with the style. It’s really just not a great thing for my website, because most of my online “personality” is on bsky,1 so I decided to put it on my bsky profile.
In the first iteration, I polled the last.fm API every 90 seconds with pylast, and updated the bio with the data I got from that. This solution was fine but something about it grossed me out2. It’s by far the least optimal way this could’ve been implemented and I simply could not let it stand.
In the next (and current) iteration, I decided to replace the last.fm monitoring with a simple webhook that would trigger from my phone whenever the song I was playing changed. To implement this, I decided to write a tiny flask server that would accept a post request with an API key (because I have this webhook exposed to the internet), artist name and track title.
@app.route('/now_playing', methods=['POST'])
def lastfm_endpoint():
provided_api_key = request.args.get('api_key')
if provided_api_key == api_key:
artist = request.args.get('artist')
track = request.args.get('track')
update_track(artist, track)
return "Success", 200
else:
return "Unauthorized", 401
That flask server calls the update_track function, which passes formats the data into “{artist} - {track}” and updates my bio with it using the atproto python library.
I have the whole thing sitting on my server, running at about 231 MiB RAM usage, so you could run this just about anywhere for cheap/free (or rewrite it in a more performant language).
To actually get the data from my phone to the webhook, I use MacroDroid. I looked in to Tasker and Automate, but they were too complex for what I needed. I have a simple macro that, when my media changes, checks if it’s from one of the apps that I scrobble from with Pano Scrobbler, and if so sends the track to my webhook.


You can see it in action here, and the source here.
-
See dame’s account for a really good example ↩