#!/usr/bin/perl # # id3-from-filename -- generate ID3 tags based on the path to an MP3 or OGG file # # usage: id3-from-filename [--sub 's/.../.../g'] # --format '...' # [--capitalize FIELD1[,FIELD2...] ] # file1 [file2 ...] > shcommands # # sh -x shcommands # # format: # ALBUM becomes the ID3 album name tag # ARTIST becomes the ID3 artist name tag # TRACK becomes the ID3 track title # TRACKNUM becomes the ID3 track number # # otherwise, format is a standard Perl regular expression. Example: # # id3-from-filename --format '.*/ARTIST_-_ALBUM/TRACKNUM-TRACK.mp3' \ # ./Ska/The_Selecter_-_Greatest_Hits/*.mp3 sub usage { die " usage: id3-from-filename [--sub 's/.../.../g'] --format '...' [--capitalize FIELD1[,FIELD2...] ] file1 [file2 ...] > shcommands sh -x shcommands format: ALBUM becomes the ID3 album name tag ARTIST becomes the ID3 artist name tag TRACK becomes the ID3 track title TRACKNUM becomes the ID3 track number otherwise, format is a standard Perl regular expression. Example: id3-from-filename --format '.*/ARTIST_-_ALBUM/TRACKNUM-TRACK.mp3' \ ./Ska/The_Selecter_-_Greatest_Hits/*.mp3 "; } # my $mp3info_cmd = 'mp3info'; # for id3v2 tags my $mp3info_cmd = 'mp3info-id3v1'; # for id3v1 tags use Getopt::Long; use vars qw($opt_format $opt_sub $opt_capitalize ); GetOptions("format=s", "capitalize=s", "sub=s") or usage(); $opt_format or usage(); my $format = $opt_format; # eg. "./ALBUM/ARTIST---TRACK.mp3" my @captures = (); $format =~ s{(ALBUM|ARTIST|TRACKNUM|TRACK)}{ push (@captures, $1); if ($1 eq 'TRACKNUM') { '(\d+)?'; } else { '(.+)?'; } }ge; foreach my $file (@ARGV) { @caught = ($file =~ /^${format}$/og); if ($#caught < 0) { warn ": does not match /^$format\$/: $file\n"; next; } my $i = 0; foreach (@captures) { $out{$_} = $caught[$i]; $i++; } my $isogg=0; if ($file =~ /\.ogg$/i) { $isogg=1; } my $command = $mp3info_cmd.' '; if ($isogg) { $command = 'vorbiscomment -w '; } foreach (sort keys %out) { my $data = format_data ($out{$_}); #print "$file: $_ = $data\n"; if ($opt_capitalize && $opt_capitalize =~ /\b$_\b/) { $data = capitalize($data); } if ($_ eq 'ARTIST') { $command .= '-a \''.$data.'\' '; } if ($_ eq 'ALBUM') { $command .= '-l \''.$data.'\' '; } if ($_ eq 'TRACKNUM') { $command .= '-n \''.$data.'\' '; } if ($_ eq 'TRACK') { $command .= '-t \''.$data.'\' '; } } if ($isogg) { $command =~ s/ -t \'/ -t \'title=/g; $command =~ s/ -a \'/ -t \'artist=/g; $command =~ s/ -l \'/ -t \'album=/g; $command =~ s/ -n \'(.*?)\' / /g; # TODO - TRACK NUMBER } my $f = $file; $f =~ s/[\\\0]/ /gs; $f =~ s/\'/'"'"'/gs; # what a chore! quoting for use inside '...' $command .= ' \''.$f.'\''; print "$command\n"; } sub format_data { my $l = shift; $l =~ s/_/ /gs; if ($opt_sub) { eval '$l =~ '.$opt_sub.';'; if ($@) { warn '$l =~ '.$opt_sub.';: '.$@; } } $l =~ s/\s+/ /gs; $l =~ s/[\\\0]/ /gs; $l =~ s/\'/'"'"'/gs; # what a chore! quoting for use inside '...' $l; } sub capitalize { my $l = shift; $l =~ s/\b([a-z])/ uc $1; /ge; $l; }