id = intval($catalog_id);
/* Get the information from the db */
$info = $this->_get_info();
foreach ($info as $key=>$value) {
$this->$key = $value;
}
} //constructor
/**
* _get_info
* get's the vars for $this out of the database requires an id
*/
private function _get_info() {
/* Grab the basic information from the catalog and return it */
$sql = "SELECT * FROM `catalog` WHERE `id`='$this->id'";
$db_results = Dba::query($sql);
$results = Dba::fetch_assoc($db_results);
return $results;
} // _get_info
/**
* _create_filecache
* This poplates an array (filecache) on this object from the database
* it is used to speed up the add process
*/
private function _create_filecache() {
if (count($this->_filecache) == 0) {
$catalog_id = Dba::escape($this->id);
// Get _EVERYTHING_
$sql = "SELECT `id`,`file` FROM `song` WHERE `catalog`='$catalog_id'";
$db_results = Dba::query($sql);
// Populate the filecache
while ($results = Dba::fetch_assoc($db_results)) {
$this->_filecache[strtolower($results['file'])] = $results['id'];
}
} // end if empty filecache
} // _create_filecache
/**
* format
* This makes the object human readable
*/
public function format() {
$this->f_name = truncate_with_ellipsis($this->name,Config::get('ellipse_threshold_title'));
$this->f_name_link = '' . scrub_out($this->f_name) . '';
$this->f_path = truncate_with_ellipsis($this->path,Config::get('ellipse_threshold_title'));
$this->f_update = $this->last_update ? date('d/m/Y h:i',$this->last_update) : _('Never');
$this->f_add = $this->last_add ? date('d/m/Y h:i',$this->last_add) : _('Never');
} // format
/**
* get_catalogs
* Pull all the current catalogs and return an array of ids
* of what you find
*/
public static function get_catalogs() {
$sql = "SELECT `id` FROM `catalog` ORDER BY `name`";
$db_results = Dba::query($sql);
$results = array();
while ($row = Dba::fetch_assoc($db_results)) {
$results[] = $row['id'];
}
return $results;
} // get_catalogs
/**
* get_catalog_ids
* This returns an array of all catalog ids
*/
public static function get_catalog_ids() {
$sql = "SELECT `id` FROM `catalog`";
$db_results = Dba::query($sql);
while ($r = Dba::fetch_assoc($db_results)) {
$results[] = $r['id'];
}
return $results;
} // get_catalog_ids
/**
* get_stats
* This returns an hash with the #'s for the different
* objects that are assoicated with this catalog. This is used
* to build the stats box, it also calculates time
*/
public static function get_stats($catalog_id=0) {
$results = self::count_songs($catalog_id);
$results = array_merge(self::count_users($catalog_id),$results);
$hours = floor($results['time']/3600);
$size = $results['size']/1048576;
$days = floor($hours/24);
$hours = $hours%24;
$time_text = "$days ";
$time_text .= ngettext('day','days',$days);
$time_text .= ", $hours ";
$time_text .= ngettext('hour','hours',$hours);
$results['time_text'] = $time_text;
if ($size > 1024) {
$total_size = sprintf("%.2f",($size/1024));
$size_unit = "GB";
}
else {
$total_size = sprintf("%.2f",$size);
$size_unit = "MB";
}
$results['total_size'] = $total_size;
$results['size_unit'] = $size_unit;
return $results;
} // get_stats
/**
* clear_stats
* This clears all stats for _everything_
*/
public static function clear_stats() {
/* Whip out everything */
$sql = "TRUNCATE `object_count`";
$db_results = Dba::query($sql);
$sql = "UDPATE `song` SET `player`='0'";
$db_results = Dba::query($sql);
return true;
} // clear_stats
/**
* create
* This creates a new catalog entry and then returns the insert id
* it checks to make sure this path is not already used before creating
* the catalog
*/
public static function create($data) {
// Clean up the path just incase
$data['path'] = rtrim(rtrim(trim($data['path']),'/'),'\\');
$path = Dba::escape($data['path']);
// Make sure the path is readable/exists
if (!is_readable($data['path']) AND $data['type'] == 'local') {
Error::add('general','Error: ' . scrub_out($data['path']) . ' is not readable or does not exist');
return false;
}
// Make sure this path isn't already in use by an existing catalog
$sql = "SELECT `id` FROM `catalog` WHERE `path`='$path'";
$db_results = Dba::query($sql);
if (Dba::num_rows($db_results)) {
Error::add('general','Error: Catalog with ' . $path . ' already exists');
return false;
}
$name = Dba::escape($data['name']);
$catalog_type = Dba::escape($data['type']);
$rename_pattern = Dba::escape($data['rename_pattern']);
$sort_pattern = Dba::escape($data['sort_pattern']);
$gather_types = ' '; //FIXME
$key = Dba::escape($data['key']);
if (!$key) { $key = ' '; } //FIXME
// Ok we're good to go ahead and insert this record
$sql = "INSERT INTO `catalog` (`name`,`path`,`add_path`,`catalog_type`,`rename_pattern`,`sort_pattern`,`gather_types`,`key`) " .
"VALUES ('$name','$path','','$catalog_type','$rename_pattern','$sort_pattern','$gather_types','$key')";
$db_results = Dba::query($sql);
$insert_id = Dba::insert_id();
if (!$insert_id) {
Error::add('general','Catalog Insert Failed check debug logs');
debug_event('catalog','SQL Failed:' . $sql,'3');
return false;
}
return $insert_id;
} // create
/**
* run_add
* This runs the add to catalog function
* it includes the javascript refresh stuff and then starts rolling
* throught the path for this catalog
*/
public function run_add($options) {
if ($this->catalog_type == 'remote') {
show_box_top(_('Running Remote Sync') . '. . .');
$this->get_remote_catalog($type=0);
show_box_bottom();
return true;
}
// Catalog Add start
$start_time = time();
require Config::get('prefix') . '/templates/show_adds_catalog.inc.php';
flush();
// Prevent the script from timing out and flush what we've got
set_time_limit(0);
$this->add_files($this->path,$options);
return true;
} // run_add
/**
* count_songs
* This returns the current # of songs, albums, artists, genres
* in this catalog
*/
public static function count_songs($catalog_id='') {
if ($catalog_id) { $catalog_search = "WHERE `catalog`='" . Dba::escape($catalog_id) . "'"; }
$sql = "SELECT COUNT(`id`),SUM(`time`),SUM(`size`) FROM `song` $catalog_search";
$db_results = Dba::query($sql);
$data = Dba::fetch_row($db_results);
$songs = $data['0'];
$time = $data['1'];
$size = $data['2'];
$sql = "SELECT COUNT(DISTINCT(`album`)) FROM `song` $catalog_search";
$db_results = Dba::query($sql);
$data = Dba::fetch_row($db_results);
$albums = $data['0'];
$sql = "SELECT COUNT(DISTINCT(`artist`)) FROM `song` $catalog_search";
$db_results = Dba::query($sql);
$data = Dba::fetch_row($db_results);
$artists = $data['0'];
$sql = "SELECT COUNT(DISTINCT(`genre`)) FROM `song` $catalog_search";
$db_results = Dba::query($sql);
$data = Dba::fetch_row($db_results);
$genres = $data['0'];
$results['songs'] = $songs;
$results['albums'] = $albums;
$results['artists'] = $artists;
$results['genres'] = $genres;
$results['size'] = $size;
$results['time'] = $time;
return $results;
} // count_songs
/**
* count_users
* This returns the total number of users in the ampache instance
*/
public static function count_users($catalog_id='') {
// Count total users
$sql = "SELECT COUNT(id) FROM `user`";
$db_results = Dba::query($sql);
$data = Dba::fetch_row($db_results);
$results['users'] = $data['0'];
// Get the connected users
$time = time();
$last_seen_time = $time - 1200;
$sql = "SELECT count(DISTINCT s.username) FROM session AS s " .
"INNER JOIN user AS u ON s.username = u.username " .
"WHERE s.expire > " . $time . " " .
"AND u.last_seen > " . $last_seen_time;
$db_results = Dba::query($sql);
$data = Dba::fetch_row($db_results);
$results['connected'] = $data['0'];
return $results;
} // count_users
/*!
@function add_file
@discussion adds a single file
*/
function add_file($filename) {
$file_size = filesize($filename);
$pattern = "/\.[" . conf('catalog_file_pattern') . "]$/i";
if ( preg_match($pattern ,$filename) && ($file_size > 0) && (!preg_match('/\.AppleDouble/', $filename)) ) {
if(!$this->check_local_mp3($filename,$gather_type)) {
$this->insert_local_song($filename,$file_size);
}
debug_event('add_file', "Error: File exists",'2','ampache-catalog');
} // if valid file
debug_event('add_file', "Error: File doesn't match pattern",'2','ampache-catalog');
} // add_file
/**
* add_files
* Recurses throught $this->path and pulls out all mp3s and returns the full
* path in an array. Passes gather_type to determin if we need to check id3
* information against the db.
*/
public function add_files($path,$options) {
// Correctly detect the slash we need to use here
if (strstr($path,"/")) {
$slash_type = '/';
}
else {
$slash_type = '\\';
}
/* Open up the directory */
$handle = opendir($path);
if (!is_resource($handle)) {
debug_event('read',"Unable to Open $path",'5','ampache-catalog');
Error::add('catalog_add',_('Error: Unable to open') . ' ' . $path);
return false;
}
/* Change the dir so is_dir works correctly */
if (!chdir($path)) {
debug_event('read',"Unable to chdir $path",'2','ampache-catalog');
Error::add('catalog_add',_('Error: Unable to change to directory') . ' ' . $path);
return false;
}
// Ensure that we've got our cache
$this->_create_filecache();
/* Recurse through this dir and create the files array */
while ( false !== ( $file = readdir($handle) ) ) {
/* Skip to next if we've got . or .. */
if ($file == '.' || $file == '..') { continue; }
debug_event('read',"Starting work on $file inside $path",'5','ampache-catalog');
/* Create the new path */
$full_file = $path.$slash_type.$file;
/* First thing first, check if file is already in catalog.
* This check is very quick, so it should be performed before any other checks to save time
*/
if (isset($this->_filecache[strtolower($full_file)])) {
continue;
}
// Incase this is the second time through clear this variable
// if it was set the day before
unset($failed_check);
if (Config::get('no_symlinks')) {
if (is_link($full_file)) {
debug_event('read',"Skipping Symbolic Link $path",'5','ampache-catalog');
continue;
}
}
/* If it's a dir run this function again! */
if (is_dir($full_file)) {
$this->add_files($full_file,$options);
/* Change the dir so is_dir works correctly */
if (!chdir($path)) {
debug_event('read',"Unable to chdir $path",'2','ampache-catalog');
Error::add('catalog_add',_('Error: Unable to change to directory') . ' ' . $path);
}
/* Skip to the next file */
continue;
} //it's a directory
/* If it's not a dir let's roll with it
* next we need to build the pattern that we will use
* to detect if it's a audio file for now the source for
* this is in the /modules/init.php file
*/
$pattern = "/\.(" . Config::get('catalog_file_pattern');
if ($options['parse_m3u']) {
$pattern .= "|m3u)$/i";
}
else {
$pattern .= ")$/i";
}
/* see if this is a valid audio file or playlist file */
if (preg_match($pattern ,$file)) {
/* Now that we're sure its a file get filesize */
$file_size = filesize($full_file);
if (!$file_size) {
debug_event('read',"Unable to get filesize for $full_file",'2','ampache-catalog');
Error::add('catalog_add',_('Error: Unable to get filesize for') . ' ' . $full_file);
} // file_size check
if (!is_readable($full_file)) {
// not readable, warn user
debug_event('read',"$full_file is not readable by ampache",'2','ampache-catalog');
Error::add('catalog_add',"$full_file " . _('is not readable by ampache'));
continue;
}
// Check to make sure the filename is of the expected charset
if (function_exists('iconv')) {
if (strcmp($full_file,iconv(Config::get('site_charset'),Config::get('site_charset') . '//IGNORE',$full_file)) != '0') {
debug_event('read',$full_file . ' has non-' . Config::get('site_charset') . ' characters and can not be indexed','1');
Error::add('catalog_add',$full_file . ' ' . _('does not match site charset'));
continue;
}
} // end if iconv
if (substr($file,-3,3) == 'm3u' AND $parse_m3u > 0) {
$this->_playlists[] = $full_file;
} // if it's an m3u
else {
$this->insert_local_song($full_file,$file_size);
/* Stupid little cutesie thing */
$this->count++;
if ( !($this->count%10)) {
$file = str_replace(array('(',')','\''),'',$full_file);
echo "\n";
flush();
} // update our current state
} // if it's not an m3u
} //if it matches the pattern
else {
debug_event('read',"$full_file ignored, non audio file or 0 bytes",'5','ampache-catalog');
} // else not an audio file
} // end while reading directory
debug_event('closedir',"Finished reading $path closing handle",'5','ampache-catalog');
// This should only happen on the last run
if ($path == $this->path) {
echo "\n";
flush();
}
/* Close the dir handle */
@closedir($handle);
} // add_files
/*!
@function get_albums
@discussion This gets albums for all songs passed in an array
*/
function get_albums($songs=array()) {
foreach ($songs as $song_id) {
$sql = "SELECT album FROM song WHERE id='$song_id'";
$db_results = mysql_query($sql, dbh());
$results = mysql_fetch_array($db_results);
$albums[] = new Album($results[0]);
} // files
return $albums;
} // get_albums
/**
* get_album_ids
* This returns an array of ids of albums that have songs in this
* catalog
*/
public function get_album_ids() {
$id = Dba::escape($this->id);
$results = array();
$sql = "SELECT DISTINCT(song.album) FROM `song` WHERE `song`.`catalog`='$id'";
$db_results = Dba::query($sql);
while ($r = Dba::fetch_assoc($db_results)) {
$results[] = $r['album'];
}
return $results;
} // get_album_ids
/**
* get_album_art
* This runs through all of the needs art albums and trys
* to find the art for them from the mp3s
*/
public function get_album_art($catalog_id=0,$all='') {
// Make sure they've actually got methods
$album_art_order = Config::get('album_art_order');
if (empty($album_art_order)) {
return true;
}
// Prevent the script from timing out
set_time_limit(0);
// If not passed use this
$catalog_id = $catalog_id ? $catalog_id : $this->id;
if ($all) {
$albums = $this->get_album_ids();
}
else {
$albums = array_keys(self::$_art_albums);
}
// Run through them an get the art!
foreach ($albums as $album_id) {
// Create the object
$album = new Album($album_id);
// We're going to need the name here
$album->format();
debug_event('gather_art','Gathering art for ' . $album->name,'5');
// Define the options we want to use for the find art function
$options = array(
'album_name' => $album->full_name,
'artist' => $album->artist_name,
'keyword' => $album->artist_name . ' ' . $album->full_name
);
// Return results
$results = $album->find_art($options,1);
if (count($results)) {
// Pull the string representation from the source
$image = get_image_from_source($results['0']);
if (strlen($image) > '5') {
$album->insert_art($image,$results['0']['mime']);
}
else {
debug_event('album_art','Image less then 5 chars, not inserting','3');
}
$art_found++;
}
/* Stupid little cutesie thing */
$search_count++;
if ( !($search_count%5)) {
echo "\n";
flush();
} //echos song count
unset($found);
} // foreach albums
// One last time for good measure
echo "\n";
flush();
self::$_art_albums = array();
} // get_album_art
/**
* get_catalog_albums()
* Returns an array of the albums from a catalog
*/
public static function get_catalog_albums($catalog_id) {
$results = array();
$sql = "SELECT DISTINCT(`song`.`album`) FROM `song` WHERE `song`.`catalog`='$catalog_id'";
$db_results = Dba::query($sql);
while ($row = Dba::fetch_assoc($db_results)) {
$results[] = $row['album'];
}
return $results;
} // get_catalog_albums
/**
* get_catalog_files
* Returns an array of song objects from a catalog, used by sort_files script
*/
public function get_catalog_files($catalog_id=0) {
$results = array();
/* Use $this->id if nothing passed */
$catalog_id = $catalog_id ? Dba::escape($catalog_id) : Dba::escape($this->id);
$sql = "SELECT `id` FROM `song` WHERE `catalog`='$catalog_id' AND `enabled`='1'";
$db_results = Dba::query($sql);
$results = array(); // return an emty array instead of nothing if no objects
while ($r = Dba::fetch_assoc($db_results)) {
$results[] = new Song($r['id']);
} //end while
return $results;
} //get_catalog_files
/**
* get_disabled
* Gets an array of the disabled songs for all catalogs
* and returns full song objects with them
*/
public static function get_disabled($count=0) {
$results = array();
if ($count) { $limit_clause = " LIMIT $count"; }
$sql = "SELECT id FROM song WHERE enabled='0' $limit_clause";
$db_results = Dba::query($sql);
while ($r = Dba::fetch_assoc($db_results)) {
$results[] = new Song($r['id']);
}
return $results;
} // get_disabled
/*!
@function get_files
@discussion Get's an array of .mp3s and returns the filenames
@param $path Get files starting at root $path
*/
function get_files($path) {
/* Set it as an empty array */
$files = array();
/* Open up the directory */
$handle = @opendir($path);
if (!is_resource($handle)) { echo "" . _("Error: Unable to open") . " $path
\n"; }
/* Change dir so we can tell if it's a directory */
if (!@chdir($path)) {
echo "Error: Unable to change to $path directory
\n";
}
// Determine the slash type and go from there
if (strstr($path,"/")) {
$slash_type = '/';
}
else {
$slash_type = '\\';
}
/* Recurse through this dir and create the files array */
while ( FALSE !== ($file = @readdir($handle)) ) {
$full_file = $path . $slash_type . $file;
/* Incase this is the second time through, unset it before checking */
unset($failed_check);
if (conf('no_symlinks')) {
if (is_link($full_file)) { $failed_check = true; }
}
/* It's a dir */
if (is_dir($full_file) AND $file != "." AND $file != ".." AND !$failed_check) {
/* Merge the results of the get_files with the current results */
$files = array_merge($files,$this->get_files($full_file));
} //isdir
/* Get the file information */
$file_info = filesize($full_file);
$pattern = "/\.[" . conf('catalog_file_pattern') . "]$/i";
// REMOVE SECOND PREG_MATCH
if ( preg_match($pattern ,$file) && ($file_info > 0) && (!preg_match("/\.AppleDouble/", $file)) ) {
$files[] = $full_file;
} //is mp3 of at least some size
} //end while
/* Close the dir handle */
@closedir($handle);
/* Return the files array */
return $files;
} //get_files
/**
* get_duplicate_songs
* This function takes a search type and returns a list of all song_ids that
* are likely to be duplicates based on teh search method selected.
*/
public static function get_duplicate_songs($search_method) {
$where_sql = '';
if (!$_REQUEST['search_disabled']) {
$where_sql = 'WHERE enabled!=\'0\'';
}
// Setup the base SQL
$sql = "SELECT song.id AS song,artist.id AS artist,album.id AS album,title,COUNT(title) AS ctitle".
" FROM `song` LEFT JOIN `artist` ON `artist`.`id`=`song`.`artist` " .
" LEFT JOIN `album` ON `album`.`id`=`song`.`album` $where_sql GROUP BY `song`.`title`";
// Add any Additional constraints
if ($search_method == "artist_title" OR $search_method == "artist_album_title") {
$sql = $sql.",artist.name";
}
if ($search_method == "artist_album_title") {
$sql = $sql.",album.name";
}
// Final componets
$sql = $sql." HAVING COUNT(title) > 1";
$sql = $sql." ORDER BY `ctitle`";
$db_results = Dba::query($sql);
$results = array();
while ($item = Dba::fetch_assoc($db_results)) {
$results[] = $item;
} // end while
return $results;
} // get_duplicate_songs
/**
* get_duplicate_info
* This takes a song, search type and auto flag and returns the duplicate songs in the correct
* order, it sorts them by longest, higest bitrate, largest filesize, checking
* the last one as most likely bad
*/
public static function get_duplicate_info($item,$search_type) {
// Build the SQL
$sql = "SELECT `song`.`id`" .
" FROM song,artist,album".
" WHERE song.artist=artist.id AND song.album=album.id".
" AND song.title= '".Dba::escape($item['title'])."'";
if ($search_type == "artist_title" || $search_type == "artist_album_title") {
$sql .=" AND artist.id = '".Dba::escape($item['artist'])."'";
}
if ($search_type == "artist_album_title" ) {
$sql .=" AND album.id = '".Dba::escape($item['album'])."'";
}
$sql .= " ORDER BY `time`,`bitrate`,`size` LIMIT 2";
$db_results = Dba::query($sql);
$results = array();
while ($item = Dba::fetch_assoc($db_results)) {
$results[] = $item['id'];
} // end while
return $results;
} // get_duplicate_info
/**
* dump_album_art (Added by Cucumber 20050216)
* This runs through all of the albums and trys to dump the
* art for them into the 'folder.jpg' file in the appropriate dir
*/
public static function dump_album_art($catalog_id,$methods=array()) {
// Get all of the albums in this catalog
$albums = self::get_catalog_albums($catalog_id);
echo "Starting Dump Album Art...\n";
// Run through them an get the art!
foreach ($albums as $album_id) {
$album = new Album($album_id);
// If no art, skip
if (!$album->has_art()) { continue; }
$image = $album->get_db_art();
/* Get the first song in the album */
$songs = $album->get_songs(1);
$song = new Song($songs[0]);
$dir = dirname($song->file);
$extension = substr($image['0']['mime'],strlen($image['0']['mime'])-3,3);
// Try the preferred filename, if that fails use folder.???
$preferred_filename = Config::get('album_art_preferred_filename');
if (!$preferred_filename || strstr($preferred_filename,"%")) { $preferred_filename = "folder.$extension"; }
$file = "$dir/$preferred_filename";
if ($file_handle = fopen($file,"w")) {
if (fwrite($file_handle, $image['0']['raw'])) {
// Also check and see if we should write out some meta data
if ($methods['metadata']) {
switch ($methods['metadata']) {
case 'windows':
$meta_file = $dir . '/desktop.ini';
$string = "[.ShellClassInfo]\nIconFile=$file\nIconIndex=0\nInfoTip=$album->full_name";
break;
default:
case 'linux':
$meta_file = $dir . '/.directory';
$string = "Name=$album->full_name\nIcon=$file";
break;
} // end switch
$meta_handle = fopen($meta_file,"w");
fwrite($meta_handle,$string);
fclose($meta_handle);
} // end metadata
$i++;
if (!($i%100)) {
echo "Written: $i. . .\n";
debug_event('art_write',"$album->name Art written to $file",'5');
}
} // end if fopen
else {
debug_event('art_write',"Unable to open $file for writting",'5');
echo "Error unable to open file for writting [$file]\n";
}
} // end if fopen worked
fclose($file_handle);
} // end foreach
echo "Album Art Dump Complete\n";
} // dump_album_art
/**
* update_last_update
* updates the last_update of the catalog
*/
private function update_last_update() {
$date = time();
$sql = "UPDATE `catalog` SET `last_update`='$date' WHERE `id`='$this->id'";
$db_results = Dba::query($sql);
} // update_last_update
/**
* update_last_add
* updates the last_add of the catalog
* @package Catalog
*/
function update_last_add() {
$date = time();
$sql = "UPDATE `catalog` SET `last_add`='$date' WHERE `id`='$this->id'";
$db_results = Dba::query($sql);
} // update_last_add
/**
* update_settings
* This function updates the basic setting of the catalog
*/
public static function update_settings($data) {
$id = Dba::escape($data['catalog_id']);
$name = Dba::escape($data['name']);
$key = Dba::escape($data['key']);
$rename = Dba::escape($data['rename_pattern']);
$sort = Dba::escape($data['sort_pattern']);
$sql = "UPDATE `catalog` SET `name`='$name', `key`='$key', `rename_pattern`='$rename', " .
"`sort_pattern`='$sort' WHERE `id` = '$id'";
$db_results = Dba::query($sql);
return true;
} // update_settings
/**
* update_single_item
* updates a single album,artist,song from the tag data
* this can be done by 75+
*/
public static function update_single_item($type,$id) {
$songs = array();
switch ($type) {
case 'album':
$album = new Album($id);
$songs = $album->get_songs();
break;
case 'artist':
$artist = new Artist($id);
$songs = $artist->get_songs();
break;
case 'song':
$songs[] = $id;
break;
} // end switch type
foreach($songs as $song_id) {
$song = new Song($song_id);
$info = self::update_song_from_tags($song,'','');
if ($info['change']) {
$file = scrub_out($song->file);
echo "
$error_msg
"; return; } $token = php_xmlrpc_decode($response->value()); /* encode the variables we need to send over */ $encoded_key = new xmlrpcval($token,"string"); $encoded_path = new xmlrpcval(Config::get('web_path'),"string"); $xmlrpc_message = new xmlrpcmsg('xmlrpcserver.get_catalogs', array($encoded_key,$encoded_path)); $response = $client->send($xmlrpc_message,30); if ($response->faultCode() ) { $error_msg = _("Error connecting to") . " " . $server . " " . _("Code") . ": " . $response->faultCode() . " " . _("Reason") . ": " . $response->faultString(); debug_event('XMLCLIENT',$error_msg,'1'); echo "$error_msg
"; return; } $data = php_xmlrpc_decode($response->value()); // Print out the catalogs we are going to sync foreach ($data as $vars) { $catalog_name = $vars['name']; $count = $vars['count']; print("Reading Remote Catalog: $catalog_name ($count Songs) [$this->path]" . _('Completed updating remote catalog(s)') . ".
$error_msg
"; } return; } // get_remote_song /** * update_remote_catalog * actually updates from the remote data, takes an array of songs that are base64 encoded and parses them * @package XMLRPC * @catagory Client * @todo This should be based off of seralize * @todo some kind of cleanup of dead songs? */ function update_remote_catalog($data,$root_path) { /* We need to check the incomming songs to see which ones need to be added */ foreach ($data as $serialized_song) { // Prevent a timeout set_time_limit(0); $song = unserialize($serialized_song); $song->artist = self::check_artist($song->artist); $song->album = self::check_album($song->album,$song->year); $song->genre = self::check_genre($song->genre); $song->file = $root_path . "/play/index.php?song=" . $data[12]; $song->catalog = $this->id; if (!$this->check_remote_song($song->file)) { $this->insert_remote_song($song); } } // foreach new Songs // now delete invalid entries self::clean($this->id); } // update_remote_catalog /** * clean_catalog * Cleans the Catalog of files that no longer exist grabs from $this->id or $id passed * Doesn't actually delete anything, disables errored files, and returns them in an array */ public function clean_catalog() { /* Define the Arrays we will need */ $dead_files = array(); // Added set time limit because this runs out of time for some people set_time_limit(0); require_once Config::get('prefix') . '/templates/show_clean_catalog.inc.php'; flush(); /* Do a quick check to make sure that the root of the catalog is readable, error if not * this will minimize the loss of catalog data if mount points fail */ if (!is_readable($this->path)) { debug_event('catalog','Catalog path:' . $this->path . ' unreadable, clean failed','1'); Error::add('general',_('Catalog Root unreadable, stopping clean')); Error::display('general'); return false; } /* Get all songs in this catalog */ $sql = "SELECT `id`,`file` FROM `song` WHERE `catalog`='$this->id' AND enabled='1'"; $db_results = Dba::query($sql); $dead_files = 0; /* Recurse through files, put @ to prevent errors poping up */ while ($results = Dba::fetch_assoc($db_results)) { /* Stupid little cutesie thing */ $count++; if (!($count%10)) { $file = str_replace(array('(',')','\''),'',$results['file']); echo "\n"; flush(); } //echos song count /* Also check the file information */ $file_info = filesize($results['file']); /* If it errors somethings splated, or the files empty */ if (!file_exists($results['file']) OR $file_info < 1) { /* Add Error */ Error::add('general',"Error File Not Found or 0 Bytes: " . $results['file']); /* Remove the file! */ $sql = "DELETE FROM `song` WHERE `id`='" . $results['id'] . "'"; $delete_results = Dba::query($sql); // Count em! $dead_files++; } //if error } //while gettings songs /* Step two find orphaned Arists/Albums * This finds artists and albums that no * longer have any songs associated with them */ self::clean($catalog_id); /* Return dead files, so they can be listed */ echo "\n"; show_box_top(); echo "" . _('Catalog Clean Done') . " [" . $dead_files . "] " . _('files removed') . "