#!/usr/bin/perl 

#               mymusic-update
# purpose:  update mymusic's sql database of songs
# version: 1.0.6 
# author: caffiend <caffiend@dioxin.com>
# date: May 23 2001 
#
# this program is distributed under the terms of the GNU Public License.
# this program is part of the mymusic distribution, available at 
# <URL: http://www.dioxin.com/~caffiend/mymusic/>
# 


@mp3dirs = ("/music","/music2");		    	# change this to the directory
					# where your mp3s are!

$host = "localhost";			# these are the default
$user = "mymusic";			# edit as necessary if 
$passwd = "mymusic";			# you changed these during
$db = "mymusic";			# installation



####################### nothing configurable below this line...


use DBI;
use MPEG::MP3Info;


$dbh =
DBI->connect("DBI:mysql:$db:$host",$user,$passwd,{mysql_client_found_rows => 1} )
	or die "can't connect to database!!!";

my $added = 0;
my $deleted = 0;
$| = 1;


printf "Building comparison lists...\n";

$on_disk = build_on_disk(@mp3dirs);

$in_db = build_in_db();

#check for songs in database, but not on disk
foreach $file (keys %$in_db) 
{
  push(@to_delete,$file) unless exists $on_disk->{$file};
}

foreach $file (keys %$on_disk)
{
  push(@to_add,$file) unless exists $in_db->{$file};
}

foreach $file (@to_delete)
{
  delfile($file);
  $deleted++;
}

foreach $file (@to_add)
{
  addfile($file);
  $added++;
}

$sth->finish();
$dbh->disconnect();

printf "Added %d songs, deleted %d\nDone.\n",$added,$deleted;

sub delfile {
   my $query;
   my $sth;
   my $song;
   my $row;

   $query = sprintf " SELECT songs.artist AS artist_id, songs.album AS album_id, albums.name AS album, 
		artists.name AS aritst FROM songs,artists,albums WHERE songs.filename = %s 
		AND songs.artist = artists.id AND albums.id = songs.album",
		$dbh->quote($file);
   $sth = $dbh->prepare($query);
   $sth->execute();
   $row = $sth->fetchrow_hashref();

   $query = sprintf "SELECT songs.filename FROM songs WHERE songs.artist=%s AND songs.album=%s AND filename != %s",
   $dbh->quote($row->{artist_id}),$dbh->quote($row->{album_id}),
		$dbh->quote($row->{$file});
   $rv = $dbh->do($query) or die "can't do $query: $dbh->errstr";
   
    if ($rv == 0)
    {
      printf "No more songs by %s from the album %s. Deleting album\n",
		$row->{artist},$row->{album};
      $query = sprintf "DELETE FROM albums WHERE albums.id = %s",
		$dbh->quote($row->{album_id});
      $dbh->do($query) or die "can't do $query: $dbh->errstr";
    }
    
    $query = sprintf "SELECT songs.filename FROM songs WHERE songs.artist = %s",
		$dbh->quote($row->{artist_id});
    $rv = $dbh->do($query) or die "Can't do $query: $dbh->errstr";

    if ($rv == 0)
    {
      printf "No more songs by %s. Deleting...\n",$row->{artist};
      $query = sprintf "DELETE FROM artists WHERE artists.id = %s",
		$dbh->quote($row->{artist_id});
      $dbh->do($query) or die "can't do $query: $dbh->errstr";
    }

   $query = sprintf "DELETE FROM songs WHERE filename=%s",
		$dbh->quote($file);
   $dbh->do($query)
	or die "can't do $query: $dbh->errstr\n";

   $deleted++;
}

sub addfile {
  $file = shift;
  return unless -f $file;

  my $info = get_mp3info($file);
  my $tag = get_mp3tag($file);

  $num = 0;
  $num = $file;
  $num =~ s/.*\/(\d*).*/$1/;
  if ( $num == "0" ) { $num = 0; }
  $length = sprintf "%d:%d",$info->{MM}, $info->{SS};

  $query = sprintf "SELECT id FROM artists WHERE name=%s",
		$dbh->quote($tag->{ARTIST});
  $rv = $dbh->do($query) or die "can't do $query: $dbh->errstr\n";

  ### add artist, if doesn't exist
  if ($rv == 0) {
    printf "Adding $tag->{ARTIST}...";
    $query = sprintf "INSERT INTO artists VALUES (0,%s)",
		$dbh->quote($tag->{ARTIST});
    $rv = $dbh->do($query) or die "can't do $query: $dbh->errstr\n";
    printf "Done.\n";
  }

  ###fetch artist id
  $query = sprintf "SELECT id FROM artists WHERE name = %s",
		$dbh->quote($tag->{ARTIST});
  $sth = $dbh->prepare($query);
  $sth->execute();
  $artist_id = $sth->fetchrow_array();
  $sth->finish;

  ### check album
  $query = sprintf "SELECT id FROM albums WHERE artist = %s AND name = %s",
		$dbh->quote($artist_id),$dbh->quote($tag->{ALBUM});
  $rv = $dbh->do($query);

  ## Add album if not existing
    if ($rv == 0) {
        printf "Adding $tag->{ARTIST} | $tag->{ALBUM}...";
        $query = sprintf "INSERT INTO albums VALUES (0,%s,%s)",
		$dbh->quote($artist_id),$dbh->quote($tag->{ALBUM});
        $rv = $dbh->do($query) or die "can't do $query: $dbh->errstr";
    printf "Done.\n"
    }
    ### Get id for album 
    $query = sprintf "SELECT id FROM albums WHERE name = %s AND artist=%s",
		$dbh->quote($tag->{ALBUM}),$dbh->quote($artist_id);
    $sth=$dbh->prepare($query);
    $rv = $sth->execute();
    $album_id = $sth->fetchrow_array(); 
    $sth->finish;

    printf "\tAdding $tag->{ARTIST} | $tag->{ALBUM} | $tag->{TITLE}...";
    $query = sprintf "INSERT INTO songs VALUES (0,%s,%s,%s,%s,%s,%s,0,%s)",
		$dbh->quote($artist_id),
		$dbh->quote($album_id),
		$dbh->quote($tag->{TITLE}),
		$dbh->quote($tag->{COMMENT}),,
		$dbh->quote($file),
		$dbh->quote($length),
		$dbh->quote($num);
	$rv = $dbh->do($query) or die "can't do $query: $dbh->errstr";
	printf "Done.\n";
}

sub build_on_disk {
  #build hash of files on disk
  @dir_list = @mp3dirs;
  my $file;
  my %hash;

  foreach $dir (@dir_list) {
    printf "looking in directory %s...\n",$dir;
    foreach $file (`find $dir/ -type f -follow -name '*.mp3'`)
      {
   	chomp $file;
  	$hash{$file} = 1;
      }
   }
  return \%hash;
}

sub build_in_db() {

  my %hash = ();
  $query = sprintf "SELECT filename FROM songs ORDER BY filename ASC";
  $sth = $dbh->prepare($query);
  $sth->execute;
  while ( $row = $sth->fetchrow_hashref )
  {
    $hash{$row->{filename}} = 1;
  }

  return \%hash;

}
