AudioFile: more write support
[id3fs.git] / lib / ID3FS / AudioFile / Mp3.pm
1 # id3fs - a FUSE-based filesystem for browsing audio metadata
2 # Copyright (C) 2010  Ian Beckwith <ianb@erislabs.net>
3 #
4 # This program is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation, either version 3 of the License, or
7 # (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
17 package ID3FS::AudioFile::Mp3;
18
19 use strict;
20 use warnings;
21 use MP3::Tag;
22
23 sub new
24 {
25     my $proto=shift;
26     my $class=ref($proto) || $proto;
27     my $self={};
28     bless($self,$class);
29
30     $self->{path}=shift;
31     $self->{mp3}=MP3::Tag->new($self->{path});
32     $self->get_tags();
33     $self->{tags}={};
34
35     return $self;
36 }
37
38 sub set
39 {
40     my ($self, $func, $value)=@_;
41     return $self->choose($func) unless($value);
42     unless(exists($self->{mp3}->{ID3v1}))
43     {
44         $self->{mp3}->new_tag("ID3v1");
45     }
46     unless(exists($self->{mp3}->{ID3v2}))
47     {
48         $self->{mp3}->new_tag("ID3v2");
49     }
50     my $method=$func . "_set";
51     $self->{mp3}->$method($value, 1);
52     return $value;
53 }
54
55 sub choose
56 {
57     my($self, $func)=@_;
58     my $thing=undef;
59     if(exists($self->{mp3}->{ID3v2}))
60     {
61         $thing=$self->{mp3}->{ID3v2}->$func();
62     }
63     if(exists($self->{mp3}->{ID3v1}) && (!defined($thing) || !length($thing)))
64     {
65         $thing=$self->{mp3}->{ID3v1}->$func();
66     }
67     return $thing;
68 }
69
70 sub year      { return(shift->set("year",     @_)); }
71 sub artist    { return(shift->set("artist",   @_)); }
72 sub album     { return(shift->set("album",    @_)); }
73 sub track     { return(shift->set("title",    @_)); }
74 sub tracknum  { return(shift->set("tracknum", @_)); }
75 sub comment   { return(shift->set("comment",  @_)); }
76
77 sub audiotype { return "mp3";         }
78 sub haspic    { return undef;         } # NEXTVERSION
79
80 sub v1genre
81 {
82     my($self, $val)=@_;
83     if($val)
84     {
85         $self->{mp3}->new_tag("ID3v1") unless(defined($self->{mp3}->{ID3v1}));
86         $self->{mp3}->{ID3v1}->genre($val);
87         return $val;
88     }
89     my $genre=undef;
90     $genre=$self->{ID3v1}->genre() if(defined($self->{ID3v1}));
91     return $genre;
92 }
93
94 sub tags
95 {
96     my $self=shift;
97     return() unless(exists($self->{mp3}->{ID3v2}) && defined($self->{mp3}->{ID3v2}));
98     return($self->{mp3}->{ID3v2}->genre());
99 }
100
101 sub get_tags
102 {
103     my ($self)=@_;
104     # MP3::Tag->get_tags shows cryptic debug info via print when it finds
105     # an unhandled id3v2 version, in addition to the warning, so use
106     # select to send prints to /dev/null
107     my $oldout=undef;
108     if(open(NULL,">/dev/null"))
109     {
110         $oldout=select(NULL);
111     }
112     eval { $self->{mp3}->get_tags; };
113     warn("$self->{path}: $@\n") if($@);
114     if(defined($oldout))
115     {
116         select($oldout);
117         close(NULL);
118     }
119 }
120
121 sub write
122 {
123     my $self=shift;
124     $self->{mp3}->update_tags();
125 }
126
127 1;