20 March 2012

(Perl) MP3::Tag を用いた ID3v2タグの読み取り・書き込み

■ ID3v2タグを読み取る方法

TIT2やTPE1などのフレーム名はMP3::Tag::ID3v2_Dataに列挙されている


#!/usr/bin/perl

use warnings;
use strict;
use MP3::Tag;

my $mp3 = MP3::Tag->new('test.mp3') or die;
$mp3->get_tags() or die;

if (exists $mp3->{ID3v2}){
my $id3v2 = $mp3->{ID3v2};
# ID3よりタグを読み込む
my $title = $id3v2->get_frame('TIT2');
my $artist = $id3v2->get_frame('TPE1');
my $album = $id3v2->get_frame('TALB');
my $year = $id3v2->get_frame('TYER');
my $track = $id3v2->get_frame('TRCK');
my $genre = $id3v2->get_frame('TCON');
my $comment_hash = $id3v2->get_frame('COMM');
my $comment = undef;
if (defined($comment_hash)){
my %comments = %{$comment_hash};
$comment = $comments{'Text'};
}
my $copyright = $id3v2->get_frame('TCOP');
my $diskno = $id3v2->get_frame('TPOS');

print(" ID3v2 tag exist\n".
" artist : ".(defined($artist)?$artist:'')."\n".
" title : ".(defined($title)?$title:'')."\n".
" album : ".(defined($album)?$album:'')."\n".
" year : ".(defined($year)?$year:'')."\n".
" track no : ".(defined($track)?$track:'')."\n".
" genre : ".(defined($genre)?$genre:'')."\n".
" comment : ".(defined($comment)?$comment:'')."\n".
" copyright : ".(defined($copyright)?$copyright:'')."\n".
" disk no : ".(defined($diskno)?$diskno:'')."\n"
);

}

$mp3->close();

読み込まれるタグの文字コードはutf8とは限らない。Encode::encode('utf8', '文字列')を用いて表示前にutf8に変換するとよい。

■ ID3v2タグを書き込む方法


#!/usr/bin/perl

use warnings;
use strict;
use MP3::Tag;

my $mp3 = MP3::Tag->new('test.mp3') or die;
$mp3->get_tags() or die;

if (exists $mp3->{ID3v2}){
my $id3v2 = $mp3->{ID3v2};
# ID3よりタグを読み込む
my $title = $id3v2->get_frame('TIT2');
my $artist = $id3v2->get_frame('TPE1');
my $album = $id3v2->get_frame('TALB');
my $year = $id3v2->get_frame('TYER');
my $track = $id3v2->get_frame('TRCK');
my $genre = $id3v2->get_frame('TCON');
my $comment_hash = $id3v2->get_frame('COMM');
my $comment = undef;
if (defined($comment_hash)){
my %comments = %{$comment_hash};
$comment = $comments{'Text'};
}
my $copyright = $id3v2->get_frame('TCOP');
my $diskno = $id3v2->get_frame('TPOS');

# artistタグを書き込む
if(defined($artist_new)){
if(!defined($artist)){ $id3v2->add_frame('TPE1', $artist_new); }
else{ $id3v2->change_frame('TPE1', $artist_new); }
print(" artist : ".(defined($artist)?$artist:'')." -> $artist_new\n");
}
# titleタグを書き込む
if(defined($title_new)){
if(!defined($title)){ $id3v2->add_frame('TIT2', $title_new); }
else{ $id3v2->change_frame('TIT2', $title_new); }
print(" title : ".(defined($title)?$title:'')." -> $title_new\n");
}
# albumタグを書き込む
if(defined($album_new)){
if(!defined($album)){ $id3v2->add_frame('TALB', $album_new); }
else{ $id3v2->change_frame('TALB', $album_new); }
print(" album : ".(defined($album)?$album:'')." -> $album_new\n");
}
# yearタグを書き込む
if(defined($year_new)){
$year_new = sub_conv_to_flagged_utf8($year_new);
if(!defined($year)){ $id3v2->add_frame('TYER', $year_new); }
else{ $id3v2->change_frame('TYER', $year_new); }
print(" year : ".(defined($year)?$year:'')." -> $year_new\n");
}
# trackタグを書き込む
if(defined($track_new)){
if(!defined($track)){ $id3v2->add_frame('TRCK', $track_new); }
else{ $id3v2->change_frame('TRCK', $track_new); }
print(" track : ".(defined($track)?$track:'')." -> $track_new\n");
}
# genreタグを書き込む
if(defined($genre_new)){
if(!defined($genre)){ $id3v2->add_frame('TCON', $genre_new); }
else{ $id3v2->change_frame('TCON', $genre_new); }
print(" genre : ".(defined($genre)?$genre:'')." -> $genre_new\n");
}
# commentタグを書き込む
if(defined($comment_new)){
if(!defined($comment)){ $id3v2->add_frame('COMM', 'ENG', '', $comment_new); }
else{ $id3v2->change_frame('COMM', 'ENG', '', $comment_new); }
print(" comment : ".(defined($comment)?$comment:'')." -> $comment_new\n");
}
# copyrightタグを書き込む
if(defined($copyright_new)){
if(!defined($copyright)){ $id3v2->add_frame('TCOP', $copyright_new); }
else{ $id3v2->change_frame('TCOP', $copyright_new); }
print(" copyright : ".(defined($copyright)?$copyright:'')." -> $copyright_new\n");
}

$id3v2->write_tag() or die("E: tag write error, $filename_base\n");
}

$mp3->close();

日本語を書きこむ場合、「utf8フラグ付き」に明示的に変換しておく必要がある。フラグなしの文字列にフラグを付けるにはdecode('文字列')のようにすればよい。
Windows Media Playerに対応するためにはUTF-16LE+BOMでID3v2に書きこむ必要があるので、環境変数 MP3TAG_USE_UTF_16LE をセットしてからこのスクリプトを実行する必要がある。 (また、マイクロソフト製品のバグ仕様かよ…)