← Home

Song Bot

I continue my vibe coding escapade with my first bot: a song-of-the-day Telegram bot that automatically sends a tasty track to subscribers every day in time for morning coffee (~07:45 Pacific).

The Curated Song List

Before automating this with a bot, I spent over a year curating these 366 songs for my today page—a revelatory exercise that surfaced my tastes: classic rock and folk-rock from the ’60s-‘80s golden era, plus generous helpings of singer-songwriters, soul/R&B, and live tracks. Christmas music (both sacred and secular) bookends the calendar from early December through early January, confirming what I previously discussed: I do love the season. I aimed for artist diversity (no more than six tracks each) and gravitate toward deep cuts—so if you recognize a hit here, it’s because it’s genuinely great. But as Grandpa was wont to say, de gustibus non est disputandum.

The Process

This was a product of Claude (Sonnet 4.5). Admittedly, it didn’t get everything perfect on the first pass, but it sure took my abrasive feedback in stride. The process wasn’t totally linear, but it went something like this:

  1. Learn about Telegram bots
  2. Set up the bot with @BotFather
  3. Create the initial daily song workflow
  4. Debug some ES module issues1, which took a while
  5. Add self-service subscriptions
  6. Test and fix
  7. Refine (message formatting, etc.)

Failing Telegram workflowsFail, fail, fail, success, fail, fail...

The Setup

Here’s what I ended up with:

  1. Telegram Bot – Created via @BotFather w/ token stored as GitHub secret. Users send /subscribe or /start to join, and /unsubscribe to opt out.
  2. Data Source (_data/daily_song.yml) – My impeccably-curated list of 366 songs2 with date, track title, artist, and YouTube Music song ID.
      - date: "11-20"
        track: "Hello City"
        artist: "Barenaked Ladies"
        songId: "0tGT9rONZPs"
    
  3. GitHub Actions Workflows
  4. Rinse and repeat – Repeats daily, fully automated via GitHub Action with no servers or hosting costs.

Feel free to test it out and then if our musical tastes aren’t matching up, just slip out with an /unsubscribe. And if you’re motivated, you could make your own by cloning these workflows and .yml files from my GitHub repo.

(The today page has the song of the day, too, if you’re more of pull person than a push person.)

bot notification

Bottom line: it’s amazing a non-coder can go from idea to fully functional Telegram bot with auto-subscriptions in one sub-100-message chat session—that there’s some right-fine vibe codin’…at least for the standards of late 2025 (I’m sure it’ll seem quaint in a year or two).

— ᴘ. ᴍ. ʙ.

  1. This is the type of thing that’s over my head and so I’m totally reliant on the LLM to diagnose and fix: Node.js was trying to run our script as an ES Module (basically new JavaScript) (which doesn’t allow require()), but the thing was written in old Javascript (i.e., CommonJS style), so got this error about “require is not defined in ES module scope.” So the fix was renaming the file to .cjs (CommonJS file extension) and wrapped the await in an async function, which told Node: “Hey, this is old-style CommonJS, not modern ES Modules.” 🤓 

  2. Yes, leap year support built in. 

First published: 2025-11-21 | tweet | cast | subscribe

tech music product

← back to all posts