On Worst Case Scenario, the podcast I host with Baz Taylor and Dave Sims, we use a WordPress plugin called Seriously Simple Podcasting to host our podcast feed. It’s a fantastic minimalist plugin with little bloat and works very well for us.
We also installed an add-on called Seriously Simple Stats which would give us download counts for each episode of the podcast.
However the plugin wasn’t showing the client information properly and this was annoying Dave.
The three of us poked at it at various points during the day, and despite not being WordPress experts (and in my case, being very far from a PHP expert), we managed to get it working.
Podcast app User agent Strings
Here are some user agent strings reported by one or two podcast apps:
- “AppleCoreMedia/1.0.0.13F69 (iPhone; U; CPU OS 9_3_2 like Mac OS X; en_ie)” – native iOS podcast app, amongst other things
- “Pocket Casts” a podcast app that is particularly popular on Android
- “Overcast/1.0 Podcast Sync (x subscribers; feed-id=y; +http://overcast.fm/)” – from Marco Arment’s Overcast app, which helpfully tells you how many subscribers you have in the agent string
- “iTunes/12.4.2 (Macintosh; OS X 10.11.5) AppleWebKit/601.6.17” – downloads from the Mac version of iTunes
Here’s the bit of the plugin that detects what client you’re using
if ( stripos( 'itunes', $user_agent ) !== false ) {
$referrer = 'itunes';
Hm. There was no entry for AppleCoreMediaPlayer, which was why downloads from the native podcast app were being detected as ‘Other’. But we tried downloading episodes from iTunes on the Mac and that was still recorded as Other.
In fact, apart from plays from the website, every client was being recorded as ‘Other’ – except for Pocket Casts. What was going on?
When your needle and your haystack are the same size
The stripos($haystack, $needle) function in PHP looks to see if a string $needle is in the string $haystack, if it is, it returns an integer with the position of $needle in $haystack, otherwise it returns false.
Absentmindedly, I typed ‘php’ in a mac terminal expecting to get an error, but instead getting a blank prompt, indicating I could type PHP code enclosed in <?php ?> and hit ctrl-D to make it run (why does OS X ship with PHP? I have no idea). I tried a smaller test case:
Those of you reading probably have the aha! moment by now, but it took a bit of probing from Baz before I got it:
And that was also the reason why Pocket Casts was showing up correctly – because the entirety of the user agent string is “Pocket Casts”! Anyhow, changing the function around to read
if ( stripos( $user_agent , 'itunes' ) !== false ) {
$referrer = 'itunes';
Double hits from the iOS podcasts app
We then hit another problem:
Turns out any downloads from the iOS Podcasts app were being counted twice. It seems like Podcasts first sends a HEAD request for the mp3 file, presumably to get size information so it can populate the progress indicator, with the user agent “Podcasts/2.4”. The app then sends a normal GET request for the mp3 file with the AppleCoreMedia user agent mentioned earlier.
Being lazy I just added a return statement if we detected the Podcasts user agent:
if(stripos( $user_agent,'podcasts/' ) !== false ) {
return;
}
I submitted it as a pull request and the maintainer merged it within a few hours. It was fun chatting away with Baz and Dave on iMessage while we tried to fix it.