#!/usr/bin/perl
# Filename:	mztool
# Author:	David Ljung Madison <DaveSource.com>
# See License:	http://MarginalHacks.com/License
# Description:	Wrapper to id3tool and vorbiscomment - but uses
#		the nicer interface of id3tool
use strict;

##################################################
# Setup the variables
##################################################
my $PROGNAME = $0;
$PROGNAME =~ s|.*/||;

my $MP3TOOL = "id3tool";
my $OGGTOOL = "vorbiscomment";

my $EDITOR = $ENV{EDITOR} || "vi";
my $TMP = "/tmp/$PROGNAME.$$";

##################################################
# Usage
##################################################
sub usage {
  foreach my $msg (@_) { print STDERR "\nERROR:  $msg\n"; }
  print STDERR "Usage:\t$PROGNAME [id3tool options] <mp3 or ogg files>\n";
  print STDERR "\tEdits mp3s or oggs, using the id3tool interface:\n\n";
  print STDERR <<END_INTERFACE;
  -t, --set-title=WORD          Sets the title to WORD
  -a, --set-album=WORD          Sets the album to WORD
  -r, --set-artist=WORD         Sets the artist to WORD
  -y, --set-year=YEAR           Sets the year to YEAR [4 digits]
  -n, --set-note=WORD           Sets the note to WORD
  -G, --set-genre-word=WORD     Sets the genre to WORD
  -#, --set-track=WORD          Sets the track number to WORD
END_INTERFACE
  print STDERR "\n";
  print STDERR "Optional -v flag will edit ogg comments with $EDITOR\n";
  exit -1;
}

sub debug {
  return unless $MAIN::DEBUG;
  foreach my $msg (@_) { print STDERR "[$PROGNAME] $msg\n"; }
}

##################################################
# Main code
##################################################
my %OGGARGS;
sub add_long {
  my ($l,$val) = @_;

  $l = lc($l);

  return $OGGARGS{title}=$val if $l eq "title";
  return $OGGARGS{album}=$val if $l eq "album";
  return $OGGARGS{artist}=$val if $l eq "artist";
  return $OGGARGS{date}=$val if $l eq "year";
  return push(@{$OGGARGS{description}},$val) if $l eq "note";
  return $OGGARGS{genre}=$val if $l eq "genre-word";
  return $OGGARGS{tracknumber}=$val if $l eq "track";
  die("Can't handle -g/--genre, sorry") if $l eq "genre";
  usage("Unknown --set-$l??\n")
}

sub add_short {
  my ($s,$val) = @_;
  return add_long("title",$val) if ($s eq "t");
  return add_long("album",$val) if ($s eq "a");
  return add_long("artist",$val) if ($s eq "r");
  return add_long("year",$val) if ($s eq "y");
  return add_long("note",$val) if ($s eq "n");
  return add_long("genre",$val) if ($s eq "g");
  return add_long("genre-word",$val) if ($s eq "G");
  return add_long("track",$val) if ($s eq "#");
}

sub main {
  my @files;
  my %args;
  my $editor;

  my @argcopy = @ARGV;

  # Read args
  while (my $arg=shift(@ARGV)) {
    if ($arg =~ /^-h$/) { usage(); }
    if ($arg =~ /^-d$/) { $MAIN::DEBUG=1; next; }
    if ($arg =~ /^-v$/) { $editor=1; next; }
    if ($arg =~ /^-([taryngG#])$/) { add_short($1,shift(@ARGV)); next; }
    if ($arg =~ /^--set-([^=]+)=(.+)$/) { add_long($1,$2); next; }
    if ($arg =~ /^-/ && !-f $arg) { usage("Unknown option: $arg"); }
    push(@files,$arg);
  }
  usage("No files specified") unless @files;

  $OGGARGS{description}=join(" ",@{$OGGARGS{description}})
    if $OGGARGS{description};

  foreach my $file ( @files ) {
    usage("Unknown file? [$file]\n") unless -f $file;
  }

  # Figure out type
  my ($ogg,$mp3);
  $ogg=1 if (grep(/\.ogg$/i, @files));
  $mp3=1 if (grep(/\.mp3$/i, @files));

  usage("Can't specify ogg *and* mp3 files") if $ogg && $mp3;

  usage("-v flag is only for ogg files") if $editor && $mp3;

  usage("Can't specify tag info with -v flag") if $editor && %OGGARGS;

  if ($ogg) {
    foreach my $file ( @files ) {
      print STDERR "  $file\n";
      if ($editor) {
        debug("[$editor $file]");
        system("$OGGTOOL $file > $TMP");
        system("$EDITOR $TMP");
        system("$OGGTOOL -w $file -c $TMP");
        unlink($TMP);
      } elsif (!%OGGARGS) {
        debug("[$OGGTOOL $file]");
        system("$OGGTOOL $file");
      } else {
        # Read in current comments
        my %args = %OGGARGS;
        open(OGG,"$OGGTOOL $file|") or usage("Can't read ogginfo [$OGGTOOL $file]\n");
        while(<OGG>) {
          $args{$1}=$2 if (/([^=]+)=(.+)/) && !$OGGARGS{$1};
        }
        close OGG;

        # Build up comment list and do it..
        my @args = qw(-w);
        map { push(@args,"-t","$_=$args{$_}") } keys %args;
        debug("[$OGGTOOL @args $file]");
        my $pid = fork;
        exec($OGGTOOL,@args,$file) if $pid==0;
        die("Couldn't fork?: $!\n") unless $pid;
        wait;
      }
    }
  } else {
    my @mp3args;
    while (my $arg=shift(@argcopy)) {
      if ($arg =~ /^-(#|-set-track=(.+))$/) {
        my $tr = $2 ? $2 : shift(@argcopy);
        usage("Track should be a number? [$tr]\n") unless $tr =~ /^\d+$/;
        push(@mp3args,"-n","Track #$tr");
      } else {
        push(@mp3args,$arg);
      }
    }
    debug("[$MP3TOOL @mp3args]");
    exec($MP3TOOL,@mp3args);
  }
}
main();
