#!/usr/bin/perl -w # mp3_tag_fix # Max Baker # 4/5/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 [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 -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 4/6/2009 end_usage }