| 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 |