26 Jul 2020

iTunes Playlist to MP3 CD

Using some hacked together script to find a way to go from an iTunes playlist to an MP3 CD. All part of getting some more life out of an old car head unit.

Posts on this blog are perhaps getting increasingly niche, but for a handful of people on the internet this post may be a dream come true. I would have been grateful for a script before writing this at least!

Backstory

After 5 years of driving a mk1 A3 (affectionately known as ‘raudi’), I’ve upgraded to a mk2 A3. We are talking 2002 to 2008 models, so I’m still 12 years off the latest pace at the time of typing! The old car had a super basic CD player which I swapped for some Kenwood CD/Bluetooth/USB-supporting head unit. It was the first change I made and worked fine for years. I was going to do the same for the new car however I’m thinking that the stock unit is a better choice. It’s one of these:

Audi Symphony CD Player

Whilst it doesn’t have Bluetooth or USB support, it does have native support for MP3 CDs. Plus as it’s the factory unit it also has useful car integration, i.e. the song title shows on the display by the speedometer and the controls on the steering wheel change the track/volume as required.

First things first, I tried a disc with some different formats and only the MP3s played. That’s pretty inconvenient as my music collection seems to be a mix of formats.

$ find . | grep  -o '\....$' | sort | uniq -c | sort -rn
2952 .mp3
2093 .m4a
1516 .itc
 245 .jpg

JPG and ITC we can ignore, although I had to google ITC to double check it wasn’t audio (it’s not, it’s some iTunes artwork format). So we are working with a mix of MP3 and M4A.

By accident more than design my music collection is split between iTunes and Google Play Music. Google has an app to keep these things in sync (including playlists) and this works well. That means we can focus on getting the playlists out from iTunes and just ignore Google Music.

Step 1 - Single M4A to MP3

I had a quick Google and convinced myself there was no easy ready-to-go way to do this. A quick try (in case Google was actually wrong!) confirmed iTunes supports burning MP3 CDs, but only if the files are already in a suitable format. There are some commercial options but I don’t need a fancy GUI. What I have in mind is a script - iTunes playlist in, MP3 CD out.

Step one is to prove we can convert a single M4A file to an MP3 file…

# We'll use ffmpeg to convert the files
$ brew install ffmpeg

# Find an m4a, output an mp3
# Miles Davis's Freddie Freeloader is an easy-going track to start with...
$ ffmpeg -i '02 Freddie Freeloader.mp4' freddie-freeloader-test.mp3

$ file freddie-freeloader-test.mp3
freddie-freeloader-test.mp3: Audio file with ID3 version 2.4.0, contains:MPEG ADTS, layer III, v1,  64 kbps, 44.1 kHz, Stereo

Running file against the output look good. I can also open the file as an MP3 and it plays as expected. Great!

I’m fairly sure ffmpeg could be used in a smarter way for better quality/file-size etc, but whatever these defaults are seems fine for me. Email me if you know the easy wins here!

Step 2 - Convert a batch based on an iTunes playlist

Yep, there’s a Perl module to read the iTunes library format:

cpan install Mac::iTunes::Library

I made a quick script just to check I can list the items in a playlist.

use warnings;
use strict;

use Mac::iTunes::Library;
use Mac::iTunes::Library::Item;
use Mac::iTunes::Library::XML;
use URI::Escape;
use feature qw(say);

# Update to your XML location of course!
my $file = "/Users/Martin/Music/iTunes/iTunes Music Library.xml";

# Create library instance
my $library = Mac::iTunes::Library->new();
$library = Mac::iTunes::Library::XML->parse($file);

my %allPlaylists = $library->playlists();

foreach my $pl (values %allPlaylists) {
    say "Playlist name: " . $pl->name;
    foreach my $i ($pl->items) {
        my $loc = uri_unescape($i->{Location});
        say $loc;
    }
    print "\n\n";
}

Works as expected. Note that I had to URI escape the locations. I assume this is a consequence of the XML format.

Step 3 - Writing to CD

I expanded the above listing script to then send files to ffmpeg if they needed conversion, or just directly copy to the output directory if not. This is version 1 of a usable iTunes playlist to MP3 file script.

It’s basic and fragile. There is no real check that MP3 files really are MP3, or that the non-MP3 files can just be sent straight to ffmpeg, but for my use case it’s fine.

The final step is, how do we take our folder and burn it to a disc? For now I am just naming the output folder with an .fpbf extension. This tells Finder in OS X to treat it as an OS X Burn Folder and that means we get a ‘Burn’ button in the top right. This flavour of folder usually stores shortcuts to files waiting to be burnt to disc but there’s nothing stopping real files being stored in that folder as well, which is ideal for us.

Piecing It Together

Using the final script we can take an iTunes playlist and get an all-MP3 set of output files ready to burn to disc.

./make-mp3-cd -p 'Big Playlist' -o folder-to-burn.fpbf

Readers who go on to use the script may notice that it can take a directory or an iTunes playlist. That’s because pretty much as soon as I was finished I found the first set of files I wanted to play in the car were just in a directory rather than a playlist. The first real world usage required an immediate modification which is classic software development.

Dev SysAdmin
Back to posts