#!/usr/bin/perl -w
###################################################

use AmazonMusicImage;
use File::Find;
use LWP::UserAgent;
use Image::Info qw(image_info dim);
use Getopt::Std;
use File::Spec;

use strict;

my %options;
my %seen;

if (!getopts('m:di:e:', \%options)|| !%options ) {
  help();
}
my $top = $options{m} || help();
my $debug = $options{d};
my $file_name = $options{i} || "cover.jpg";
if ($file_name !~ /\.jpg$/) {
  print "\nFile name must end with .jpg\n";
  exit;
}
my $exclude = $options{e} || "tmp|lost+found|Misc. Live";
$|++;

# Calls the main workflow --
find(\&wanted, $top);


##### Sub here #####

sub help {
  print qq(
Usage: $0 -m "/path/to/music/dir" [options]
Options are:
\t-m path\t\tFull path to the top of your music hierarchy. 
\t\t\tTHIS OPTION IS REQUIRIED
\t-i image_name\tFile name to save album cover as. Default: cover.jpg
\t-d\t\tTurn on verbose debugging
\t-e\t\tDirectories to exclude seperated by a "|".
\t\t\tUse just the dir name, not the full path
\t\t\t(i.e. "temporary directory|dir to skip" etc.)
	  );
  print "\n";
  exit;
}

sub wanted {
  my $image;
  my $dir = $File::Find::dir;
  if ($seen{$dir}) {
    return;
  }
  # Mark that we've been here. No point doing a dir twice
  $seen{$dir} = 1;
  if ($dir =~ /$exclude/i) {
    print "\nExcluding $dir\n" if ($debug);
    return;
  }
#  print "#" if (!$debug);
  opendir(DIR, $dir) || die "can't opendir $dir: $!";
  # Grab any file that doesn't start with a .
  my @files = grep {/^[^\.]/ && -f File::Spec->catfile("$dir",$_)} readdir(DIR);
  return if $#files < 0;
  closedir(DIR);
  # If there's not a cover here already
  if (!(grep {/$file_name/i} @files)) {
    # We only want music file with extensions we recognize
    warn "Now looking in: $dir\n" if ($debug);
    @files = getMatchingExts(@files);
    return if ($#files < 0);
    my $track = getTrackNum('1',@files);
    #print "res: $track\n";
    my $lbp = rindex( $dir, '/' );
    my $album = substr( $dir, $lbp+1 );
    my $year = substr($album,0,4);
    my $delim = substr($album,4,1);
    if (($delim =~ /_/) && (isnum($year))) { 
       $album = substr( $album, 5 ); 
    } 
    return if ( $album =~ /various/i );
    my $slbp = rindex( $dir, '/', $lbp-1 );
    my $artist = substr( $dir, $slbp+1, $lbp-$slbp-1 );

    my $various = 0;
    if ( $artist =~ /various/i ) {
       $various = 1;
       my $sp = rindex( $track, ' - ' );
       if ($sp) {
          $artist = substr($track,0,$sp);
          $track = substr($track,$sp+3); 
       }
    }

    my $a = new AmazonMusicImage(debug=>$debug);
    # Start by trying to get the large size image
    # If it's not there, ask for smaller sized images
    # We have to fetch the image each time because we have no
    # way of knowing about a place-holder image until we look at it
    my @urls = $a->get_url($artist,$album,$track,$various);
    foreach my $url (@urls) {
       $image = get_image($url);
       if ($image) {
          last;
       }
    }
#    if (!$image) {
#      $url = $a->get_url($tag, size=>"Medium", var=>"$various");
#      $image = get_image($url) if $url;
#    }
#    if (!$image) {
#      $url = $a->get_url($tag, size=>"Small", var=>"$various");
#      $image = get_image($url) if $url;
#    }
    if ($image) {
      open(FOO,">$file_name") || die "Could not open cover.jpg in $dir for writing! $!\n";
      # In case we're on Windows or
      # on a perl build that thinks everything should be
      # UTF-8 text
      binmode(FOO); 
      print FOO $image;
      close FOO || warn "\nCould not write to $file_name!: $!\n";
    }
  }
  else {
     warn "Image file already exists in $dir\n" if ($debug);
  }
}

sub get_image {
  my $url = shift;
  if (! $url) {
     return;
  }
  my $image;
  my $ua = LWP::UserAgent->new;
  my $req = HTTP::Request->new(GET=>$url);
  my $res = $ua->request($req);
  if ($res->is_success) {
     $image =  $res->content;
  } else {
    warn  "\nCould not download image file for $url\n" if ($debug);
    return;
  }

  my $info = image_info(\$image);
  my ($h, $w) = dim($info);
  if (($h == 1) && ($w == 1)) {
    # Sometimes Amazon gives us a 1x1 gif if it could not find the picture
    warn  "\n1x1 image found. Moving on\n" if ($debug);
    return;
  }
  return $image;
}

# Code blatantly stolen from Slim/Music/Info.pm


sub getMatchingExts {
   my @tags = ('mp3', 'mp2', 'ogg', 'flc', 'flac', 'wav', 'aif', 'wma', 'mov', 'm4a', 'shn', 'mpc');
   my @files = @_;
   my @files2;
   foreach my $file(@files) {
      for my $ext(@tags) {
         if ($file =~ /\.$ext$/) {
            push(@files2,( $file =~ /(.*)\.$ext$/ )); 
         }
      }
   }
   return @files2;
}

sub getTrackNum {
   my $num = shift;
   my @files = @_;
   foreach my $file(@files) {
      my $tag = substr($file,0,2);
      my $delim = substr($file,2,1);
      if (($delim =~ /_/) && (isnum($tag)) && ($tag = $num)) { 
         return substr( $file, 3 ); 
      } 
   }
   return $files[$num-1];
}

sub isnum {

   # -- NAME: isnum
   #
   # -- PURPOSE: Determine whether the argument is numeric
   #
   # -- CALLING SEQUENCE:
   #
   # #-# $numeric = &isnum ( $x );
   # #-# i -- $x = string or number to be inspected
   # #-# o -- $numeric = 1 if $x is numeric; = 0 otherwise
   #
   # -- DISCUSSION:
   #
   # Uses a rather complicated regexp to determine whether a specified
   # string could be interpreted as a number. Source:
   # Aho, Kernighan, Weinberger, "The AWK Programming Language",
   # Addison Wesley, October 1988, p.30.
   #
   # -- EXAMPLE:
   #
   # $i = &isnum ( '1.ed3' );
   # $j = &isnum ( '1.e+3' );
   # # return $i = 0 and $j = 1
   #
   # -- END

   my $x = shift;
   my $s;

   if ( $x =~ /^[+-]?(\d+[.]?\d*|[.]\d+)([Ee][+-]?\d+)?$/ ) {
      $s = 1;
   } else {
      $s = 0;
   }

   $s;

} 
