id3fs-tag: -V: summarize tags in directories
[id3fs.git] / lib / ID3FS / AudioFile / Mp3.pm
index d51e0b0..8ec87ef 100644 (file)
@@ -18,7 +18,9 @@ package ID3FS::AudioFile::Mp3;
 
 use strict;
 use warnings;
+use ID3FS::AudioFile;
 use MP3::Tag;
+use MP3::Info;
 
 sub new
 {
@@ -28,7 +30,8 @@ sub new
     bless($self,$class);
 
     $self->{path}=shift;
-    $self->{mp3}=MP3::Tag->new($self->{path});
+    $self->{mp3tag}=MP3::Tag->new($self->{path});
+    $self->{mp3info}=MP3::Info->new($self->{path});
     $self->get_tags();
     $self->{tags}={};
 
@@ -39,16 +42,16 @@ sub set
 {
     my ($self, $func, $value)=@_;
     return $self->choose($func) unless($value);
-    unless(exists($self->{mp3}->{ID3v1}))
+    unless(exists($self->{mp3tag}->{ID3v1}))
     {
-       $self->{mp3}->new_tag("ID3v1");
+       $self->{mp3tag}->new_tag("ID3v1");
     }
-    unless(exists($self->{mp3}->{ID3v2}))
+    unless(exists($self->{mp3tag}->{ID3v2}))
     {
-       $self->{mp3}->new_tag("ID3v2");
+       $self->{mp3tag}->new_tag("ID3v2");
     }
     my $method=$func . "_set";
-    $self->{mp3}->$method($value, 1);
+    $self->{mp3tag}->$method($value, 1);
     return $value;
 }
 
@@ -56,34 +59,54 @@ sub choose
 {
     my($self, $func)=@_;
     my $thing=undef;
-    if(exists($self->{mp3}->{ID3v2}))
+    if(exists($self->{mp3tag}->{ID3v2}))
     {
-       $thing=$self->{mp3}->{ID3v2}->$func();
+       $thing=$self->{mp3tag}->{ID3v2}->$func();
     }
-    if(exists($self->{mp3}->{ID3v1}) && (!defined($thing) || !length($thing)))
+    if(exists($self->{mp3tag}->{ID3v1}) && (!defined($thing) || !length($thing)))
     {
-       $thing=$self->{mp3}->{ID3v1}->$func();
+       $thing=$self->{mp3tag}->{ID3v1}->$func();
     }
     return $thing;
 }
 
-sub year      { return(shift->set("year",     @_)); }
-sub artist    { return(shift->set("artist",   @_)); }
-sub album     { return(shift->set("album",    @_)); }
-sub track     { return(shift->set("title",    @_)); }
-sub tracknum  { return(shift->set("track",    @_)); }
-sub comment   { return(shift->set("comment",  @_)); }
+sub year      { return(shift->set("year",    @_)); }
+sub artist    { return(shift->set("artist",  @_)); }
+sub album     { return(shift->set("album",   @_)); }
+sub track     { return(shift->set("title",   @_)); }
+sub tracknum  { return(shift->set("track",   @_)); }
+sub comment   { return(shift->set("comment", @_)); }
 
 sub audiotype { return "mp3";         }
 sub haspic    { return undef;         } # NEXTVERSION
 
+# we only set v2 genre
+sub genre
+{
+    my ($self, $value)=@_;
+    if($value)
+    {
+       if(exists($self->{mp3tag}->{ID3v2}))
+       {
+           $self->{mp3tag}->{ID3v2}->remove_frame("TCON");
+       }
+       else
+       {
+           $self->{mp3tag}->new_tag("ID3v2");
+       }
+       $self->{mp3tag}->{ID3v2}->add_frame("TCON", $value);
+
+    }
+    return($self->{mp3tag}->{ID3v2}->genre());
+}
+
 sub v1genre
 {
     my($self, $val)=@_;
     if($val)
     {
-       $self->{mp3}->new_tag("ID3v1") unless(defined($self->{mp3}->{ID3v1}));
-       $self->{mp3}->{ID3v1}->genre($val);
+       $self->{mp3tag}->new_tag("ID3v1") unless(defined($self->{mp3tag}->{ID3v1}));
+       $self->{mp3tag}->{ID3v1}->genre($val);
        return $val;
     }
     my $genre=undef;
@@ -94,8 +117,8 @@ sub v1genre
 sub tags
 {
     my $self=shift;
-    return() unless(exists($self->{mp3}->{ID3v2}) && defined($self->{mp3}->{ID3v2}));
-    return($self->{mp3}->{ID3v2}->genre());
+    return() unless(exists($self->{mp3tag}->{ID3v2}) && defined($self->{mp3tag}->{ID3v2}));
+    return($self->{mp3tag}->{ID3v2}->genre());
 }
 
 sub get_tags
@@ -109,7 +132,7 @@ sub get_tags
     {
        $oldout=select(NULL);
     }
-    eval { $self->{mp3}->get_tags; };
+    eval { $self->{mp3tag}->get_tags; };
     warn("$self->{path}: $@\n") if($@);
     if(defined($oldout))
     {
@@ -123,16 +146,52 @@ sub add_tags
     my($self, @tags)=@_;
     my $existing=$self->tags();
     my @existing=split(/\s*,\s*/, $existing) if($existing);
-    my @merged=$self->uniq(@tags, @existing);
+    my @merged=ID3FS::AudioFile::uniq(@tags, @existing);
     my $genre=join(', ', @merged);
     return($self->set("genre", $genre));
 }
 
-
 sub write
 {
     my $self=shift;
-    $self->{mp3}->update_tags();
+    if(exists($self->{mp3tag}->{ID3v1}))
+    {
+       my $del=1;
+       my $artist=$self->{mp3tag}->{ID3v1}->artist();
+       $del=0 if($artist && $artist =~ /\S+/);
+       my $album=$self->{mp3tag}->{ID3v1}->album();
+       $del=0 if($album && $album =~ /\S+/);
+       my $track=$self->{mp3tag}->{ID3v1}->title();
+       $del=0 if($track && $track =~ /\S+/);
+       my $tracknum=$self->{mp3tag}->{ID3v1}->track();
+       $del=0 if($tracknum && $tracknum !~ /^0+$/);
+       my $genre=$self->{mp3tag}->{ID3v1}->genre();
+       $del=0 if($genre && $genre =~ /\S+/);
+       my $comment=$self->{mp3tag}->{ID3v1}->comment();
+       $del=0 if($comment && $comment =~ /\S+/);
+       my $year=$self->{mp3tag}->{ID3v1}->year();
+       $del=0 if($year && $year =~ /\S+/ && $year !~ /^0+$/);
+       if($del)
+       {
+           $self->{mp3tag}->{ID3v1}->remove_tag;
+       }
+       else
+       {
+           $self->{mp3tag}->{ID3v1}->write_tag;
+       }
+    }
+    if(exists($self->{mp3tag}->{ID3v2}))
+    {
+       my $frames=$self->{mp3tag}->{ID3v2}->get_frame_ids();
+       if($frames && scalar(keys(%$frames)))
+       {
+           $self->{mp3tag}->{ID3v2}->write_tag;
+       }
+       else
+       {
+           $self->{mp3tag}->{ID3v2}->remove_tag;
+       }
+    }
 }
 
 sub delete_artist   { shift->delete("artist");  }
@@ -146,14 +205,24 @@ sub delete_genre    { shift->delete("genre");   }
 
 sub delete_tags
 {
-    my($self, @tags)=@_;
+    my($self, $tags, $delvals)=@_;
     my $current=$self->tags();
     my @current=split(/\s*,\s*/, $current);
+    my @tags=split(/\s*,\s*/, $tags);
     my %hash=();
     @hash{@current}=();
     for my $tag (@tags)
     {
        delete($hash{$tag}) if(exists($hash{$tag}));
+       if($delvals)
+       {
+           my $base=($tag =~ /(.*?)\//)[0];
+           $base=$tag unless($base);
+           for my $curtag (keys %hash)
+           {
+               delete($hash{$curtag}) if($curtag =~ /^$base\//);
+           }
+       }
     }
     my @tagsout=sort keys(%hash);
     my $genre=join(', ', @tagsout);
@@ -170,13 +239,13 @@ sub delete_tags
 sub delete_all
 {
     my($self)=@_;
-    if(exists($self->{mp3}->{ID3v1}))
+    if(exists($self->{mp3tag}->{ID3v1}))
     {
-       $self->{mp3}->{ID3v1}->remove_tag;
+       $self->{mp3tag}->{ID3v1}->remove_tag;
     }
-    if(exists($self->{mp3}->{ID3v2}))
+    if(exists($self->{mp3tag}->{ID3v2}))
     {
-       $self->{mp3}->{ID3v2}->remove_tag;
+       $self->{mp3tag}->{ID3v2}->remove_tag;
     }
 }
 
@@ -184,62 +253,75 @@ sub delete
 {
     my($self, $thing)=@_;
 
-    if(exists($self->{mp3}->{ID3v1}) && $thing ne "genre")
+    if(exists($self->{mp3tag}->{ID3v1}) && $thing ne "genre")
     {
        my $action=$thing;
        $action="genre" if($action eq "v1genre");
        if($action eq "track")
        {
-           $self->{mp3}->{ID3v1}->track("00");
+           $self->{mp3tag}->{ID3v1}->track("00");
        }
        else
        {
-           $self->{mp3}->{ID3v1}->$action(" ");
+           $self->{mp3tag}->{ID3v1}->$action(" ");
        }
     }
 
-    if(exists($self->{mp3}->{ID3v2}))
+    if(exists($self->{mp3tag}->{ID3v2}))
     {
-       print "2: remove: $thing\n";
        if($thing eq "artist")
        {
-           $self->{mp3}->{ID3v2}->remove_frame("TPE1");
-           $self->{mp3}->{ID3v2}->remove_frame("TPE2");
+           $self->{mp3tag}->{ID3v2}->remove_frame("TPE1");
+           $self->{mp3tag}->{ID3v2}->remove_frame("TPE2");
        }
        elsif($thing eq "album")
        {
-           $self->{mp3}->{ID3v2}->remove_frame("TALB");
+           $self->{mp3tag}->{ID3v2}->remove_frame("TALB");
        }
        elsif($thing eq "song")
        {
-           $self->{mp3}->{ID3v2}->remove_frame("TIT2");
+           $self->{mp3tag}->{ID3v2}->remove_frame("TIT2");
        }
        elsif($thing eq "track")
        {
-           $self->{mp3}->{ID3v2}->remove_frame("TRCK");
+           $self->{mp3tag}->{ID3v2}->remove_frame("TRCK");
        }
        elsif($thing eq "year")
        {
-           $self->{mp3}->{ID3v2}->remove_frame("TYER");
-           $self->{mp3}->{ID3v2}->remove_frame("TDRC");
+           $self->{mp3tag}->{ID3v2}->remove_frame("TYER");
+           $self->{mp3tag}->{ID3v2}->remove_frame("TDRC");
        }
        elsif($thing eq "comment")
        {
-           $self->{mp3}->{ID3v2}->remove_frame("COMM");
+           $self->{mp3tag}->{ID3v2}->remove_frame("COMM");
        }
        elsif($thing eq "genre")
        {
-           $self->{mp3}->{ID3v2}->remove_frame("TCON");
+           $self->{mp3tag}->{ID3v2}->remove_frame("TCON");
        }
     }
 }
 
-sub uniq
+
+sub channels
+{
+    my($self)=@_;
+    return undef unless($self->{mp3info});
+    return( ($self->{mp3info}->stereo()) ? 2 : 1 );
+}
+
+sub bitrate
 {
-    my ($self, @things)=@_;
-    my %hash=();
-    @hash{@things}=();
-    return(sort keys(%hash));
+    my($self)=@_;
+    return undef unless($self->{mp3info});
+    return( int($self->{mp3info}->bitrate()) );
+}
+
+sub samplerate
+{
+    my($self)=@_;
+    return undef unless($self->{mp3info});
+    return(int($self->{mp3info}->frequency() * 1000));
 }