line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package MP3::ID3v1Tag; |
2
|
|
|
|
|
|
|
require 5.004; |
3
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
5
|
|
|
|
|
|
|
# $Id: ID3v1Tag.pm,v 2.11 2000/09/01 00:26:18 sander Exp $ |
6
|
|
|
|
|
|
|
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
7
|
|
|
|
|
|
|
|
8
|
1
|
|
|
1
|
|
841
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
35
|
|
9
|
1
|
|
|
1
|
|
5
|
use vars qw(@ISA @EXPORT @EXPORT_OK); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
56
|
|
10
|
1
|
|
|
1
|
|
6
|
use Carp; |
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
77
|
|
11
|
1
|
|
|
1
|
|
927
|
use IO::File; |
|
1
|
|
|
|
|
13229
|
|
|
1
|
|
|
|
|
2658
|
|
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
require Exporter; |
14
|
|
|
|
|
|
|
@ISA = ('Exporter'); |
15
|
|
|
|
|
|
|
@EXPORT = qw(); |
16
|
|
|
|
|
|
|
@EXPORT_OK = qw(); |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
$MP3::ID3v1Tag::VERSION = do { my @r = (q$Revision: 2.11 $ =~ /\d+/g); $r[0]--;sprintf "%d."."%02d" x $#r, @r }; # must be all one line, for MakeMaker |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
## Revision and debuging |
21
|
|
|
|
|
|
|
$MP3::ID3v1Tag::revision = '$Id: ID3v1Tag.pm,v 2.11 2000/09/01 00:26:18 sander Exp $ '; |
22
|
|
|
|
|
|
|
my $DEBUG = 0; |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
## SOME USEFULL CONSTANTS. |
25
|
|
|
|
|
|
|
## see http://www.dv.co.yu/mpgscript/mpeghdr.htm |
26
|
|
|
|
|
|
|
## by Predrag Supurovic |
27
|
|
|
|
|
|
|
## http://www.id3.org/ |
28
|
|
|
|
|
|
|
my $DefaultClass = 'MP3::ID3v1Tag'; |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
@MP3::ID3v1Tag::id3_genres_array = ( |
31
|
|
|
|
|
|
|
'Blues', 'Classic Rock', 'Country', 'Dance', |
32
|
|
|
|
|
|
|
'Disco', 'Funk', 'Grunge', 'Hip-Hop', 'Jazz', |
33
|
|
|
|
|
|
|
'Metal', 'New Age', 'Oldies', 'Other', 'Pop', 'R&B', |
34
|
|
|
|
|
|
|
'Rap', 'Reggae', 'Rock', 'Techno', 'Industrial', |
35
|
|
|
|
|
|
|
'Alternative', 'Ska', 'Death Metal', 'Pranks', |
36
|
|
|
|
|
|
|
'Soundtrack', 'Euro-Techno', 'Ambient', 'Trip-Hop', |
37
|
|
|
|
|
|
|
'Vocal', 'Jazz+Funk', 'Fusion', 'Trance', |
38
|
|
|
|
|
|
|
'Classical', 'Instrumental', 'Acid', 'House', |
39
|
|
|
|
|
|
|
'Game', 'Sound Clip', 'Gospel', 'Noise', |
40
|
|
|
|
|
|
|
'AlternRock', 'Bass', 'Soul', 'Punk', 'Space', |
41
|
|
|
|
|
|
|
'Meditative', 'Instrumental Pop', |
42
|
|
|
|
|
|
|
'Instrumental Rock', 'Ethnic', 'Gothic', 'Darkwave', |
43
|
|
|
|
|
|
|
'Techno-Industrial', 'Electronic', 'Pop-Folk', |
44
|
|
|
|
|
|
|
'Eurodance', 'Dream', 'Southern Rock', 'Comedy', |
45
|
|
|
|
|
|
|
'Cult', 'Gangsta', 'Top 40', 'Christian Rap', |
46
|
|
|
|
|
|
|
'Pop/Funk', 'Jungle', 'Native American', 'Cabaret', |
47
|
|
|
|
|
|
|
'New Wave', 'Psychadelic', 'Rave', 'Showtunes', |
48
|
|
|
|
|
|
|
'Trailer', 'Lo-Fi', 'Tribal', 'Acid Punk', |
49
|
|
|
|
|
|
|
'Acid Jazz', 'Polka', 'Retro', 'Musical', |
50
|
|
|
|
|
|
|
'Rock & Roll', |
51
|
|
|
|
|
|
|
'Hard Rock', 'Folk', 'Folk/Rock', 'National Folk', |
52
|
|
|
|
|
|
|
'Swing', 'Fast Fusion', 'Bebob', 'Latin', 'Revival', |
53
|
|
|
|
|
|
|
'Celtic', 'Bluegrass', 'Avantgarde', 'Gothic Rock', |
54
|
|
|
|
|
|
|
'Progressive Rock', 'Psychedelic Rock', |
55
|
|
|
|
|
|
|
'Symphonic Rock', 'Slow Rock', 'Big Band', |
56
|
|
|
|
|
|
|
'Chorus', 'Easy Listening', 'Acoustic', 'Humour', |
57
|
|
|
|
|
|
|
'Speech', |
58
|
|
|
|
|
|
|
'Chanson', 'Opera', 'Chamber Music', 'Sonata', |
59
|
|
|
|
|
|
|
'Symphony', 'Booty Bass', 'Primus', 'Porn Groove', |
60
|
|
|
|
|
|
|
'Satire', 'Slow Jam', 'Club', 'Tango', 'Samba', |
61
|
|
|
|
|
|
|
'Folklore', 'Ballad', 'Power Ballad', |
62
|
|
|
|
|
|
|
'Rhythmic Soul', 'Freestyle', 'Duet', |
63
|
|
|
|
|
|
|
'Punk Rock', 'Drum Solo', 'Acapella', |
64
|
|
|
|
|
|
|
'Euro-house', 'Dance Hall' |
65
|
|
|
|
|
|
|
); |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
my $c = 0; |
68
|
|
|
|
|
|
|
%MP3::ID3v1Tag::id3_genres = map {$_ => $c++ } @MP3::ID3v1Tag::id3_genres_array; |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
## A silly print routine useful for debugging. |
71
|
|
|
|
|
|
|
sub debug { |
72
|
0
|
|
|
0
|
0
|
|
my($self,$message) = @_; |
73
|
0
|
0
|
|
|
|
|
print STDERR "$message\n" if $DEBUG; |
74
|
|
|
|
|
|
|
} |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
## Constructor for Object of Module |
77
|
|
|
|
|
|
|
sub new { |
78
|
0
|
|
|
0
|
0
|
|
my($class,$mp3_file,$readonly) = @_; |
79
|
0
|
|
|
|
|
|
my $self = {}; |
80
|
0
|
0
|
|
|
|
|
$readonly = 0 unless defined($readonly); |
81
|
0
|
|
|
|
|
|
$self->{FileHandle} = new IO::File; |
82
|
0
|
0
|
0
|
|
|
|
if( -w $mp3_file || !$readonly) { |
83
|
0
|
0
|
0
|
|
|
|
$self->{FileHandle}->open("+<${mp3_file}") or (warn("Can't open ${mp3_file}: $!") and return undef); |
84
|
0
|
|
|
|
|
|
$self->{readonly} = 0; |
85
|
|
|
|
|
|
|
} else { |
86
|
0
|
0
|
0
|
|
|
|
$self->{FileHandle}->open("<${mp3_file}") or (warn("Can't open ${mp3_file}: $!") and return undef); |
87
|
0
|
|
|
|
|
|
$self->{readonly} = 1; |
88
|
|
|
|
|
|
|
} |
89
|
0
|
|
|
|
|
|
$self->{filename} = $mp3_file; |
90
|
0
|
|
|
|
|
|
$self->{tag} = (); |
91
|
0
|
|
0
|
|
|
|
bless($self, ref $class || $class || $DefaultClass); |
92
|
0
|
|
|
|
|
|
my $initialized = $self->init(); |
93
|
0
|
|
|
|
|
|
return $self; |
94
|
|
|
|
|
|
|
} |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
# We provide a DESTROY method so that the autoloader |
97
|
|
|
|
|
|
|
# doesn't bother trying to find it. |
98
|
|
|
|
|
|
|
sub DESTROY { |
99
|
0
|
|
|
0
|
|
|
my($self) = @_; |
100
|
0
|
|
|
|
|
|
$self->{FileHandle}->close(); |
101
|
|
|
|
|
|
|
} |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
## Generic routine to see if this MP3 has an ID3v1Tag |
104
|
|
|
|
|
|
|
sub got_tag { |
105
|
0
|
|
|
0
|
0
|
|
my($self) = @_; |
106
|
0
|
0
|
|
|
|
|
return ($self->find_tag_id3v1())?1:0; |
107
|
|
|
|
|
|
|
} |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
## Some generic initialization |
110
|
|
|
|
|
|
|
## Find the headers and be ready for questions. |
111
|
|
|
|
|
|
|
sub init { |
112
|
0
|
|
|
0
|
0
|
|
my($self) = @_; |
113
|
0
|
|
|
|
|
|
my $bytestring =""; |
114
|
0
|
|
|
|
|
|
$bytestring = $self->find_tag_id3v1(); |
115
|
0
|
0
|
|
|
|
|
if(!defined($bytestring)) { |
116
|
0
|
|
|
|
|
|
return 0; |
117
|
|
|
|
|
|
|
} else { |
118
|
0
|
|
|
|
|
|
$self->decode_tag_id3v1($bytestring); |
119
|
|
|
|
|
|
|
} |
120
|
0
|
|
|
|
|
|
return 1; |
121
|
|
|
|
|
|
|
} |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
## Print a Genre Chart for easy reference. |
124
|
|
|
|
|
|
|
sub print_genre_chart { |
125
|
0
|
|
|
0
|
0
|
|
my($self,$columns) = @_; |
126
|
0
|
0
|
|
|
|
|
$columns = 3 if ($columns <=0); |
127
|
0
|
|
|
|
|
|
my $i = 0; |
128
|
0
|
|
|
|
|
|
for(my $i = 0;$i < $#MP3::ID3v1Tag::id3_genres_array+1 ; $i += $columns) { |
129
|
0
|
|
0
|
|
|
|
for(my $j = 0;($j < $columns) && ($i + $j < $#MP3::ID3v1Tag::id3_genres_array+1); $j++) { |
130
|
0
|
|
|
|
|
|
printf("%2s. %-20s",$i + $j, $MP3::ID3v1Tag::id3_genres_array[$i + $j]); |
131
|
|
|
|
|
|
|
} |
132
|
0
|
|
|
|
|
|
print "\n"; |
133
|
|
|
|
|
|
|
} |
134
|
|
|
|
|
|
|
} |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
## ID3v1 TAG at the END of the File. |
137
|
|
|
|
|
|
|
## Talks about ID3v2 being at the beginning of the file. |
138
|
|
|
|
|
|
|
sub find_tag_id3v1 { |
139
|
0
|
|
|
0
|
0
|
|
my($self) = @_; |
140
|
0
|
|
|
|
|
|
my($bytes,$line); |
141
|
|
|
|
|
|
|
## MusicMatch has their data here aswell, but they are planning |
142
|
|
|
|
|
|
|
## on supporting ID3 to prevent issues. |
143
|
0
|
|
|
|
|
|
$self->{FileHandle}->seek(-128,SEEK_END); # Find the last 128 bytes |
144
|
0
|
|
|
|
|
|
while($line = $self->{FileHandle}->getline()) { $bytes .= $line; } |
|
0
|
|
|
|
|
|
|
145
|
0
|
0
|
|
|
|
|
return undef if $bytes !~ /^TAG/; # Must have Tag Ident to be valid. |
146
|
0
|
|
|
|
|
|
return $bytes; |
147
|
|
|
|
|
|
|
} |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
## Decode the ID3v1 Tag into useful tidbits. |
151
|
|
|
|
|
|
|
sub decode_tag_id3v1 { |
152
|
0
|
|
|
0
|
0
|
|
my($self,$buffer) = @_; |
153
|
|
|
|
|
|
|
## Unpack the Audio ID3v1 |
154
|
0
|
|
|
|
|
|
(undef, @{$self->{tag}}{qw/title artist album year comment genre_num/}) = |
|
0
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
unpack('a3a30a30a30a4a30C1', $buffer); |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
## Clean em up a bit |
158
|
0
|
|
|
|
|
|
foreach (sort keys %{$self->{tag}}) { |
|
0
|
|
|
|
|
|
|
159
|
0
|
0
|
|
|
|
|
if(defined($self->{tag}{$_})) { |
160
|
0
|
|
|
|
|
|
$self->{tag}{$_} =~ s/\s+$//; |
161
|
0
|
|
|
|
|
|
$self->{tag}{$_} =~ s/\0.*$//; |
162
|
0
|
|
|
|
|
|
$self->debug(sprintf("ID3v1: %s = ", $_ ) . $self->{tag}{$_}); |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
} |
165
|
0
|
|
|
|
|
|
$self->{tag}{'genre'} = $MP3::ID3v1Tag::id3_genres_array[$self->{tag}{'genre_num'}]; |
166
|
0
|
|
|
|
|
|
$self->debug(sprintf("ID3v1: %s = ", 'genre' ) . $self->{tag}{'genre'}); |
167
|
|
|
|
|
|
|
} |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
sub encode_tag_id3v1 { |
170
|
0
|
|
|
0
|
0
|
|
my($self) = @_; |
171
|
|
|
|
|
|
|
## Visit the beginning of the id3 tag if it exists |
172
|
0
|
0
|
|
|
|
|
return 0 if($self->{readonly}); |
173
|
0
|
0
|
|
|
|
|
if(!defined($self->find_tag_id3v1())) { |
174
|
0
|
|
|
|
|
|
$self->debug("Going to Append Tag"); |
175
|
|
|
|
|
|
|
# No Tag |
176
|
0
|
|
|
|
|
|
$self->{FileHandle}->seek(0,SEEK_END); # Find EOF |
177
|
|
|
|
|
|
|
} else { |
178
|
0
|
|
|
|
|
|
$self->debug("Going to Re-write Tag."); |
179
|
0
|
|
|
|
|
|
$self->{FileHandle}->seek(-128,SEEK_END); # Find the last 128 bytes |
180
|
|
|
|
|
|
|
} |
181
|
0
|
0
|
|
|
|
|
$self->{tag}{'genre_num'} = 255 if(!defined($self->{tag}{'genre_num'})); |
182
|
0
|
|
|
|
|
|
$self->{FileHandle}->print(pack("a3a30a30a30a4a30C1", |
183
|
|
|
|
|
|
|
'TAG', |
184
|
|
|
|
|
|
|
$self->{tag}{'title'}, |
185
|
|
|
|
|
|
|
$self->{tag}{'artist'}, |
186
|
|
|
|
|
|
|
$self->{tag}{'album'}, |
187
|
|
|
|
|
|
|
$self->{tag}{'year'}, |
188
|
|
|
|
|
|
|
$self->{tag}{'comment'}, |
189
|
|
|
|
|
|
|
$self->{tag}{'genre_num'})); |
190
|
0
|
|
|
|
|
|
$self->{FileHandle}->flush(); |
191
|
0
|
|
|
|
|
|
return 1; |
192
|
|
|
|
|
|
|
} |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
sub remove_tag { |
195
|
0
|
|
|
0
|
0
|
|
my($self) = @_; |
196
|
0
|
0
|
|
|
|
|
return 0 if($self->{readonly}); |
197
|
0
|
0
|
|
|
|
|
return 1 if(!defined($self->find_tag_id3v1())); |
198
|
0
|
|
|
|
|
|
my $filesize = (stat($self->{FileHandle}))[7]; |
199
|
0
|
|
|
|
|
|
$self->debug("Removing Tag: File size = $filesize"); |
200
|
0
|
|
|
|
|
|
my $success = truncate($self->{FileHandle},($filesize - 128)); |
201
|
0
|
|
|
|
|
|
$filesize = (stat($self->{FileHandle}))[7]; |
202
|
0
|
|
|
|
|
|
$self->debug("Removed Tag : File size = $filesize"); |
203
|
|
|
|
|
|
|
} |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
sub save { |
206
|
0
|
|
|
0
|
0
|
|
my($self) = @_; |
207
|
0
|
|
|
|
|
|
return $self->encode_tag_id3v1(); |
208
|
|
|
|
|
|
|
} |
209
|
|
|
|
|
|
|
## Print the Tag to default File Handler (usually STDOUT) |
210
|
|
|
|
|
|
|
sub print_tag { |
211
|
0
|
|
|
0
|
0
|
|
my($self) = @_; |
212
|
|
|
|
|
|
|
|
213
|
0
|
0
|
|
|
|
|
if(defined($self->{tag})) { |
214
|
0
|
|
|
|
|
|
foreach (sort keys %{$self->{tag}}) { |
|
0
|
|
|
|
|
|
|
215
|
0
|
|
|
|
|
|
print(sprintf("%-10s = ",$_ ) . $self->{tag}{$_} . "\n"); |
216
|
|
|
|
|
|
|
} |
217
|
|
|
|
|
|
|
} else { |
218
|
0
|
|
|
|
|
|
print "No ID3v1 Tag Found\n"; |
219
|
|
|
|
|
|
|
} |
220
|
|
|
|
|
|
|
} |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
## |
224
|
|
|
|
|
|
|
sub get_title { |
225
|
0
|
|
|
0
|
0
|
|
my($self) = @_; |
226
|
0
|
|
|
|
|
|
return $self->{tag}{'title'}; |
227
|
|
|
|
|
|
|
} |
228
|
|
|
|
|
|
|
sub set_title { |
229
|
0
|
|
|
0
|
0
|
|
my ($self,$title) = @_; |
230
|
0
|
|
|
|
|
|
$self->{tag}{'title'} = $title; |
231
|
|
|
|
|
|
|
} |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
## |
234
|
|
|
|
|
|
|
sub get_artist { |
235
|
0
|
|
|
0
|
0
|
|
my($self) = @_; |
236
|
0
|
|
|
|
|
|
return $self->{tag}{'artist'}; |
237
|
|
|
|
|
|
|
} |
238
|
|
|
|
|
|
|
sub set_artist { |
239
|
0
|
|
|
0
|
0
|
|
my($self,$artist) = @_; |
240
|
0
|
|
|
|
|
|
$self->{tag}{'artist'} = $artist; |
241
|
|
|
|
|
|
|
} |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
## |
244
|
|
|
|
|
|
|
sub get_album { |
245
|
0
|
|
|
0
|
0
|
|
my($self) = @_; |
246
|
0
|
|
|
|
|
|
return $self->{tag}{'album'}; |
247
|
|
|
|
|
|
|
} |
248
|
|
|
|
|
|
|
sub set_album { |
249
|
0
|
|
|
0
|
0
|
|
my($self,$album) = @_; |
250
|
0
|
|
|
|
|
|
$self->{tag}{'album'} = $album; |
251
|
|
|
|
|
|
|
} |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
## |
254
|
|
|
|
|
|
|
sub get_year { |
255
|
0
|
|
|
0
|
0
|
|
my($self) = @_; |
256
|
0
|
|
|
|
|
|
return $self->{tag}{'year'}; |
257
|
|
|
|
|
|
|
} |
258
|
|
|
|
|
|
|
sub set_year { |
259
|
0
|
|
|
0
|
0
|
|
my($self,$year) = @_; |
260
|
0
|
|
|
|
|
|
$self->{tag}{'year'} = $year; |
261
|
|
|
|
|
|
|
} |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
sub get_comment { |
264
|
0
|
|
|
0
|
0
|
|
my($self) = @_; |
265
|
0
|
|
|
|
|
|
return $self->{tag}{'comment'}; |
266
|
|
|
|
|
|
|
} |
267
|
|
|
|
|
|
|
sub set_comment { |
268
|
0
|
|
|
0
|
0
|
|
my($self,$comment) = @_; |
269
|
0
|
|
|
|
|
|
$self->{tag}{'comment'} = $comment; |
270
|
|
|
|
|
|
|
} |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
sub set_genre { |
273
|
0
|
|
|
0
|
0
|
|
my($self,$genre) = @_; |
274
|
0
|
|
|
|
|
|
my $genre_num = $MP3::ID3v1Tag::id3_genres{$genre}; |
275
|
0
|
0
|
0
|
|
|
|
if($genre_num >= 0 && $genre_num <= $#MP3::ID3v1Tag::id3_genres_array) { |
276
|
0
|
|
|
|
|
|
$self->{tag}{'genre'} = $genre; |
277
|
0
|
|
|
|
|
|
$self->{tag}{'genre_num'} = $genre_num; |
278
|
|
|
|
|
|
|
} |
279
|
|
|
|
|
|
|
} |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
sub get_genre { |
282
|
0
|
|
|
0
|
0
|
|
my($self) = @_; |
283
|
0
|
|
|
|
|
|
return $self->{tag}{'genre'}; |
284
|
|
|
|
|
|
|
} |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
sub set_genre_num { |
287
|
0
|
|
|
0
|
0
|
|
my($self,$genre_num) = @_; |
288
|
0
|
0
|
0
|
|
|
|
if( $genre_num >= 0 && $genre_num <= $#MP3::ID3v1Tag::id3_genres_array) { |
289
|
0
|
|
|
|
|
|
$self->{tag}{'genre_num'} = $genre_num; |
290
|
0
|
|
|
|
|
|
$self->{tag}{'genre'} = $MP3::ID3v1Tag::id3_genres_array[$genre_num]; |
291
|
0
|
|
|
|
|
|
return 1; |
292
|
|
|
|
|
|
|
} |
293
|
0
|
|
|
|
|
|
return 0; |
294
|
|
|
|
|
|
|
} |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
sub get_genre_num { |
297
|
0
|
|
|
0
|
0
|
|
my($self) = @_; |
298
|
0
|
|
|
|
|
|
return $self->{tag}{'genre_num'}; |
299
|
|
|
|
|
|
|
} |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
## Gives direct access to the %tag hash |
302
|
|
|
|
|
|
|
sub tag { |
303
|
0
|
|
|
0
|
0
|
|
my($self,$key) = @_; |
304
|
0
|
0
|
|
|
|
|
return wantarray ? keys %{$self->{tag}}: $self->{tag}{$key}; |
|
0
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
} |
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
1; |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
=pod |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
=head1 NAME |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
MP3::ID3v1Tag - Edit ID3v1 Tags from an Audio MPEG Layer 3. |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
=head1 SYNOPSIS |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
use MP3::ID3v1Tag; |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
$mp3_file = new MP3::ID3v1Tag("filename.mp3"); |
321
|
|
|
|
|
|
|
$mp3_file->print_tag(); |
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
if($mp3_file->got_tag()) { |
324
|
|
|
|
|
|
|
$mp3_file->set_title($title); |
325
|
|
|
|
|
|
|
$save_status = $mp3_file->save(); |
326
|
|
|
|
|
|
|
} |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
=head1 DESCRIPTION |
330
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
The ID3v1Tag routines are useful for setting and reading ID3 MP3 Audio Tags. |
332
|
|
|
|
|
|
|
Just create an MP3::ID3v1Tag Object with the path to the file of interest, |
333
|
|
|
|
|
|
|
and query any of the methods below. |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
=head2 Print Full ID3 Tag |
336
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
To get a print out of all the header information (Default FileHandler), simply |
338
|
|
|
|
|
|
|
state the following |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
$mp3_file->print_tag(); |
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
=head2 Print Genre Chart |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
With an optional number of columns argument (default is 3) this will |
345
|
|
|
|
|
|
|
return a list of genre numbers with their appropriate genre. |
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
$mp3_file->print_genre_chart($COLUMNS); |
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
=head2 Checking for the Existance of ID3 Tags |
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
There is a handy method named got_tag() that can be easily used to determine |
352
|
|
|
|
|
|
|
if a particular MP3 file contains an ID3 Tag. |
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
if $mp3_file->got_tag() { |
355
|
|
|
|
|
|
|
$mp3_file->print_tag(); |
356
|
|
|
|
|
|
|
} |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
=head2 Viewing Tag Compontents individually |
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
There exist several methods that will return you the individual components |
361
|
|
|
|
|
|
|
of the ID3 Tag. |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
$title = $mp3_file->get_title(); |
364
|
|
|
|
|
|
|
$artist = $mp3_file->get_artist(); |
365
|
|
|
|
|
|
|
$album = $mp3_file->get_album(); |
366
|
|
|
|
|
|
|
$year = $mp3_file->get_year(); |
367
|
|
|
|
|
|
|
$genre = $mp3_file->get_genre(); |
368
|
|
|
|
|
|
|
$genre_num = $mp3_file->get_genre_num(); |
369
|
|
|
|
|
|
|
$comment = $mp3_file->get_comment(); |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
=head2 Editing and Removing Tags |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
Similar methods exist to allow you to change the components of the Tag, |
374
|
|
|
|
|
|
|
but none of the changes will actually be changed in the file until you |
375
|
|
|
|
|
|
|
call the save() routine. |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
$mp3_file->set_title("New Title"); |
378
|
|
|
|
|
|
|
$mp3_file->set_artist("New Artist"); |
379
|
|
|
|
|
|
|
$mp3_file->set_album("New Album"); |
380
|
|
|
|
|
|
|
$mp3_file->set_year(1999); |
381
|
|
|
|
|
|
|
$mp3_file->set_genre("Blues"); |
382
|
|
|
|
|
|
|
# Or use the genre numbers -> |
383
|
|
|
|
|
|
|
$mp3_file->set_genre_num(0); |
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
To remove an tag in its entirely just calling the remove_tag() method |
386
|
|
|
|
|
|
|
should work for you. |
387
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
$mp3_file->remove_tag() if $mp3_file->got_tag(); |
389
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
You could access all the components directly for a read only loop such |
391
|
|
|
|
|
|
|
as the following |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
foreach (sort $mp3_file->tag) { |
394
|
|
|
|
|
|
|
print "$_: " . $mp3_file->tag($_) . "\n"; |
395
|
|
|
|
|
|
|
} |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
=head1 AUTHOR |
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
Sander van Zoest Esvanzoest@cpan.orgE |
401
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
=head1 THANKS |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
Matt Plummer Ematt@mp3.comE, Mike Oliphant Eoliphant@gtk.orgE, |
405
|
|
|
|
|
|
|
Matt DiMeo Emattd@mp3.comE, Olaf Maetzner, Jason Bodnar and Peter |
406
|
|
|
|
|
|
|
Johansson |
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
=head1 COPYRIGHT |
409
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
Copyright 2000, Alexander van Zoest. All rights reserved. |
411
|
|
|
|
|
|
|
Copyright 1999-2000, Alexander van Zoest, MP3.com, Inc. All rights reserved. |
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it |
414
|
|
|
|
|
|
|
under the same terms as Perl itself. |
415
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
=head1 REFERENCES |
417
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
For general overview of MPEG 1.0, Layer 3 (MP3) Audio visit |
419
|
|
|
|
|
|
|
or get the book, |
420
|
|
|
|
|
|
|
"MP3: The Definitive Guide" by O'Reilly and Associates |
421
|
|
|
|
|
|
|
. |
422
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
For technical details about MP3 Audio read the |
424
|
|
|
|
|
|
|
ISO/IEC 11172 and ISO/IEC 13818 specifications, obtained via |
425
|
|
|
|
|
|
|
in the US or |
426
|
|
|
|
|
|
|
elsewhere in the world. For more information also check |
427
|
|
|
|
|
|
|
out compiled by Gabriel Bouvigne. |
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
For more specific references to the MP3 Audio ID3 Tags visit |
430
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
For information about ID3v2 and a perl implementation see MPEG::ID3v2Tag |
433
|
|
|
|
|
|
|
written by Matt DiMeo Emattd@mp3.comE. |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
=cut |