1package MP3::Tag;
2
3################
4#
5# provides a general interface for different modules, which can read tags
6#
7# at the moment MP3::Tag works with MP3::Tag::ID3v1 and MP3::Tag::ID3v2
8
9use strict;
10use MP3::Tag::ID3v1;
11use MP3::Tag::ID3v2;
12use MP3::Tag::File;
13use vars qw/$VERSION %config/;
14
15$VERSION="0.40";
16
17=pod
18
19=head1 NAME
20
21MP3::Tag - Module for reading tags of MP3 audio files
22
23=head1 SYNOPSIS
24
25  use MP3::Tag;
26
27  $mp3 = MP3::Tag->new($filename);
28
29  # get some information about the file in the easiest way
30  ($song, $track, $artist, $album) = $mp3->autoinfo();
31
32  # or have a closer look on the tags
33
34  # scan file for existing tags
35  $mp3->get_tags;
36
37  if (exists $mp3->{ID3v1}) {
38      # read some information from the tag
39      $id3v1 = $mp3->{ID3v1};  # $id3v1 is only a shortcut for $mp3->{ID3v1}
40      print $id3v1->song;
41
42      # change the tag contents
43      $id3v1->all("Song","Artist","Album",2001,"Comment",10,"Top 40");
44      $id3v1->write_tag;
45  }
46
47  if (exists $mp3->{ID3v2}) {
48      # read some information from the tag
49      ($name, $info) = $mp3->{ID3v2}->get_frame("TIT2");
50      # delete the tag completely from the file
51      $mp3->{ID3v2}->remove_tag;
52  } else {
53      # create a new tag
54      $mp3->new_tag("ID3v2");
55      $mp3->{ID3v2}->add_frame("TALB", "Album title");
56      $mp3->write_tag;
57  }
58
59  $mp3->close();
60
61=head1 AUTHOR
62
63Thomas Geffert, thg@users.sourceforge.net
64
65=head1 DESCRIPTION
66
67Tag is a wrapper module to read different tags of mp3 files.
68It provides an easy way to access the functions of seperate moduls
69which do the handling of reading/writing the tags itself.
70
71At the moment MP3::Tag::ID3v1 and MP3::Tag::ID3v2 are supported.
72
73=over 4
74
75=item new()
76
77 $mp3 = MP3::Tag->new($filename);
78
79Creates a mp3-object, which can be used to retrieve/set
80different tags.
81
82=cut
83
84sub new {
85    my $class = shift;
86    my $filename = shift;
87    my $mp3data;
88    if (-f $filename) {
89	$mp3data = MP3::Tag::File->new($filename);
90    }
91    # later it should hopefully possible to support also http/ftp sources
92    # with a MP3::Tag::Net module or something like that
93    if ($mp3data) {
94	my $self={filename=>$mp3data};
95	bless $self, $class;
96	return $self;
97    }
98    return undef;
99}
100
101=pod
102
103=item get_tags()
104
105  [old name: getTags() . The old name is still available, but its use is not advised]
106
107  @tags = $mp3->get_tags;
108
109Checks which tags can be found in the mp3-object. It returns
110a list @tags which contains strings identifying the found tags, like
111"ID3v1" or "ID3v2" .
112
113Each found tag can then be accessed with $mp3->{tagname} , where tagname is
114a sting returned by get_tags ;
115
116Use the information found in L<MP3::Tag::ID3v1> and L<MP3::Tag::ID3v2>
117to see what you can do with the tags.
118
119=cut 
120
121################ tag subs
122
123sub get_tags {
124    my $self = shift;
125    my (@IDs, $ref);
126    if (exists $self->{gottags}) {
127	push @IDs, "ID3v1" if exists $self->{ID3v1};
128	push @IDs, "ID3v2" if exists $self->{ID3v2};
129    } elsif ($self->{filename}->open()) {
130	$self->{gottags}=1;
131	if (defined ($ref = MP3::Tag::ID3v2->new($self->{filename}))) {
132	    $self->{ID3v2} = $ref;
133	    push @IDs, "ID3v2";
134	}
135	if(defined ($ref = MP3::Tag::ID3v1->new($self->{filename}))) {
136	    $self->{ID3v1} = $ref;
137	    push @IDs, "ID3v1";
138	}
139    }
140    return @IDs;
141}
142
143# keep old name for a while
144*getTags = \&get_tags;
145
146=pod
147
148=item new_tag()
149
150  [old name: newTag() . The old name is still available, but its use is not advised]
151
152  $tag = $mp3->new_tag($tagname);
153
154Creates a new tag of the given type $tagname. You
155can access it then with $mp3->{$tagname}. At the
156moment ID3v1 and ID3v2 are supported as tagname.
157
158Returns an tag-object: $mp3->{$tagname}.
159
160=cut
161
162sub new_tag {
163    my $self = shift;
164    my $whichTag = shift;
165    if ($whichTag =~ /1/) {
166	$self->{ID3v1}= MP3::Tag::ID3v1->new($self->{filename},1);
167	return $self->{ID3v1};
168    } elsif ($whichTag =~ /2/) {
169	$self->{ID3v2}= MP3::Tag::ID3v2->new($self->{filename},1);
170	return $self->{ID3v2};
171    }
172}
173
174# keep old name for a while
175*newTag = \&new_tag;
176
177#only as a shortcut to {filename}->close to explicitly close a file
178
179=pod
180
181=item close()
182
183  $mp3->close;
184
185You can use close() to explicitly close a file. Normally this is done
186automatically by the module, so that you do not need to do this.
187
188=cut
189
190sub close {
191    my $self=shift;
192    $self->{filename}->close;
193}
194
195=pod
196
197=item genres()
198
199  $allgenres = $mp3->genres;
200  $genreName = $mp3->genres($genreID);
201  $genreID   = $mp3->genres($genreName);
202
203Returns a list of all genres (reference to an array), or the according
204name or id to a given id or name.
205
206This function is only a shortcut to MP3::Tag::ID3v1->genres.
207
208This can be also called as MP3::Tag->genres;
209
210=cut
211
212sub genres {
213  # returns all genres, or if a parameter is given, the according genre
214  my $self=shift;
215  return MP3::Tag::ID3v1::genres(shift);
216}
217
218=pod
219
220=item autoinfo()
221
222  ($song, $track, $artist, $album) = $mp3->autoinfo();
223  $info_hashref = $mp3->autoinfo();
224
225autoinfo() returns information about the song name, song number,
226artist and album name. It can get this information from an
227ID3v1-tag, an ID3v2-tag and from the filename itself.
228
229It will as default first try to find a ID3v2-tag to get this
230information. If this cannot be found it tries to find a ID3v1-tag and
231if this is not present either, it will use the filename to retrieve
232the information.
233
234You can change the order of this with the config() command.
235
236autoinfo() returns an array with the information or a hashref. The hash
237has four keys 'song', 'track', 'artist' and 'album' where the information is
238stored.
239
240=cut
241
242sub autoinfo() {
243    my ($self) = shift;
244
245    my @order;
246    if (exists $config{autoinfo}) {
247	@order = @{$config{autoinfo}};
248    } else {
249	@order = ("ID3v2","ID3v1","filename");
250    }
251
252    $self->get_tags unless exists $self->{gottags};
253
254    my ($song, $track, $artist, $album)=("","","","");
255    foreach my $part (@order) {
256	if (exists $self->{$part}) {
257	    #get the info
258	    $song=$self->{$part}->song;
259	    $track=$self->{$part}->track;
260	    $artist=$self->{$part}->artist;
261	    $album=$self->{$part}->album;
262	    last;
263	}
264    }
265    return wantarray ? ($song, $track, $artist, $album) :
266                       { song => $song, track => $track, artist => $artist, album => $album } ;
267}
268
269=pod
270
271=item config
272
273  MP3::Tag->config("item", options, ...);
274
275Possible items are:
276
277* autoinfo
278
279  Configure the order in which ID3v1-, ID3v2-tag and filename are used
280  by autoinfo.  Options can be "ID3v1","ID3v2","filename". The order
281  in which they are given to config also sets the order how they are
282  used by autoinfo. If an option is not present, it will not be used
283  by auotinfo.
284
285  $mp3->config("autoinfo","ID3v1","ID3v2","filename");
286
287    sets the order to check first ID3v1, then ID3v2 and at last the
288    Filename
289
290  $mp3->config("autoinfo","ID3v1","filename","ID3v2");
291
292    sets the order to check first ID3v1, then the Filename and last
293    ID3v2. As the filename will be always present ID3v2 will here
294    never be checked.
295
296  $mp3->config("autoinfo","ID3v1","ID3v2");
297
298    sets the order to check first ID3v1, then ID3v2. The filename will
299    never be used.
300
301* Later there will be probably more things to configure.
302
303=cut
304
305sub config() {
306    my ($self, $item, @options) = @_;
307
308    $item = lc $item;
309
310    if ($item ne "autoinfo") {
311	warn "MP3::Tag::config(): Unknown option '$item' found\n";
312	return;
313    }
314
315    $config{$item}=\@options;
316}
317
318
319sub DESTROY {
320    my $self=shift;
321    if (exists $self->{filename} and defined $self->{filename}) {
322	$self->{filename}->close;
323    }
324}
325
3261;
327
328=pod
329
330=head1 SEE ALSO
331
332L<MP3::Tag::ID3v1>, L<MP3::Tag::ID3v2>, L<MP3::Tag::File>
333
334=cut
335