ITunes – Embedding Folder.jpg into your MP3s for Cover Flow

Written by max on 2009-04-29

Update

I’ve consolidated this script into a new one. GO HERE : http://warped.org/blog/2009/05/03/itunes-fixing-id3-tags-in-mp3s-take-two/

Overview

Let’s say that you have a well organized MP3 collection that you previously used with something like nAMP / Apache::MP3 that already has album art in each directory. Or better yet, you have a friend who does!

You may have collected album art for every album that you have, but good old Itunes will not recognize that. It will only find album art based on the ID3v2 tags in the files, and if the album is available for purchase from Apple.

There are plenty of programs you can download to help you manually add album art to the MP3’s. But if you already have done this, it sucks to have to do it again.

The Script

This script in Perl will embed a Folder.jpg and a Folder_back.jpg to files for use in Itunes. It’s partially based on another script I saw. As soon as I found that again, I’ll add the attribution back in here.

#!/usr/bin/perl -w
# mp3_add_art
# Max Baker <max @warped.org>
# 4/5/09
 
use File::Glob qw(:globally :glob);
use Audio::TagLib;
use Getopt::Long;
GetOptions (\%Args, "h|help", "f|front=s", 'b|back=s');
 
$Cover_Front = $Args{f} || "Folder.jpg";
$Cover_Back  = $Args{b} || "Folder_back.jpg";
 
die &usage if (! scalar @ARGV or $Args{h});
 
foreach my $d (@ARGV) {
    recurse_dir($d);
}
 
exit;
 
sub recurse_dir {
    my $root = shift;
 
    print "Entering $root\n";
 
    # bsd_glob handles spaces in file names/paths
    my @files = bsd_glob("$root/*",GLOB_QUOTE);
    foreach my $f (@files) {
        #print "'$f'\n";
        next if $f eq '.';
        next if $f eq '..';
 
        if (-d $f) {
            recurse_dir($f);
            next;
        }
        if (-r $f and $f =~ /\.mp3$/) {
            add_image($f,"$root/$Cover_Front","FrontCover","Cover (front)") if -r "$root/$Cover_Front";
            add_image($f,"$root/$Cover_Back", "BackCover", "Cover (back)")  if -r "$root/$Cover_Back";
        }
    }
}
sub add_image {
    my ($f,$img,$type,$desc) = @_;
 
    print "add_image($type) $img -> $f\n";
 
    my $mp3 = Audio::TagLib::MPEG::File->new($f) or die;
    my $id3v2 = $mp3->ID3v2Tag(1);
    open(PICFILE, "< $img") or die "Can't open image $img. $!\n";
 
    my $imgdata;
    my $filesize = -s PICFILE;
    binmode(PICFILE);
    read(PICFILE, $imgdata, $filesize);
    close(PICFILE);
 
    my $imgbv = Audio::TagLib::ByteVector->new();
    $imgbv->setData($imgdata,$filesize);
    my $bv = Audio::TagLib::ByteVector->new("APIC");
    my $field = Audio::TagLib::ID3v2::AttachedPictureFrame->new($bv, "UTF8");
    $field->setPicture($imgbv);
    $field->setTextEncoding("UTF8");
    $field->setMimeType(Audio::TagLib::String->new("image/jpeg"));
    $field->setType($type);
    $field->setDescription(Audio::TagLib::String->new($desc));
    $id3v2->addFrame($field);
    $mp3->save();
}
 
sub usage {
    return < < "end_usage";
 
mp3addart <dir>
 
Max Baker </max><max \@warped.org> 4/6/2009
 
This script recursively goes through a directory and imbeds album
art into MP3 Files. It uses taglib and Audio::TagLib.
 
USAGE: $0 <dir> [-f $Cover_Front] [-b $Cover_Back]
 
    -f - The name of the image to look for in each dir to embed front-covers
    -b - The name of the image to look for in each dir to embed back-covers
 
 
end_usage
}
</dir></max>

Prerequisites

You’ll notice in the prerequisites a Perl module you can get off of CPAN : Audio::Taglib.
For which you’ll need the TagLib library.

You should install the TagLib library using packages. For me using Fedora/Mythdora 10 I used this command :

yum install taglib-devel

The only problem is that TagLib has moved on to version 1.5 and Audio::TagLib hasn’t quite caught up yet. So you need to modify one line in Audio::TagLib before installing it. The file you are editing is
Makefile.PL.

BEGIN {
    # a simple work around to perform the neccessary pre-check
    # instead of overloading subs of MakeMaker or other wrapper
    print STDERR "ONLY support TagLib version 1.4.*\n";
    require Carp;
	# FIXME
	# openned for FreeBSD, OS X (darwin) and Cygwin
    Carp::croak("$^O is not supported currently") 
		unless $^O eq 'linux' or $^O eq 'freebsd' or $^O eq 'darwin' or 
		    $^O eq 'cygwin';
	Carp::croak("Please install taglib C++ package first") unless 
		system("taglib-config --version") == 0;
	our $libver = qx(taglib-config --version);
	chomp($libver);
	Carp::croak("Please install taglib ver 1.4.*") unless 
		$libver =~ m/^1\.4/io;
	our $libs = qx(taglib-config --libs);
	our $inc  = ' -I/usr/include -I./include -I. '. qx(taglib-config --cflags);
}

BECOMES :

BEGIN {
    # a simple work around to perform the neccessary pre-check
    # instead of overloading subs of MakeMaker or other wrapper
    print STDERR "ONLY support TagLib version 1.4.*\n";
    require Carp;
	# FIXME
	# openned for FreeBSD, OS X (darwin) and Cygwin
    Carp::croak("$^O is not supported currently") 
		unless $^O eq 'linux' or $^O eq 'freebsd' or $^O eq 'darwin' or 
		    $^O eq 'cygwin';
	Carp::croak("Please install taglib C++ package first") unless 
		system("taglib-config --version") == 0;
	our $libver = qx(taglib-config --version);
	chomp($libver);
	Carp::croak("Please install taglib ver >1.4.*") unless 
		$libver =~ m/^1\.[45]/io;
	our $libs = qx(taglib-config --libs);
	our $inc  = ' -I/usr/include -I./include -I. '. qx(taglib-config --cflags);
}

So that Version 1.4 and 1.5 are OK. Some tests fail, but otherwise it seems to work fine for me.

Next up : Setting the compilation Flag from a script.