Automatic Podcast Converter and Publisher

At my local church, Hoboken Grace, we record the pastor’s conversation each week using a digital recorder that writes an uncompressed WAV file to an SD card. The way we used to do the podcast is someone (whoever was willing on any given week) would take the SD card home, convert it to MP3 using whichever means they found appropriate, upload it to our WordPress site, create a new post for it, and then associate the uploaded MP3 with the post. While each of these steps are relatively simple, it is an unwieldy task for a non-technical user. What’s more is that the MP3 conversion was all over the place – some of the guys would use Audacity, others would use GarageBand, and with all different settings. This resulted in files of different qualities and vastly different file sizes which just made it confusing for those listening or downloading.

I decided it was time to solve the problem, and that’s when the Hoboken Grace Podcaster was born. Because all of the computers we have at church are Mac, I decided to code it using the Cocoa framework, which is the main development platform for Mac OS X. What I basically did was create a very simple wizard-like GUI that should be easy to use even for someone unfamiliar with our underlying WordPress setup.

The opening screen looks like this, and all the user has to do is browse to the WAV file on their computer. They can optionally also choose a JPG image to use as album art in the MP3 (this is the picture that shows up for the podcast in iTunes), but if they don’t, the default will be used, which in this case is the logo for Hoboken Grace.

Convert Audio Step

After clicking the Continue button, the conversion process commences. Our usual podcasts are around 45 minutes to an hour, and these take approximately two minutes to convert. The backend conversion is performed using LAME, with the command-line options “-V8 –vbr-new -q0 -B128 –lowpass 11.6 –resample 22 –ti default.jpg”, which I found works very well for voice recordings like podcasts. It results in an MP3 file of approximately 8MB for every hour which is pretty good compression! When the process is finished, the user is brought to the second step.

Publish Step

After the user types in the title and description (or content, in WordPress parlance), pressing the Continue button will cause the MP3 file to be uploaded, a new post created, and the two linked together in order to complete the podcast setup. All of the heavy lifting for this is done by WordPress itself; I am just sending it commands via the Powerpress plug-in which sets up an enclosure in the custom fields in order to power the podcast RSS/iTunes feeds). I am actually doing all of the XML-RPC client stuff in a PHP script which I am then calling using Cocoa – the same way I call LAME to do the audio conversion. There are some XML-RPC interfaces for Cocoa, and I did get one of them to work, but it was just a lot of code and dependencies that I didn’t want my project to have.

I should take a quick detour here to describe the agonizing experience I had when initially working with XML-RPC. It truly is a very simple process to interface with it, which I suppose shows the validity of service oriented architecture as a paradigm. But when I had first started testing some API calls, I kept getting this nasty error: “transport error – HTTP status code was not 200”. A quick Google search turned into about two hours of research and hair-pulling, with no results. People had posted fixes, but none of them applied to my scenario. I had to sleep on it before I realized that I should see where the error was being printed (in the wp-includes/class-IXR.php file, which incidentally is what I was using as my XML-RPC client). I then modified the area around the error to print out more useful messages – it turns out the transport error is just something that is printed when one function call returns false. It doesn’t matter why it returns false, it just always prints the same message. What I eventually discovered is that the real error message was caused because instead of getting HTTP status 200 (which means OK – it’s a good thing), I was getting 301, which is the code for “Moved Permanently”. I initially thought this was something to do with the server configuration, but then after some reading I found out that every time a server returns 301, they also give a URL which is where you should be going. I tweaked the client-IXR file further until I finally printed out the right URL and realized my problem – I had left out www. in the URL for the WordPress site. It turns out that on most sites, when you omit www., the server automatically issues a 301 that tacks on the missing prefix, all of which your browser does behind the scenes without telling you, which is why I didn’t realize what was happening. I couldn’t believe how simple the problem was considering all the hours I spend finding it, but I feel like it often times is something quite simple.

The good thing is that after I found this problem, it was relatively smooth sailing. I had another frustrating problem later that was a result of me passing an NSNumber as an argument when calling my PHP script. It turns out that all arguments must be NSString’s. The error I got for this problem was “unrecognized selector sent to instance”. I believe these two problems I ran into would have been diagnosed, understood, and fixed in much shorter time if the error messages had been more descriptive. Consider this a +1 in favor of spending the extra time to construct meaningful error messages. (Ironically, as I say that, I’m thinking of all the obscenely arcane messages that could be printed by this very program I’ve written, since I’m directly showing errors from the IXR class. Oh, well.)

After the publishing process is complete, the user is presented with a Finished screen that allows them to quit the program. The third screen doesn’t have any functionality, just a message, so I’ll omit it. With that said, this program is basically made up of two very simple screens that do everything necessary to get a new episode from WAV format to published on the internet and available in iTunes. Not bad for two day’s work. The XML-RPC interface is really the staple of this whole project. That, and NSTask, which makes it easy to call other programs from Cocoa. In that sense, Cocoa was really just used in the GUI development, which in my opinion is where it belongs. That’s not to say I couldn’t have made the whole app in native Cocoa code, but who wants to reinvent the wheel when LAME and a simple PHP script can do everything so nicely?

Since the program is so specific to our setup at Hoboken Grace, I don’t see any point in including an executable download. However, a lot of what I’ve done here can be reused by anyone who is looking to create a similar interface for their own WordPress-based podcast. Therefore, I will link the source code at the end of this post. If anyone wants to use it, they’ll probably have to do a lot of modifications, but then the basic procedure is to build the program using XCode and then drop the resulting .app bundle into the /Required subdirectory, since that is what contains the lame executable and the PHP scripts necessary for everything to run. xmlrpc.php is what you will probably have to modify the most, since it does the specific tasks of uploading a file and making a new WordPress post with the Powerpress-specific custom fields. If anyone does decide to use this code as a starting point, don’t hesitate to contact me if you don’t understand how something works. All the IPC and RPC may be a little confusing – almost to the point where it warrants a diagram 🙂

You can download the source code here.

EDIT: I also ported the code to C#.net since some of the people at church were using Windows-based machines. For anyone interested in that source code, you can download it by clicking here.