I, uhm, built another thing. A few weeks ago, I saw a friend add a song list to his Strava activities, presumably by hand. Music is a big part of my running habit, so that tickled me. It also seemed like a great candidate for a Real Project™ that I could publish online for anyone to use.
Out of those thoughts, and about $50 of AI tokens, came workout-song-log.bouleau.dev.
What it is
The app itself is very simple: Go to the website, sign in with Strava and Spotify1 and then go running with some music in your ears. Once you log an activity on Strava, the app will add any songs that you listened to during the activity to its description. Under the hood, this is using Flask, Postgres, and Redis.
For now, though, there’s a catch: Spotify hasn’t approved my app yet, so you’ll need to send me your username so that I can add you to my app. Try me at [email protected].
Project firsts
- First project using uv for real
- First time using webhooks (!)
- First time offloading background tasks to a Redis worker queue, with scheduling
Ditching Claude Code
I first tried to build this project with Claude Code, but after some false starts I decided to ditch it and use Aider with Gemini 2.5 Pro. I had previously put that model aside due to its initial inability to create properly formatted diffs, but it looks like the Aider folks fixed that. I only have good things to say about this tool + model combination.
I’ve given up on one-shotting anything that isn’t a landing page
This is actually the second incarnation of this app. I first tried to one-shot the whole project with Gemini 2.5 Pro Exp. It did NOT work out well. I’m sure I could have made it work with more prep work and context management, but I’ve found that applying an agile methodology to vibe coding works better for projects like this.
On the second try, I worked as I would if I coded it myself (duh): Starting with simple single-user script, then introducing a database for state keeping, then a simple UI with Flask, then multiple users, then moving some code into scheduled workers, then re-building the frontend.
Gemini 2.5 can do impressive things with screenshots
This was the biggest aha moment of this build. I was running into some styling issues in the frontend, and I realized that if I…
- Take a screenshot of the problem and put it in the clipboard (pro tip for Mac users: hold
ctrl
when taking a screenshot to put it in the clipboard instead of disk) - Pass it to Aider using
/paste
- Prompt Gemini to “fix this”. No other context. …it usually does really well! Most of the times I did this, it successfully spotted the problem and fixed it.
Spotify API nits
The /me/player/recently-played endpoint of Spotify’s API only reports recently played tracks that were not skipped at all. I assumed that tracks with a very short playtime would be excluded, but it’s worse than that: If I press Skip 10 seconds before a song ends, it never ends up in the API output. Annoyingly, it seems like the internal APIs do show those tracks since they show up in the desktop app’s Recently Played list.
The API is also locked to only whitelisted accounts until I get an approval from Spotify. Unlike Strava’s developer program process which only took me a few days, this one seems pretty grim: Some folks on Reddit are saying that it took them 6 months to be approved for a hobby project.
Open sourcing the code
I hope to put this project on GitHub soon. Watch this space and thanks for reading!
-
Full disclosure: I worked at Spotify for a long time. I left in 2023, and it goes without saying that this is a personal project that has no official endorsement from them. ↩︎