iTunes – Fixing ID3 tags in MP3’s – Take two
Overview
In these last three posts [1] [2] [3] I tackled fixing my existing MP3’s to make them more iTunes friendly. I did it with three Perl scripts using two different ID3 libraries : Audio::TabLib which is a Perl wrapper to KDE’s TagLib, and MP3::Tag.
I’ve since given up on MP3::Tag. Although updated recently, it still does not support ID3v2 2.4, which, unfortunately is the default in iTunes versions 7 and 8. So I’ve combined all three scripts into one script that only uses Audio::TagLib. One bonus of this, is that TagLib is a fast C++ library, and so the script runs a lot faster than a Pure Perl based method. One batch run on 160GB of MP3’s only took a couple minutes.
The Script
The following script does all three of the functions from my last posts :
- Add Folder.jpg (or another image) to the MP3 for Cover Art
- Convert version 1 tags (ID3v1) to version 2 (ID3v2)
- Set the iTunes Compilation Flag (ICMP)
You can download the script here : http://warped.org/linux/mp3_fix_tag or copy paste from below :
#!/usr/bin/perl -w # mp3_tag_fix # Max Baker max@warped.org # 5/3/09 $VERSION=1.1; use File::Glob qw(:globally :glob); use Audio::TagLib; use Getopt::Long; GetOptions (\%Args, "h|help", "f|front=s", 'b|back=s', 'c|covers|addcovers','v1tov2', 'comp|compilation'); $Cover_Front = $Args{f} || "Folder.jpg"; $Cover_Back = $Args{b} || "Folder_back.jpg"; die &usage if (! scalar @ARGV or $Args{h}); die &usage unless ($Args{c} || $Args{v1tov2} || $Args{comp}); foreach my $f (@ARGV) { if (-d $f) { recurse_dir($f); next; } go($f); } exit; sub go { my $f = shift; # Only work on files that end in .mp3 return if $f eq '.'; return if $f eq '..'; return unless -r $f and $f =~ /\.mp3$/i; print " $f\n"; my $mp3 = Audio::TagLib::MPEG::File->new($f) or die; my $id3v1 = $mp3->ID3v1Tag(1); my $id3v2 = $mp3->ID3v2Tag(1); # Cover Art if ($Args{c}) { #print " --> Adding Cover Art\n"; add_image($id3v2,$f,"$root/$Cover_Front","FrontCover","Cover (front)") if -r "$root/$Cover_Front"; add_image($id3v2,$f,"$root/$Cover_Back", "BackCover", "Cover (back)") if -r "$root/$Cover_Back"; } # Copy v1 tags to v2 if ($Args{v1tov2}) { print " --> Copying ID3v1 data to ID3v2\n"; $id3v2->setArtist(Audio::TagLib::String->new($id3v1->artist)) if nb($id3v1->artist); $id3v2->setAlbum(Audio::TagLib::String->new($id3v1->album)) if nb($id3v1->album); $id3v2->setTitle(Audio::TagLib::String->new($id3v1->title)) if nb($id3v1->title); $id3v2->setYear($id3v1->year) if nb($id3v1->year); $id3v2->setTrack($id3v1->track) if nb($id3v1->track); $id3v2->setGenre(Audio::TagLib::String->new($id3v1->genre)) if nb($id3v1->genre); } # Add/Replace TCMP - Compilation Tag if ($Args{comp}) { print " --> Setting Compilation Flag\n"; my $tcmp = Audio::TagLib::ByteVector->new("TCMP"); $id3v2->removeFrames($tcmp); #my $f = Audio::TagLib::ID3v2::TextIdentificationFrame->new($tcmp, "UTF8"); my $f = Audio::TagLib::ID3v2::TextIdentificationFrame->new($tcmp); $f->setText(Audio::TagLib::String->new("1")); $id3v2->addFrame($f); } $mp3->save(); } 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) { if (-d $f) { recurse_dir($f); next; } go($f); } } # not blank or undef sub nb { my $string = shift; return 0 unless defined $string; return 0 if $string =~ /^\s*$/; return 1; } sub add_image { my ($id3v2,$f,$img,$type,$desc) = @_; print " --> add_image($type) $img -> $f\n"; 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); } sub usage { return < < "end_usage"; USAGE: $0 <dir> <cmd> [options] mp3_tag_fix Version $VERSION This script is used to fix up MP3 files for use in iTunes. It can do the following things : * Recursively go through a directory and embed album art * Copy ID3v1 tag data into ID3v2 <commands> -c | --addcovers - Embed $Cover_Front / $Cover_Back into the MP3 --v1tov2 - Copy ID3v1 Tags into ID3v2 Tag --comp - Set iTunes Compilation flag (TCMP) [OPTIONS] -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 Max Baker max\@warped.org 5/3/2009 end_usage } </commands></cmd>
Prerequisites
See the Prerequisites section on this post.
January 15th, 2010 at 5:54 am
Hi,
So good but it don’t work with the line 79 ==> my $root = shift;
I replace by==> $root = shift;