I don't know if this is a good place for feature requests, but the only thing keeping me from switching to this at at the moment is download settings per podcast.
For example, some podcasts I don't want to miss an episode and I want them all downloaded. Other podcasts I only check in on occasionally and would only want the latest episode to be kept on device.
I subscribe to a lot of podcast and downloading and keeping every episode is going to eat up a lot of storage.
Besides that, love the simplicity of it. Well done!
Thanks! That makes a lot of sense. It actually only downloads at most 2 episodes per podcast at a time, but that's still not great for your use case. I do plan to add per-podcast settings in probably the release after next, so stay tuned for that!
I have the same requirements but started to think these use cases might be different enough to warrant different apps. So I’ve gradually shifted to those “don’t miss” ones in a dedicated podcast app and the occasional ones to Spotify. Could probably do with another app for the tiny daily ones too..
I've considered the multiple apps to manage content consumption but it's such an inelegant solution I've been unwilling to try it.
I want to be able to categorize content. I want a category of podcast to work to, work out to, go to sleep to, or to simply sit a learn. I want different categories of music. I want to be able to set a group of content on YouTube that I will watch everything on, and one that I can sort through and pick the few videos I want to watch.
Given the value of that data in just my sorting and prioritizing of content, I don't know why I don't have the tools so that data can be harvested and sold.
I don't see anything being demanded. I have several open source projects used by other people. I don't implement every requested feature, but requests are a great way to get ideas I might never have had on my own.
If a developer wants money for every feature, they're free to use a commercial license and accept the tradeoffs.
Demand or request – what gives somebody the right to make a request without offering anything in return? Most people here wouldn't walk around in the street asking strangers for a handout, or ask for free stuff in shops and restaurants. So why is it okay to make these requests without offering even token compensation?
I have made feature requests from open source project, and always with a monetary offer attached. If everybody who wants a feature pitches in a little, then the creator will be compensated fairly if he chooses to implement that feature.
I can recommend reading "The Cathedral and the Bazaar" if you're interested in learning more about the philosophical and economic underpinnings that existed in the early days of open source, which still largely hold true today.
Person 1: I have built this thing, maybe somebody finds it useful. Then you can have it for free.
Person 2: I'm not going to use it unless you do as I say with your thing, and I'm not going to offer anything for you.
Well okay, then don't use it? Or if you want a feature, offer something in return. Or make the request towards a paid service – their ears are very eager to hear what features potential customers would like to have.
You have a cynical view of what is a feature of Show HN posts: community feedback. This is where the rubber meets the road and where you find out if people would use your project. And part of that is people telling you why they wouldn't use it.
The best case scenario really is that the only thing keeping someone from using your project is a feature that you can implement that would make your project better for everyone. For the sake of launching, you tend to pick a subset of features that you consider necessary, and it's good feedback when all you need to do is extend the circle to include a few more.
I think your negative reaction is warranted for when people trash the project, especially under the weak guise of constructive criticism. But feature feedback is not that.
The OP himself liked the feature request which is perhaps a counterpoint to your interpretation. I don't think they would agree with you that it was inappropriate nor demanding, but rather useful feedback.
One of the problems with open source hobby projects as opposed to projects you do for a job is the lack of feedback. If I ever were motivated to do an open source project to scratch an itch, I would want feedback and feature requests to make it better
"Boost voices" is a cool feature a lot of apps have, but what is really needed is a "compress voices" feature. So many podcasters speak loudly 75% of the time, but then trail off randomly or almost whisper. Then you turn it up and they're projecting loudly again and blow your ears out. It's especially annoying in the car trying to compete with road noise.
Sure! I have a whole library dedicated to integrating Racket and Swift and you can find some of the nitty-gritty details there[1]. The gist of it is:
1. You build Racket for iOS in an interpreted mode (regular Racket works a bit like a JIT in that it needs to load code into memory at runtime, which is a no-go on iOS)
2. You link to it as a regular static library.
3. You call Racket's C API[2] to load and run Racket code.
Here's[3] a somewhat outdated video I did a while back on using that library for Mac app development. Many of the things in this video are now much simpler/more straightforward, but maybe it serves to give you an idea. I also have some source-available Mac apps built this way that you can take a look at[4, 5].
I support a number of podcast creators on Patreon, and apparently they’ll (at some stage) allow creators to have multiple RSS feeds. Until then, I’d love to be able to regex match on titles for download. This one creator I follow has about 6-7 different shows on the same feed, but I only listen to 2 of them.
I’ve been a Pocket Casts users since I can remember. I’ll +1 the CarPlay support that you mention was already on your list. The other, which they’ve recently introduced, is to disable Lock Screen scrubbing. Been a life saver!
Looks great though! I’ll keep an eye on the change long as it evolves.
> The other, which they’ve recently introduced, is to disable Lock Screen scrubbing
I was so happy I happened to read through their recent changelog and caught that. WAY too many times I accidentally swiped along the scrub bar and put myself at a random place in a 4 hour podcast episode and had to spend 5 minutes trying to figure out where I was.
Thanks! I used Pixelmator Pro to put the images together. I just made one long image that I cropped at the end into the screenshots you see on the App Store. For the iPhone templates, I think I exported a template from Sketch, but I later found out that Pixelmator also has them (you can find them under the Mockups category in the New dialog).
The app store labels are somewhat broad, but that refers to the error tracking that the app does. When an unhandled exception occurs in the app, that error is sent to Sentry.
Yeah, that is plainly not “no tracking”. Developers are not entitled to the events that occur on devices that belong to me unless they obtain my permission for such surveillance first.
I will never understand why developers believe that they are entitled to information from devices that they do not own.
A botched deploy that I didn't notice ended up crashing the server, which then failed to recover when the systemd unit tried to restart it (it couldn't bind the port and ran out of retries quickly) overnight, so that's why that was failing. It's back up now and I'll put a fix in today.
The app looks really good! Based on the title I thought it’d be something you made most as a testbed for Racket so I was surprised to see the app itself actually looks great :D
I tried looking through your blog but couldn’t find anything except the 40 minute YouTube video for your other app. It sounds like both the UI and the audio-related code are in Swift? What code ends up actually being in Racket then?
That's right, the UI and the Audio Engine bits are in Swift, because it's easier to interface with those Frameworks directly from Swift (and not fight the platform). Everything else (the Database management & the models, the download manager, ID3 parsing, parsing release notes, syncing with the backend server, etc.) is implemented in Racket and is portable.
> Database management
> syncing with the backend server
Do features like these, when implemented in Racket, consume more resources (battery, CPU, etc.) than if they were implemented using the native API equivalents (e.g., NSURLSession or whichever is more applicable)?
In the larger context of cross-platform apps with a common core written in a non-native programming stack, I often wonder this about network and disk I/O management. I understand using the native APIs for other "I/O" like UI, hardware interfaces (bluetooth, accelerometer, etc.), because they often don't have an
equivalent API in the programming stack used to implement the common core.
As far as I know, Capacitor wraps over the native APIs.
Ultimately, you end up calling some system API for I/O, so the only difference is how efficient the implementations of those Frameworks are compared to the embedded language's implementations. On iOS, embedding Racket requires using an interpreted mode (as opposed to Racket's usual native compilation mode), so there is a small hit, but it's not one that is really noticeable in battery or CPU consumption. In fact, Podcatcher seems to do better in battery consumption compared to the competition in my (and my friend's) testing, but I would guess that's not necessarily _because_ of Racket; it probably has more to do with how the system as a whole pays attention to perf.
That makes sense. Do you keep the in-memory data in Racket data structures? I imagine keeping the data fed to Swift UI in sync with data maintained by GC'd Racket would involve some work.
Yes, the app uses Noise under the hood, and the way to think about it is a request-response model[1]. Swift makes an async request to the Racket backend, it constructs some data (either by querying SQLite, or making a request to the backend, etc.) and returns a response. If it doesn't retain any of the data, then it gets GC'd. The ser/de is relatively low overhead -- if you try the app and go to Settings -> Support and take a look at the logs after using it a little, that should give you an idea of how long the requests take. The lines that start with `#` refer to Swift->Racket RPCs. Here's an example from my logs:
Some things on the Racket side are long running, like the download manager. It's like an actor that keeps track of what's being downloaded and the progress of each download. Whenever a download makes progress, it notifies the Swift side by making a callback from Racket->Swift. In this example, there is some duplication since both the Swift and Racket sides each have a view of the same data, but it's negligible.
What's not as great from a memory use perspective is how large Racket's baseline memory use is. Loading the Racket runtime and all the app code takes up about 180MB of RAM, but then anything the app does is marginal on top of that (unless there's a bug, of course).
[1]: I did this precisely because, as you say, keeping keeping data in sync in memory between the two languages would be very hard, especially since the Racket GC is allowed to move values in memory. A value you grab at t0 might no longer be available at t1 if the Racket VM was given a chance to run between t0 and t1, so it's better to just let Racket run in its own thread and communicate with it via pipes. Probably, the same would be true for OCaml.
- Both sides pass messages to each other. Both of them talk through C ABI. My model was synchronous though. Async is certainly better.
- I used the protobuf binary protocol for message passing. Faster and probably more efficient than, say, JSON. But both sides may have copies of the same data for this reason.
I've written down my approach, which roughly aligns with yours, in the project's README.
What I wanted to do was for OCaml side to allocate data in memory, and for Swift to access the same memory through some commonly agreed upon protocol (protobuf itself maybe?). But I haven't yet explored how difficult this could be with GC coming in play. I think OCaml does have a few tricks to tell GC to not collect objects being shared through C ABI (https://ocaml.org/manual/5.3/intfc.html#s:c-gc-harmony), but I haven't looked into this enough to be sure.
Your projects will sure help me figure out the concepts!
Nice! Yeah, using protobufs seems reasonable. Re. GC, Racket has support for "freezing" values in place to prevent the GC from moving them, but freezing too many values can impact the GC's operation so I'd watch out for that if that's possible in OCaml.
Looks cool! If I may, a couple of feature suggestions:
1. You mentioned it already but bookmarks. In particular bookmarks that can be added through iOS Shortcuts (so we can each build whatever crazy automation we need) and that can be exported (so we can keep LARPing productivity in our Obsidian vaults).
2. An "undo" function, somehow. I know this is weird but I've misclicked the seek bar so many times (esp. in the lock screen) and lost where I was... a solution for that would be so cool.
I've been using the same podcasts app for... well over 10 years. But yours looks really cool, I may just switch.
Noted! There is already an undo function, though. If you seek, an undo button pops up. Also, if you go to settings, there's a "History" view where you can also undo from.
satoshis, derivative of bitcoin I think? I have a poor understanding of it. Essentially it's a way to pay podcast producers directly. Streaming means it sends whatever you set per minute so you auto-support podcasts. Boosts are short messages with dollar values tied to it. The show has to support this though, not all podcasts do.
Yeah, based on Bitcoin lightning (which is quite different from normal bitcoin) meaning no transaction costs and very low energy use. Basically it happens off-chain until someone syncs-up (then it becomes a btc transaction). It makes payments in fractions of cents possible, ie I stream 10 sats/min which is about 60 Eur cent per minute (so 1 cent per second).
You can also send messages to creators and attach amounts (those are called boosts), so you'd send a short message and attach 10k sats (or whatever you want), which is about 10 euros/dollars.
Some podcasts I listen to use this to read messages on the show (the highest ones). It's fun and casual but remains highly technical for now, https://getalby.com/ takes away some friction (but you're still self hosing a lightning wallet using docker compose). Easiest I think is Fountain [0, 1], which has it all built in. But I never tried that, I use Castamatic [2] with Alby.
I have to say, it seems to divide the Linux podcast world a bit with some shows embracing this, and some just calling it crypto-bs. A well, people seem to enjoy it and creators get real value, enough to have to rely less on ads even. I think this is one of the babies we'd throw out if we banned crypto currencies (which I agree are 99.999% bs).
I will definitely check it out. I've never done iOS development but I have been considering doing this very thing as a way to learn and to give myself the podcast player I really want. :) Good luck!
Can it handle feeds that aren't available on the public internet?
I have a personal feed that I can connect to over TailScale. But I've found that most podcast clients have a server-side component, which means their backend server must be able to access the feed.
I tried adding my private feed to Podcatcher and am getting "Server Error (500)".
Yup, unfortunately Podcatcher works the same way and that explains why you'd be getting that error, since the server can't access your feed. That's certainly something that it could support though, but you would obviously not get any push notifications for that feed.
Thanks for the feedback. Subscribing in particular is slow, especially for podcasts with lots of episodes, because it tries to save all the episode metadata locally, to avoid roundtripping later. So, it’s slow initially so it can be fast later and work offline, but I understand how that can be annoying!
I did not use this app yet, but I want to share my issue with the current native podcast player in iOS.
Some podcasts are news related and require hearing the latest episode. Other podcasts are more serial like history narrations and require hearing the series in the order it appears. Download options should be reflective of these two functions. And "play next" should also be reflective of these two functions.
Some podcasts have fast speakers and need to be slowed down. Other podcasts have slow speakers and need to be sped up. The speed setting should be saved per podcast.
New View: A play next queue list should be present. Swipe right to play. Swipe left for other options
Condensed View: Upon expanding an episode, swipe left to see other episodes in the list ordered by date based on preference. Scroll down to see options for the episode. Scroll up to see other episodes in Queue.
Native iOS podcast player allows to customize per-podcast episode order (newest first/oldest first)
I guess playback speed is a global playback property though.
For example, some podcasts I don't want to miss an episode and I want them all downloaded. Other podcasts I only check in on occasionally and would only want the latest episode to be kept on device.
I subscribe to a lot of podcast and downloading and keeping every episode is going to eat up a lot of storage.
Besides that, love the simplicity of it. Well done!
reply