#!/usr/bin/perl

#+------------------------------------------------------------------------+
#|                                                                        |
#| id32m3u -- by greenfly <greenfly@greenfly.org>                         |
#|                                                                        |
#| usage: id32m3u [--archos] <dir> [<dir2>...]                            |
#|                                                                        |
#| This script reads the id3 tags of any MP3s it finds in the directories |
#| it is passed, and then creates a Playlist directory containing         |
#| m3u files in an Artist and Album structure.                            |
#|                                                                        |
#| if the script is passed the --archos option it will format a playlist  |
#| suitable for an archos mp3 player                                      |
#|                                                                        |
#+------------------------------------------------------------------------+

use MP3::Tag;
use File::Find;
use File::Path;
use File::Copy;
use String::Approx qw(amatch);
use Cwd;
use strict;

@ARGV = ('.') unless @ARGV;

my $starting_dir = getcwd();
our %tags;
my $artist;
my $album;
my $track;
our $last_path = "";
our $archos;


sub process_mp3
{
	my $mp3;
	my $filename = $_;
	next unless($filename =~ /\.mp3$/i);
	my $full_file_path = $File::Find::name;
	my ($title, $track, $artist, $album, $comment, $year, $genre) = 0;
	print "$File::Find::dir\n" if($last_path ne $File::Find::dir);
	$last_path = $File::Find::dir;
	$mp3 = MP3::Tag->new($filename) or next;

	($title, $track, $artist, $album, $comment, $year, $genre) = $mp3->autoinfo();

	$artist =~ s/^The\s*//g;

	$title =~ s/([A-Za-z0-9']+)/\u\L$1/g;
	$track =~ s/([A-Za-z0-9']+)/\u\L$1/g;
	$artist =~ s/([A-Za-z0-9']+)/\u\L$1/g;
	$album =~ s/([A-Za-z0-9']+)/\u\L$1/g;
	$genre =~ s/([A-Za-z0-9']+)/\u\L$1/g;

	$tags{$full_file_path}{'title'} = $title;
	$tags{$full_file_path}{'track'} = $track;
	$tags{$full_file_path}{'artist'} = $artist;
	$tags{$full_file_path}{'album'} = $album;
	$tags{$full_file_path}{'comment'} = $comment;
	$tags{$full_file_path}{'year'} = $year;
	$tags{$full_file_path}{'genre'} = $genre;
	$tags{$full_file_path}{'filename'} = $filename;

#	print "$tags{$full_file_path}{'title'} ";
#	print "$tags{$full_file_path}{'track'} ";
#	print "$tags{$full_file_path}{'artist'} ";
#	print "$tags{$full_file_path}{'album'} ";
#	print "$tags{$full_file_path}{'comment'} ";
#	print "$tags{$full_file_path}{'year'} ";
#	print "$tags{$full_file_path}{'genre'} ";
#	print "$tags{$full_file_path}{'filename'} ";
#	print "\n";
#        print "$artist " if(lc($last_artist) ne lc($artist));
#	$last_artist = $artist;
}

# process all the directories passed as arguments
$| = 1;
print "Processing: ";
foreach(@ARGV)
{
   if($_ eq "--archos"){$archos = "/Music/"; next;}
   print "$_ ";
   find(\&process_mp3, $_);
}
print " Finished Processing\n";

prune_artists();

# recreate the directory structure
move("Playlists", "Playlists.bak");
mkdir "Playlists";
chdir "Playlists";
mkdir "Artists";
mkdir "Albums";
foreach $artist (list_artists())
{
   next if($artist eq "");
	mkdir "Artists/$artist";
	open ALLARTISTS, ">> Artists/\ ALL.m3u";
	open ALLALBUMS, ">> Albums/\ ALL.m3u";
	open ALLARTISTSALBUM, ">> Artists/$artist/\ ALL.m3u";
	foreach $track (tracks_for_artist($artist))
	{
	   next if($track eq "");
	   print ALLARTISTS "$archos$track\n";
	   print ALLARTISTSALBUM "$archos$track\n";
	}
	foreach $album (albums_for_artist($artist))
	{
	   open ARTISTSALBUM, ">> Artists/$artist/$album.m3u";
	   open ALBUMS, ">> Albums/$album.m3u";
	   foreach $track (tracks_for_album($album))
	   {
	      next if($track eq "");
	      print ALLALBUMS "$archos$track\n";
	      print ARTISTSALBUM "$archos$track\n";
	      print ALBUMS "$archos$track\n";
	   }
	   close ALBUMS;
	   close ARTISTSALBUM;
	}
	close ALLARTISTSALBUM;
	close ALLALBUMS;
	close ALLARTIST;
}
chdir($starting_dir);
rmtree("Playlists.bak");

sub prune_artists
{
   my %artists = {};
   my $artist;
   my @matches;
   my $dist;
   foreach(sort keys %tags)
   {
      $artist = "";
      @matches = ();
      $artist = $tags{$_}{'artist'};
      next if($artist =~ /^.?$/);


      @matches = amatch($artist, ['i 10%'], keys %artists);
      if(defined $matches[0]){$artist = $matches[0]}

      $tags{$_}{'artist'} = $artist;
      $artists{$artist}++;
   }
}

sub list_artists
{
   my %artists;
   my $artist;
   my $matched;
   foreach(keys %tags)
   {
      $artist = $tags{$_}{'artist'};
      next if($artist eq "");
      $artists{$artist} = 1;
   }
   return sort keys %artists;
}

sub albums_for_artist
{
   my $artist = shift;
   my %albums;
   my $confirmed_artist;
   foreach(keys %tags)
   {
      $confirmed_artist = $tags{$_}{'artist'};

      #if(amatch("$artist", $confirmed_artist))
      if($artist eq $confirmed_artist)
      {
	 next if($tags{$_}{'album'} eq "");
	 $albums{$tags{$_}{'album'}} = 1;
      }
   }
   return sort keys %albums;
}

sub tracks_for_album
{
   my $album = shift;
   return if($album eq "");
   my @tracks;
   foreach(keys %tags)
   {
      if($tags{$_}{'album'} =~ /^\Q$album\E$/i)
      {
	 if($tags{$_}{'track'} ne "")
	 {
	    $tracks[$tags{$_}{'track'}] =  $_;
	 }
	 else
	 {
	    push(@tracks, $_);
	 }
      }

   }
   return @tracks;
}

sub tracks_for_artist
{
   my $artist = shift;
   return if($artist eq "");
   my @tracks;
   my $confirmed_artist;
   foreach(keys %tags)
   {
      $confirmed_artist = $tags{$_}{'artist'};

      #if(amatch($artist, $confirmed_artist))
      if($artist eq $confirmed_artist)
      {
	 push(@tracks, $_);
      }
   }
   return sort @tracks;
}

sub by_artist
{
   $tags{$a}{'artist'} cmp $tags{$b}{'artist'}
   or
   $tags{$a}{'year'} <=> $tags{$b}{'year'}
   or
   $tags{$a}{'album'} cmp $tags{$b}{'album'}
   or
   $tags{$a}{'track'} <=> $tags{$b}{'track'}
   or
   $tags{$a}{'title'} cmp $tags{$b}{'title'}
   or
   $a cmp $b;
}

