Why do podcast apps suck?⌗
Ok, so this is largely hyperbole. But I did get so irritated with finding a podcast app that did what I want that I ended up writing one.
You can see how that project is going on my github. This post is more an overview of why I made it and what it does.
What should a podcast app do?⌗
Fundamentally, at least in my opinion, a podcast is a book; a series of chapters that should be consumed in order. You should be able to stop, jam in a bookmark, and then pick up exactly where you left off whenever you want.
Apparently making this an easy thing to do is not the primary goal of most podcast apps however. I used to use spotify for my podcasts as it worked pretty well. You could sort the episodes by date and have it ignore played episodes. It pretty much worked for my use case until a recent change to the spotify app that basically threw all the features that made it usable for podcasts out the window.
Well shit, what now?
A journey of disappointment⌗
I figured, someone must have made a podcast app that makes it easy to just listen to stuff in order right? So I embarked on a journey trying every podcast app I could find. My use case was simple: Select a feed and press play. That should be it. Just press play and let it play the episodes, automatically go to the next episode and keep playing until the feed is done.
Nothing did this. There was almost invariably faffing about with adding things to the Queue through some unintuitive interface. I am a simple bean with simple needs, and one of those needs is convenience. So being a naive thembean I figured I’d just make my own…
And here we are⌗
Yapa (Yet Another Podcast App) is my baby. You add a feed and then you tell it to play it. Done. Hit Ctrl+C when you want to pause and it’ll remember where you left off and resume at exactly that point the next time you play that feed/playlist.
The question of how to store feed data was a fun one. Initially I thought of using a docstore, some kind of embedded NoSQL db or maybe just sqlite but in the end I settled on just a plain JSON file. Why? Because JSON in Go is easy. You just tag your structs and then you can serialize/deserialize your data in a quick typesafe way.
Obviously there is one major drawback to this; Yapa reads the entire store into memory when it starts and writes that out to file on data changes. if Yapa is playing a feed and you make a change to the store in a separate terminal that change will be overwritten when the feed starts a new episode because it has to mark the previous episode as played and then write the store. It doesn’t know or care that the store on file has changed in the meantime and I’m not sure that there’s an elegent solution to that. I’m ok with that though. I can just Ctrl+C the player, make changes and then restart it and it’ll pick up exactly where I left off so the inconvenience is minimal.
My primary concern was that adding, searching, and playing feeds be as pain free as possible and I think Yapa does that well enough. You can filter episodes by ID or regular expression, mark them played/unplayed etc… Here’s how it looks:
┌─ nick@fnord │ ~ └─❯ yapa list ID Name Eps Played Last Updated 0 The Cast Die Podcast 30 0 2021-07-11 00:04 1 RQ Early Access Patron Feed 703 23 2021-07-11 00:04 2 D&D is For Nerds 355 61 2021-07-10 14:00 3 VAST Horizon 27 0 2021-07-09 03:59 4 Dark Dice 30 26 2021-07-09 03:59 5 Critical Role 240 107 2021-07-08 12:01 6 The Adventure Zone 197 5 2021-07-08 11:00 7 Dark Air with Terry Carnation 16 7 2021-07-08 08:00 8 Out of Place 16 16 2021-07-06 20:33 9 This Paranormal Life 222 221 2021-07-06 20:29 10 Sweden Rolls 165 6 2021-07-05 20:00 11 Hearty Dice Friends 206 4 2021-07-02 11:47 12 The Hotel 38 0 2021-06-01 06:00 13 Power Word Roll 70 2 2021-01-28 11:00 14 Lake Clarity 26 0 2020-11-17 21:28 15 The Theatre of Tomorrow 50 0 2020-10-26 06:00 16 Swan Dive by the Savage Godlings 22 0 2020-08-04 14:35 ┌─ nick@fnord │ ~ └─❯ yapa list -f4 -e0-5 ID Name Played Pub Date 0 Dark Dice: Episode 0 - The Game Yes 2018-09-25 03:59 1 Dark Dice: Meet the Innskeep Yes 2018-09-29 00:42 2 Chapter 1: The Silent One Yes 2018-11-01 19:44 3 Chapter 2: Mindless Yes 2018-12-04 01:33 4 Dark Dice: Meet the Bard Yes 2018-12-31 21:54 5 Chapter 3: Captive Yes 2019-02-06 04:48 ┌─ nick@fnord │ ~ └─❯ yapa list -f4 -r'^The Long' ID Name Played Pub Date 26 The Long Road: Chapter 1A: Recovery No 2021-02-26 02:54 27 The Long Road: Chapter 1B: Unavenged No 2021-05-12 11:23 28 The Long Road: Chapter 2B: Quartet No 2021-06-25 03:59 ┌─ nick@fnord │ ~ └─❯ yapa list -f4 -r'^The Long' -s'The Long Road' ID Name Played Pub Date 26 The Long Road: Chapter 1A: Recovery No 2021-02-26 02:54 27 The Long Road: Chapter 1B: Unavenged No 2021-05-12 11:23 28 The Long Road: Chapter 2B: Quartet No 2021-06-25 03:59 Playlist saved as 'The Long Road' ┌─ nick@fnord │ ~ └─❯ yapa play -f4 -l'The Long Road' Feed: Dark Dice Playing: The Long Road: Chapter 1A: Recovery Elapsed: 0m 6s
I’d hoped to write it in pure Go to handle the mp3 playing by itself, but I had some weird issues with libraries I tried to use for that so I settled on just running mpv and tracking time/catching signals in a go routine instead.
Since then I’ve added RE2 based filtering for lists to make it easier pull out episodes I want and save them to playlists. I think the playlists management is largely done at this point. I’m open to pull requests if anyone wants to add features but the mission statement of Yapa needs to stay faithful to its intent: Keep it simple.
PS. Oh hai Alex⌗
Here’s a binary build for ARM7 that (should?) run on your pi