id3fs-tag: -V: summarize tags in directories
[id3fs.git] / bin / id3fs-tag
index 28b4b6a..6bff1c4 100755 (executable)
 use lib '/home/ianb/projects/id3fs/id3fs/lib'; # FIXME: remove
 use strict;
 use Getopt::Long qw(Configure);
+use File::Find;
 use ID3FS::AudioFile;
 use vars qw($me);
 $me=($0=~/(?:.*\/)?(.*)/)[0];
 
+my @extensions=qw(mp3); # FIXME:  flac ogg
+my (%argv_tags, %dir_tags, %file_tags);
+my $current_argv;
 my $verbose=0;
 my $help=0;
 my ($artist, $album, $track, $tracknum, $year, $v1genre, $comment,
     $delete_artist, $delete_album, $delete_track, $delete_tracknum,
     $delete_year, $delete_v1genre, $delete_comment, $delete_all,
     $delete_genre, $genre, $add_tags, $delete_tags, $overwrite_tagvals,
-    $delete_tagvals);
+    $delete_tagvals, $tag_summary);
 
 Configure(qw(bundling no_ignore_case));
 my $optret=GetOptions(
@@ -56,29 +60,51 @@ my $optret=GetOptions(
     "overwrite-tagvals|tagvals|o=s"  => \$overwrite_tagvals,
     "delete-tags|T=s"                => \$delete_tags,
     "delete-tags-with-values|O=s"    => \$delete_tagvals,
+    "summary|V"                      => \$tag_summary,
     );
 
 usage() if(!@ARGV || !$optret || $help);
 
-while(my $filename=shift @ARGV)
+while(my $path=shift @ARGV)
 {
-    unless(-f $filename)
+    unless(-e $path)
     {
-       warn("$me: $filename: not found\n");
+       warn("$me: $path: not found\n");
        next;
     }
-    my $file=ID3FS::AudioFile->new($filename);
-    next unless($file);
-    my $changes=0;
-    $changes =  do_deletes($file);
-    $changes += do_adds($file);
-    if($changes)
-    {
-       do_write($file);
-    }
-    else
+    $current_argv=$path; # ick, global nastiness
+    File::Find::find( {wanted => \&wanted, follow => 1, no_chdir => 1}, $path);
+}
+
+summarize_tags() if($tag_summary);
+
+
+sub wanted
+{
+    my $ext='';
+    if(/.*\.(.*)/) { $ext=lc($1); }
+    if(-f && scalar(grep({ $ext eq lc($_);} @extensions)))
     {
-       do_display($file);
+       my $file=ID3FS::AudioFile->new($_);
+       return unless($file);
+       if($tag_summary)
+       {
+           gather_tags($_, $file);
+       }
+       else
+       {
+           my $changes=0;
+           $changes =  do_deletes($file);
+           $changes += do_adds($file);
+           if($changes)
+           {
+               do_write($file);
+           }
+           else
+           {
+               do_display($file);
+           }
+       }
     }
 }
 
@@ -177,6 +203,49 @@ sub do_display
     }
 }
 
+sub gather_tags
+{
+    my($path, $file)=@_;
+    my @tags=$file->tags();
+    @tags=map { join('/', grep { defined; } @$_); } @tags;
+    @tags=ID3FS::AudioFile::uniq(@tags);
+    $file_tags{$path}=\@tags;
+    my @argv_tags=();
+    @argv_tags=@{$argv_tags{$current_argv}} if($argv_tags{$current_argv});
+    $argv_tags{$current_argv}=[ ID3FS::AudioFile::uniq(@tags, @argv_tags) ];
+}
+
+sub summarize_tags
+{
+    my @all_tags=ID3FS::AudioFile::uniq(map { @$_; } values(%argv_tags));
+    # find common tags
+    my @common_tags=();
+OUTER: for my $tag (@all_tags)
+    {
+       for my $taglist (values(%argv_tags))
+       {
+           next OUTER unless(grep { $_ eq $tag; } @$taglist);
+       }
+       push(@common_tags, $tag);
+    }
+    print "ALL: ",    join(', ', @all_tags), "\n";
+    print "COMMON: ", join(', ', @common_tags), "\n";
+
+    use Data::Dumper;
+    # remove common tags from %argv_tags
+    for my $argv (keys(%argv_tags))
+    {
+       next unless(@{$argv_tags{$argv}});
+       $argv_tags{$argv}= [ ID3FS::AudioFile::list_remove(\@common_tags, $argv_tags{$argv}) ];
+    }
+
+    print "PER-DIR: \n";
+    for my $argv (keys(%argv_tags))
+    {
+       print "$argv: ", join(', ', @{$argv_tags{$argv}}), "\n";
+    }
+}
+
 sub usage
 {
     die("Usage: $me [-vhALSNY0CDG] [-a ARTIST] [-l ALBUM] [-s SONG] [-n TRACKNUM] FILES...\n".