#!/usr/bin/perl
# Filename:	oggmv
# Author:	David Ljung <dljung>
# Description:	Moves an ogg file according to its vorbiscomment tags
use strict;

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

my $MODE	= 0755;	# Dir permissions
my $ILL_CHARS	= '\s~()!*?\"\'\/';

##################################################
# Usage
##################################################
sub usage {
  my $msg;
  foreach $msg (@_) { print "ERROR:  $msg\n"; }
  print "\n";
  print "Usage:\t$PROGNAME [-d] [-v] <ogg> ..\n";
  print "\tMoves an ogg file according to its vorbiscomment tags\n";
  print "\t-v\tSet verbose mode\n";
  print "\t-d\tSet debug mode\n";
  print "\n";
  exit -1;
}

sub parse_args {
  my @oggs;
  my $arg;
  while ($#ARGV>=0) {
    $arg=shift(@ARGV);
    if ($arg =~ /^-h$/) { usage(); }
    if ($arg =~ /^-d$/) { $MAIN::DEBUG=1; next; }
    if ($arg =~ /^-v$/) { $MAIN::VERBOSE=1; next; }
    if ($arg =~ /^-/) { usage("Unknown option: $arg"); }
    push(@oggs,$arg);
  }
  usage("No oggs defined") if (!@oggs);

  @oggs;
}

sub clean {
  my ($str) = @_;

  $str =~ s/\s+$//;
  $str =~ s|/|-|g;
  $str =~ s/[$ILL_CHARS]/_/g;
  $str =~ s/_+/_/g;
  $str =~ s/_+$//; $str =~ s/^_+//;
  $str =~ s/\-+/\-/g;
  $str =~ s/\-+$//; $str =~ s/^\-+//;
  $str;
}

##################################################
# Main code
##################################################
sub main {
  my (@oggs) = parse_args();

  foreach my $ogg ( @oggs ) {
    if (! -f $ogg) {
      print STDERR "[$PROGNAME] Warning:  Couldn't find ogg [$ogg]\n";
      next;
    }

    # Get ogg tags
    open(TAGS,"vorbiscomment \Q$ogg\E |") || die("[$PROGNAME] Couldn't run vorbiscomment [$ogg]\n");
    my %i;
    ($i{title},$i{artist},$i{album},$i{note}) = ("unknown","unknown","unknown");
    while(<TAGS>) {
      chomp;
      next if /^\s*$/;
      die("[$PROGNAME] Bad vorbiscomment: [$_]") unless /^(\S+)=(.*)$/;
      my ($key,$val) = (lc($1),clean($2));
      $i{$key} = $val;
    }
    close(TAGS);

    if ($i{artist} eq "unknown" || ($i{title} eq "unknown" && $i{album} eq "unknown")) {
      print STDERR "[$PROGNAME] Error:  No vorbiscomment for ogg [$ogg]\n";
      next;
    }
    print STDERR "[$PROGNAME] Warning:  Missing vorbiscomment for ogg [$ogg]\n"
      if ($i{title} eq "unknown" || $i{artist} eq "unknown" || $i{album} eq "unknown");

    # PATH:  <artist>/<album>/<title>.ogg
    # Make the directories
    (-d $i{artist}) || mkdir($i{artist},$MODE)
      || die("[$PROGNAME] Couldn't make directory [$i{artist}]\n");
    (-d "$i{artist}/$i{album}") || mkdir("$i{artist}/$i{album}",$MODE)
      || die("[$PROGNAME] Couldn't make directory [$i{artist}/$i{album}]\n");

    my $file = $i{tracknumber} ?
      sprintf("$i{artist}/$i{album}/%0.2d-$i{title}.ogg",$i{tracknumber}) :
      "$i{artist}/$i{album}/$i{title}.ogg";
    if (-f $file) {
      print STDERR "[$PROGNAME]  ERROR: $file already exists.\n";
      next;
    }

    # Move it
    system("/bin/mv \"$ogg\" \"$file\"");
    if ($?) {
      print STDERR "[$PROGNAME]  ERROR: $file already exists.\n";
    } else {
      print "$ogg -> $file\n" if ($MAIN::VERBOSE);
    }
  }
} main();
