Category: |
Audio Related Programs |
Author/Contact Info |
The Mad Hatter |
Description: |
Given a directory, this will go thru and try to figure out artist, album, and title from the directory structure and filename. A few options allow you to tweak how it gets the information. Once it has gathered the info, it then writes an ID3v2 tag. I would support Ogg Vorbis, but I couldn't find a module on CPAN that could write tags to Oggs. Requires MP3::Tag, File::Find::Rule, File::Spec, and Cwd. (The last two are in the core.)
Nota Bene: Use at your own risk. If this messes up your pristine music collection, makes your socks smell, computer implode, or generally screws up anything, I am not liable. |
#!/usr/bin/perl
#
# "Intelligent" ID3v2 tagger for MP3s
#
our $VERSION = 0.04;
use strict;
use warnings;
use MP3::Tag;
use File::Find::Rule;
use File::Spec;
use Cwd;
my $dir = ""; # Search by default nowhere
my $ext = '.mp3'; # Grab files with the extension of .mp
+3
my $noSplit = 0; # If the file does NOT contain a hyph
+en, split into artist/title
my $titleFirst = 0; # Format: title - artist instead of: a
+rtist - title
my $artistFromName = 0; # Grab artist from filename
my $noOverwrite = 0; # Don't overwrite existing tags
my $help = 0; # Show help
my $cwd = Cwd::getcwd();
use Getopt::Long;
GetOptions("dir=s" => \$dir,
"ext=s" => \$ext,
"no-split" => \$noSplit,
"title-first" => \$titleFirst,
"artist-from-name" => \$artistFromName,
"no-overwrite" => \$noOverwrite,
"help" => \$help);
if ($help || !$dir) {
print <<" HELP";
$0 - "intelligent" ID3v2 tagger for MP3s, version $VERSION
Usage (defaults in brackets):
-d, --directory=DIR directory to start search in [$dir]
-e, --extension=EXT extension to search for [$ext]
--no-split do NOT split the filename into: artist - titl
+e [$noSplit]
-t, --title-first if not --no-split, use: title - artist instea
+d [$titleFirst]
-a, --artist-from-name get the artist from the filename [$artistFrom
+Name]
--no-overwrite don't overwrite any existing info [$noOverwri
+te]
HELP
exit;
}
my @mp3s = File::Find::Rule->file()
->name("*$ext")
->in($dir);
foreach my $mp3 (@mp3s) {
my @spec = File::Spec->splitdir(File::Spec->abs2rel($mp3, $dir));
my %file;
$file{name} = $spec[$#spec];
if (@spec >= 4) {
$file{genre} = $spec[$#spec - 3];
$file{artist} = $spec[$#spec - 2];
$file{album} = $spec[$#spec - 1];
}
elsif (@spec == 3) {
$file{artist} = $spec[$#spec - 2];
$file{album} = $spec[$#spec - 1];
}
elsif (@spec == 2) {
$file{artist} = $spec[$#spec - 1];
}
my $sansExtension = $file{name};
$sansExtension =~ s/\Q$ext\E\z//;
if (!$noSplit && $sansExtension =~ /\s*-\s*/) {
my ($artist, $title);
unless ($titleFirst) {
($artist, $title) = split /\s*-\s*/, $sansExtension, 2;
}
else {
($title, $artist) = split /\s*-\s*/, $sansExtension, 2;
}
$file{title} = $title;
$file{artist} = $artist if !$file{artist} || $artistFromName;
}
else {
$file{title} = $sansExtension;
}
my $tag = MP3::Tag->new($mp3);
# read an existing tag
$tag->get_tags();
my $id3v2;
$id3v2 = exists $tag->{ID3v2}
? $tag->{ID3v2}
: $tag->new_tag("ID3v2");
unless ($noOverwrite) {
$id3v2->remove_tag;
$id3v2 = $tag->new_tag("ID3v2");
$id3v2->add_frame("TIT2", $file{title}) if $file{title};
$id3v2->add_frame("TPE1", $file{artist}) if $file{artist};
$id3v2->add_frame("TALB", $file{album}) if $file{album};
$id3v2->add_frame("TCON", $file{genre}) if $file{genre};
$id3v2->write_tag;
}
else {
$id3v2->remove_frame($_) for qw/TIT2 TPE1 TALB TCON/;
$id3v2->add_frame("TIT2", $file{title}) if $file{title};
$id3v2->add_frame("TPE1", $file{artist}) if $file{artist};
$id3v2->add_frame("TALB", $file{album}) if $file{album};
$id3v2->add_frame("TCON", $file{genre}) if $file{genre};
}
$id3v2->write_tag;
}
|
Re: "Intelligent" ID3v2 Tagger
by Mr_Person (Hermit) on Jul 21, 2003 at 13:14 UTC
|
Ogg::Vorbis::Header will write to Ogg comment tags. I've been using it for a while without any problems. One thing that's a little different about Ogg comment fields is that unlike ID3 tags, there is no set requirement of what the tags must be called. However, there's a list here that has the most common usage for field and most players will follow that. | [reply] |
|
Ah, I saw that, but didn't know Ogg comment tags were freeform like that. Thanks for enlightening me, now I'll get around to adding Ogg support sometime.
| [reply] |
Re: "Intelligent" ID3v2 Tagger
by Chady (Priest) on Jul 21, 2003 at 13:44 UTC
|
Hi,
I'm writing something to categorize MP3s, I was thinking of something to correctly "parse"(?) the MP3 into good metadata: If the file has ID3 tags it's good, I read those and use them, if not, I have to rely on parsing the filename, folder/filename, folder/folder/filename... etc.
Instead of assuming that the files are always /(title) - (artist)/, I was thinking of something like checking $1 and $2 against a list of the artists already in the db to see if there IS an artist with that name and mark that as a possible artist, if not, require input from the user, but there are obvious flaws in that. (different ways to type the artist name, typos, punctuations...etc)
Does anyone use a similar technique? or something to achieve the same results?
He who asks will be a fool for five minutes, but he who doesn't ask will remain a fool for life.
Chady | http://chady.net/
| [reply] |
|
I have a similar problem regarding the naming convention, I have:
/(artist)/(album)/(tracknum) - (title)
What I thought might be better would be to have a templating string, then that could be used to extract the relevant fields. Thus using keywords, such as ARTIST, ALBUM, etc you should be able to extract the right field from the right portion of the path. So my template would look like:
/ARTIST/ALBUM/TRACKNUM - TITLE
I already do the extraction using File::Find::Rule (ain't it grand ... thanks Rich), but haven't gotten round to doing all the MP3 tagging. So I'll be having a jolly good play with this script once I'm back from YAPC::Europe.
A fine effort.
--
Barbie | Birmingham Perl Mongers | http://birmingham.pm.org/
| [reply] |
|
| [reply] |
Re: "Intelligent" ID3v2 Tagger
by Anonymous Monk on Dec 23, 2004 at 11:53 UTC
|
Hi
Having spent a good couple of hours playing with ID3v2 under Windows, MP3::Tag is the way foward. I had some problems adding long string comments with some other modules, so for completeness, in the context above comments could be added using the code below.
$id3v2->add_frame("COMM", "ENG", "Short text", "A nice long comment with lots of long text");
| [reply] [d/l] |
|
|