#!/usr/bin/php
<?php /*

Copyright (C) 2005 Martin Furter, Ram Yalamanchili

This file is part of Ices2Web

Ices2Web is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.

Ices2Web is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Ices2Web; see the file COPYING.  If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.

------------------------------------------------------------------------------*/

include( "db.php" );
include( "cfg.php" );


function printarray( $name, $array )
{
	echo "<h3>$name</h3>\n";
	echo "<pre>\n";
	reset( $array );
	while( list($k,$v) = each( $array ) )
	{
		echo "$k = $v\n";
	}
	echo "</pre>\n";
}

function str_to_sql( $str )
{
	if( $str == "" )
	{
		return "null";
	}
	else
	{
		return "'" . pg_escape_string( $str ) . "'";
	}
}

function number_to_sql( $number )
{
	if( $number == "" )
	{
		return "null";
	}
	else
	{
		return $number;
	}
}

function epoch_to_sql( $epoch )
{
	if( $epoch == "" )
	{
		return "null";
	}
	else
	{
		return "to_timestamp( '" . strftime( $GLOBALS["strftimefmt"], $epoch ) .
				"', " . $GLOBALS["datefmt"] . " )";
	}
}

function db_remove( $conn, $reldir, $name, $type )
{
	// echo "db_remove $type '$reldir/$name'\n";
	if( $name == "" )
	{
		return;
	}
	$sql =	"delete from " .
				"ices2_oggfiles " .
			" where " .
				"iof_directory = " . str_to_sql( $reldir ) . " and " .
				"iof_name = " . str_to_sql( $name );
	// echo "SQL <$sql>\n";
	pg_exec( $conn, $sql );
	if( $type == "dir" )
	{
		if( $reldir == "/" )
		{
			$dir = $name;
		}
		else
		{
			$dir = $reldir . "/" . $name;
		}
		$dirlen = strlen($dir) + 1;
		$dir = pg_escape_string( $dir );
		$sql =	"delete from " .
					"ices2_oggfiles " .
				"where " .
					"iof_directory = '$dir' or " .
					"substr( iof_directory, 1, $dirlen ) = '$dir/'";
		// echo "SQL <$sql>\n";
		pg_exec( $conn, $sql );
	}
}

function db_insert( $conn, $reldir, $name, $props )
{
	$type = $props["type"];
	// echo "db_insert $type '$reldir/$name'\n";
	if( $type == "file" )
	{
		$sql =	"insert into ices2_oggfiles ( " .
					"iof_directory, " .
					"iof_name, " .
					"iof_is_file, " .
					"iof_title, " .
					"iof_artist, " .
					"iof_album, " .
					"iof_track_nr, " .
					"iof_genre, " .
					"iof_length, " .
					"iof_bitrate, " .
					"iof_filesize, " .
					"iof_date_mod " .
				") values ( " .
					str_to_sql( $reldir ) . ", " .
					str_to_sql( $name ) . ", " .
					"true, " .
					str_to_sql( $props["title"] ) . ", " .
					str_to_sql( $props["artist"] ) . ", " .
					str_to_sql( $props["album"] ) . ", " .
					str_to_sql( $props["track"] ) . ", " .
					str_to_sql( $props["genre"] ) . ", " .
					number_to_sql( $props["length"] ) . ", " .
					number_to_sql( $props["bitrate"] ) . ", " .
					number_to_sql( $props["filesize"] ) . ", " .
					epoch_to_sql( $props["date_mod"] ) .
				" )";
	}
	else
	{
		$sql =	"insert into ices2_oggfiles ( " .
					"iof_directory, " .
					"iof_name, " .
					"iof_is_file " .
				") values ( " .
					str_to_sql( $reldir ) . ", " .
					str_to_sql( $name ) . ", " .
					"false " .
				" )";
	}
	pg_exec( $conn, $sql );
}

function db_update_file( $conn, $reldir, $name, $props )
{
	$type = $props["type"];
	// echo "db_update_file $type '$reldir/$name'\n";
	if( $type != "file" )
	{
		return;
	}
	$sql =	"update " .
				"ices2_oggfiles " .
			"set" .
				"  iof_title = " . str_to_sql( $props["title"] ) .
				", iof_artist = " . str_to_sql( $props["artist"] ) .
				", iof_album = " . str_to_sql( $props["album"] ) .
				", iof_track_nr = " . str_to_sql( $props["track"] ) .
				", iof_genre = " . str_to_sql( $props["genre"] ) .
				", iof_length = " . number_to_sql( $props["length"] ) .
				", iof_bitrate = " . number_to_sql( $props["bitrate"] ) .
				", iof_filesize = " . number_to_sql( $props["filesize"] ) .
				", iof_date_mod = " . epoch_to_sql( $props["date_mod"] ) .
			" where " .
				"iof_directory = " . str_to_sql( $reldir ) . " and " .
				"iof_name = " . str_to_sql( $name );
	// echo "SQL <$sql>\n";
	pg_exec( $conn, $sql );
}

function get_db_dir( $conn, $reldir )
{
	$dir = array();
	$sql =	"select " .
				"iof_name, " .
				"iof_is_file, " .
				"iof_title, iof_artist, iof_album, iof_track_nr, " .
				"iof_genre, iof_length, iof_bitrate, iof_filesize, " .
				"extract(epoch from iof_date_mod) as iof_date_mod " .
			"from " .
				"ices2_oggfiles " .
			"where ".
				"iof_directory = '" . pg_escape_string($reldir) . "'";
	$rs = pg_exec( $conn, $sql );
	if( $rs )
	{
		while( $row = pg_fetch_array( $rs ) )
		{
			$node = array();
			if( $row["iof_is_file"]== "t" )
			{
				$node["type"] = "file";
				// echo "db file '$name'\n";
			}
			else
			{
				$node["type"] = "dir";
				// echo "db dir  '$name'\n";
			}
			$node["title"] = $row["iof_title"];
			$node["artist"] = $row["iof_artist"];
			$node["album"] = $row["iof_album"];
			$node["track"] = $row["iof_track_nr"];
			$node["genre"] = $row["iof_genre"];
			$node["length"] = $row["iof_length"];
			$node["bitrate"] = $row["iof_bitrate"];
			$node["filesize"] = $row["iof_filesize"];
			$node["date_mod"] = $row["iof_date_mod"];
			$dir[$row["iof_name"]] = $node;
		}
	}
	return $dir;
}

function get_ogg_info( $absfile, &$props )
{
	$lines = array();
	exec( "ogginfo " . escapeshellarg( $absfile ), $lines, $rc );
	if( $rc != 0 )
	{
		return;
	}
	$n = count($lines);
	$i = 0;
	while( $i < $n && !ereg( "^Nominal bitrate: ", $lines[$i] ) )
	{
		$i++;
	}
	if( $i >= $n ) return;
	$tmp = split( "  *", $lines[$i] );
	$props["bitrate"] = ereg_replace( "[.].*\$", "", $tmp[2] );
	while( $i < $n && !ereg( "^User comments section follows", $lines[$i] ) )
	{
		$i++;
	}
	$i++;
	if( $i >= $n ) return;
	while( $i < $n && ereg( "^\t[a-z][a-z]*=", $lines[$i] ) )
	{
		$tmp = split( "=", trim( $lines[$i] ), 2 );
		switch( $tmp[0] )
		{
			case "genre":
				$props["genre"] = $tmp[1];
				break;
			case "title":
				$props["title"] = $tmp[1];
				break;
			case "artist":
				$props["artist"] = $tmp[1];
				break;
			case "album":
				$props["album"] = $tmp[1];
				break;
			// tracknum ???
		}
		$i++;
	}
	while( $i < $n && !ereg( "^\tPlayback length: ", $lines[$i] ) )
	{
		$i++;
	}
	if( $i >= $n ) return;
	$tmp = split( "  *", $lines[$i] );
	$tmp = split( ":", $tmp[2] );
	$tn = count($tmp);
	$i = 0;
	$secs = 0;
	while( $i < $tn )
	{
		switch( substr( $tmp[$i], strlen($tmp[$i])-1 ) )
		{
			case "h":
				$secs += 3600 * substr( $tmp[$i], 0, strlen($tmp[$i])-1 );
				break;
			case "m":
				$secs += 60 * substr( $tmp[$i], 0, strlen($tmp[$i])-1 );
				break;
			case "s":
				$secs += ereg_replace( "[.m].*\$", "", $tmp[$i] );
				break;
		}
		$i++;
	}
	$props["length"] = $secs;
}

function get_fs_dir( $reldir, $music_dir )
{
	$absdir = $music_dir . "/" . $reldir;
	$dir = array();
	if( is_dir( $absdir ) )
	{
		$dh = opendir( $absdir );
		if( $dh )
		{
			while( $name = readdir( $dh ) )
			{
				if( substr( $name, 0, 1 ) != "." )
				{
					$node = array( "indb" => false );
					if( is_dir( $absdir . "/" . $name ) )
					{
						$node["type"] = "dir";
						// echo "fs dir  '$name'\n";
					}
					else if( is_file( $absdir . "/" . $name ) &&
							ereg( "[.]ogg\$", $name ) )
					{
						$abspath = $absdir . "/" . $name;
						$node["type"] = "file";
						$node["filesize"] = filesize( $abspath );
						$node["date_mod"] = filemtime( $abspath );
						// echo "fs file '$name'\n";
					}
					if( isset( $node["type"] ) )
					{
						$dir[$name] = $node;
					}
				}
			}
			closedir( $dh );
		}
	}
	return $dir;
}

function scan_files( $conn, $reldir, $music_dir )
{
	echo "*** directory '$reldir' ***\n";
	$dbfiles = get_db_dir( $conn, $reldir );
	$fsfiles = get_fs_dir( $reldir, $music_dir );
	reset( $dbfiles );
	while( list( $name, $props ) = each( $dbfiles ) )
	{
		if( !isset( $fsfiles[$name] ) )
		{
			echo "    removed '$name'\n";
			db_remove( $conn, $reldir, $name, $props["type"] );
		}
		else if( $fsfiles[$name]["type"] != $props["type"] )
		{
			echo "    mismatch '$name'\n";
			db_remove( $conn, $reldir, $name, $props["type"] );
		}
		else
		{
			if( $props["type"] == "file" &&
				( $fsfiles[$name]["date_mod"] != $props["date_mod"] ||
				  $fsfiles[$name]["filesize"] != $props["filesize"] ) )
			{
				echo "    modified '$name'\n";
				// echo "        " . $props["date_mod"] . "\n";
				// echo "        " . $fsfiles[$name]["date_mod"] . "\n";
				$props["date_mod"] = $fsfiles[$name]["date_mod"];
				$props["filesize"] = $fsfiles[$name]["filesize"];
				if( $reldir == "/" )
				{
					$abspath = $music_dir . "/" . $name;
				}
				else
				{
					$abspath = $music_dir . "/" . $reldir . "/" . $name;
				}
				get_ogg_info( $abspath, $props );
				db_update_file( $conn, $reldir, $name, $props );
			}
			$fsfiles[$name]["indb"] = true;
		}
	}
	reset( $fsfiles );
	while( list( $name, $props ) = each( $fsfiles ) )
	{
		if( $reldir == "/" )
		{
			$newreldir = $name;
			$abspath = $music_dir . "/" . $name;
		}
		else
		{
			$newreldir = $reldir . "/" . $name;
			$abspath = $music_dir . "/" . $reldir . "/" . $name;
		}
		if( !$props["indb"] )
		{
			echo "    added '$name'\n";
			if( $props["type"] == "file" )
			{
				get_ogg_info( $abspath, $props );
			}
			db_insert( $conn, $reldir, $name, $props );
		}
		if( $props["type"] == "dir" )
		{
			scan_files( $conn, $newreldir, $music_dir );
		}
	}
}

// printarray( "_SERVER", $_SERVER );

if( !isset( $_SERVER["SERVER_SOFTWARE"] ) )
{
	$conn = db_connect();
	scan_files( $conn, "/", $music_dir );
}


?>