I Made a Podcast Player — defn.io

I made a podcast player for iOS. It’s called Podcatcher and
it’s live on the iOS App Store! As with most
things I’ve made in the past several years, it’s
implemented using a combination of Racket and Swift. This
approach continues to be a very fun and productive way for me to
write apps, and working on these projects has allowed me to refine
it further. For example, I’ve recently added async support to Noise
and made it compliant with Swift Concurrency while maintaining
backwards-compatibility with the existing implementation based on
Futures.

Why a podcast player? Because I listen to podcasts a lot (like a lot,
a lot, a hundred hours a month a lot) and the podcast player I used
to use recently made some changes I didn’t like, so I decided to make
an app suited to my liking and listening style. As you might expect
from a modern podcast player, it’s got audio enhancements like an
equalizer that boosts voices, silence trimming, variable speed with
pitch adjustment, and a “shower mode” that boosts voices further,
trading quality for loudness when you need it. It’s also free, has no
ads or tracking, and it’s local-first except for the podcast directory
and sync. There is a backend component that ingests podcast feeds
periodically and sends push notifications to the app to update its local
database when new episodes get released.

Compared to some of the other apps, cross-device sync via iCloud is
maybe the main thing that is currently missing, and the UI is less
fancy/custom, but that’s what I prefer anyway. In a future release, I
plan to add a sleep timer, support for favorites & bookmarks and a watch
companion app. I’m also open to suggestions, so let me know what you
think if you give it a try!

On the Racket and OSS side of things, the following changes directly
resulted from my work on the app, either because they were needed to
make the project work at all (i.e. some of the build changes, and the
work to support OpenSSL) or because working on the app exposed certain
problems (i.e. the performance issue with the XML library, and the
redirect issue in http-easy).

Plus, the changes to Noise I mentioned earlier. I am
still debating whether or not I want to make the app itself source
available, like I’ve done for Franz and Remember. Maybe if there’s
interest.

In terms of lines of code per language, the app looks like this:

-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
Swift                           68            621             25           6392
Racket                          73            590             42           4965
-------------------------------------------------------------------------------
SUM:                           141           1211             67          11357
-------------------------------------------------------------------------------

The Racket numbers include the API component, which is about 1800 lines
of code on its own, but the Racket code is a lot more dense than the
Swift code, which has only one external library dependency, compared to
the Racket core which has several:

  • actor-lib
  • binfmt-lib
  • buid-lib
  • db-lib
  • define-query-lib
  • deta-lib
  • html-lib
  • http-easy-lib
  • monocle-lib
  • noise-serde-lib
  • north
  • sentry-lib
  • struct-define
  • threading-lib

The Swift part also includes about 1.5k lines of code representing
structs and ser/de code generated by Noise.

Leave a Reply