This winter I took a course called System Software. In it, we learned a neat programming language called Perl. Perl was handy for that class because it happens to be very good at parsing text, and we used it to write a simple compiler. Being the pragmatic kind of person that I am, I immediately began to think of ways to use this new found skill, and the opportunity arose in a rather roundabout way.
You see, I have what I’d describe as a fairly large collection of music (roughly 18.6 days worth according to iTunes). This sometimes causes problems when I’m out shopping for CDs and I can’t quite recall which ones I already own. iTunes is able to export a list of your music as an XML document, but you end up with a large unwieldy file with roughly 15 lines per song.
The solution: create a small Perl script to go through every line of this gigantic XML document and create a list of albums matched with artists. The result of my code monkeying is in the box below. Is the script terribly well written? Not especially. Did my album problem really need solving that badly? Not particularly. Was this a good excuse to play around with Perl a bit? Damn right. Enjoy.
#!/usr/bin/perl
#===========================================
#Script written by Matthew Gallant
#===========================================
$filename = $ARGV[0];
print("Extracting album list from $filename... ");
open(READ, "$filename") ||
die("\nError: $filename not found or cannot be opened.");
my %albums;
my $artist;
while(my $line = <READ>)
{
if($line =~ m/<key>Artist<\/key>/)
{
chomp($line);
$line =~ s/^\s+<key>Artist<\/key><string>//;
$line =~ s/&/&/;
$line =~ s/<\/string>//;
if($line =~ m/^The /)
{
$line =~ s/^The //;
$line = $line . ", The";
}
$artist = $line;
}
elsif($line =~ m/<key>Album<\/key>/)
{
chomp($line);
$line =~ s/^\s+<key>Album<\/key><string>//;
$line =~ s/&/&/;
$line =~ s/ \(Disc \d\)//;
$line =~ s/<\/string>//;
if($line ne "N/A")
{
my %artistalbums;
if(exists $albums{$artist})
{
my $albumsref = $albums{$artist};
%artistalbums = %$albumsref;
}
$artistalbums{$line} = "";
$albums{$artist} = \%artistalbums;
}
}
}
close(READ);
print("Complete.\n");
print("Writing album list to Album List.txt... ");
open(WRITE, ">Album List.txt") ||
die("\nError: Album List.txt cannot be written to.\n");
for my $key (sort(keys %albums))
{
$tempkey = $key;
if($tempkey =~ m/, The$/)
{
$tempkey =~ s/, The//;
$tempkey = "The " . $tempkey;
}
printf WRITE ("%-40.39s", $tempkey);
my $valuesref = $albums{$key};
my %values = %$valuesref;
foreach my $album (sort(keys %values))
{
print WRITE ("$album\n\t\t\t\t\t");
}
print WRITE ("\n");
}
close(WRITE);
print("Complete.");
exit(0);
The result should look something like this. If you’d like to try this program out, but don’t have the experience to run it in the command prompt, here’s a summarized guide with some helpful links:
- If you’re running Windows, you’ll need to download a Perl interpreter such as ActivePerl. If you’re running Linux, it’s built in.
- Open up a simple text editor (NodePad, WordPad, TextPad), then save the code from the above box as “albumlister.pl”. Open iTunes, go to File > Export Library and save it as “library.xml” in the same directory as the Perl code.
- Open up the command prompt and switch over to the directory where you saved the Perl code (helpful guide here).
- Type in the following to run the program: “perl albumlister.pl library.xml“. Your album list will be stored in a file called “Album List.txt” in the same directory.
July 17th, 2007 at 5:09 am
I’ve over 20 gig of music, I think it’s a common problem, trying to remember what you have.
Having so much music available, I don’t judge music by who tells me it’s good anymore. I ‘listen’ to it, novel I know. Via site like lastfm I end up with music I’ve never heard of. 10 years ago I was stuck with whatever my country town pop trash shop had.
I’ve never felt brave enough to tackle perl. It seems so unforgiving. But I’ve been thinking should just so that I can do this
:)
July 17th, 2007 at 5:17 am
Blogger really frustrates me in that I can’t edit my comments… Grr.
July 17th, 2007 at 6:23 am
For what it’s worth, one option is to delete your own comment and repost the corrected version.
Perl might be more forgiving than you think. For instance, there are only three main kinds of variables: scalars ($), arrays (@) and hash tables (%). Furthermore, the formatting requirements for the code are typically very leniant. My main qualm with Perl is that the error messages you get from the interpreter tend to be very cryptic.
Also, to make a small correction from my post, it turns out I can turn off the automatic <br> tags, but then unfortunately all of my previous posts will not be correctly formatted.
July 17th, 2007 at 7:10 am
By unforgiving I meant that since it is so flexible and the error messages are so cryptic, I get the impression that mistakes and misunderstandings can be difficult to pin down.
So in a way it’s too flexible, so it scares me off.
July 17th, 2007 at 7:25 am
You’re exactly right, that’s a major pain when using Perl.