id = $catalog_id; /* Get the information from the db */ $info = $this->get_info(); /* Assign Vars */ $this->path = $info->path; $this->name = $info->name; $this->last_update = $info->last_update; $this->last_add = $info->last_add; $this->id3_set_command = $info->id3_set_command; $this->rename_pattern = $info->rename_pattern; $this->sort_pattern = $info->sort_pattern; $this->catalog_type = $info->catalog_type; } //catalog_id } //constructor /*! @function get_info @discussion get's the vars for $this out of the database @param $this->id Taken from the object */ function get_info() { /* Grab the basic information from the catalog and return it */ $sql = "SELECT * FROM catalog WHERE id='$this->id'"; $db_results = mysql_query($sql, dbh()); $results = mysql_fetch_object($db_results); return $results; } //get_info /*! @function get_catalogs @discussion Pull all the current catalogs */ function get_catalogs() { $sql = "SELECT id FROM catalog"; $db_results = mysql_query($sql, dbh()); while ($r = mysql_fetch_object($db_results)) { $results[] = new Catalog($r->id); } return $results; } // get_catalogs /*! @function get_catalog_stats @discussion Pulls information about number of songs etc for a specifc catalog, or all catalogs calls many other internal functions, returns an object containing results @param $catalog_id If set tells us to pull from a single catalog, rather than all catalogs */ function get_catalog_stats($catalog_id=0) { $results->songs = $this->count_songs($catalog_id); $results->albums = $this->count_albums($catalog_id); $results->artists = $this->count_artists($catalog_id); $results->size = $this->get_song_size($catalog_id); $results->time = $this->get_song_time($catalog_id); } // get_catalog_stats /*! @function get_song_time @discussion Get the total amount of time (song wise) in all or specific catalog @param $catalog_id If set tells ut to pick a specific catalog */ function get_song_time($catalog_id=0) { $sql = "SELECT SUM(song.time) FROM song"; if ($catalog_id) { $sql .= " WHERE catalog='$catalog_id'"; } $db_results = mysql_query($sql, dbh()); $results = mysql_fetch_field($db_results); /* Do some conversion to get Hours Min Sec */ return $results; } // get_song_time /*! @function get_song_size @discussion Get the total size of songs in all or a specific catalog @param $catalog_id If set tells us to pick a specific catalog */ function get_song_size($catalog_id=0) { $sql = "SELECT SUM(song.size) FROM song"; if ($catalog_id) { $sql .= " WHERE catalog='$catalog_id'"; } $db_results = mysql_query($sql, dbh()); $results = mysql_fetch_field($db_results); /* Convert it into MB */ $results = ($results / 1048576); return $results; } // get_song_size /*! @function count_artists @discussion Count the number of artists in all catalogs or in a specific one @param $catalog_id If set tells us to pick a specific catalog */ function count_artists($catalog_id=0) { $sql = "SELECT DISTINCT(song.artist) FROM song"; if ($catalog_id) { $sql .= " WHERE catalog='$catalog_id'"; } $db_results = mysql_query($sql,dbh()); $results = mysql_num_rows($db_results); return $results; } // count_artists /*! @function count_albums @discussion Count the number of albums in all catalogs or in a specific one @param $catalog_id If set tells us to pick a specific catalog */ function count_albums($catalog_id=0) { $sql = "SELECT DISTINCT(song.album) FROM song"; if ($catalog_id) { $sql .=" WHERE catalog='$catalog_id'"; } $db_results = mysql_query($sql, dbh()); $results = mysql_num_rows($db_results); return $results; } // count_albums /*! @function count_songs @discussion Count the number of songs in all catalogs, or a specific one @param $catalog_id If set tells us to pick a specific catalog */ function count_songs($catalog_id=0) { $sql = "SELECT count(*) FROM song"; if ($catalog_id) { $sql .= " WHERE catalog='$catalog_id'"; } $db_results = mysql_query($sql, dbh()); $results = mysql_fetch_field($db_results); return $results; } // count_songs /*! @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); } } // if valid file } // add_file /*! @function add_files @discussion 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. @param $path The root path you want to start grabing files from @param $gather_type=0 Determins if we need to check the id3 tags of the file or not */ function add_files($path,$gather_type=0,$parse_m3u=0) { /* Strip existing escape slashes and then add them again This is done because we keep adding to the dir (slashed) + (non slashed) and a double addslashes would pooch things */ /* Open up the directory */ $handle = opendir(stripslashes($path)); if (!is_resource($handle)) { if (conf('debug')) { log_event($_SESSION['userdata']['username'],'read',"Unable to Open $path",'ampache-catalog'); } echo "" . _("Error: Unable to open") . " $path
\n"; } /* Recurse through this dir and create the files array */ while ( false !== ( $file = readdir($handle) ) ) { // Fix Found by Naund // Needed to protect from ' in filenames $file = sql_escape($file); // Prevent the script from timing out set_time_limit(0); /* if not .. or . */ if ($file != "." AND $file != "..") { if (conf('debug')) { log_event($_SESSION['userdata']['username'],'read',"Starting work on $file inside $path",'ampache-catalog'); } /* Change the dir so is_dir works correctly */ if (!@chdir(stripslashes($path))) { if (conf('debug')) { log_event($_SESSION['userdata']['username'],'read',"Unable to chdir $path",'ampache-catalog'); } echo "" . _("Error: Unable to change to directory") . " $path
\n"; } /* Create the new path */ $full_file = stripslashes($path."/".$file); $full_file = str_replace("//","/",$full_file); if (conf('no_symlinks')) { if (is_link($full_file)) { $failed_check = 1; } } /* If it's a dir run this function again! */ if (is_dir($full_file) AND !$failed_check) { $this->add_files($full_file,$gather_type,$parse_m3u); unset($failed_check); } //it's a directory /* If it's not a dir let's roll with it */ else { /* Get the file information */ $file_size = @filesize($full_file); if (!$file_size && $file_size != '0') { echo "" . _("Error: Unable to get filesize for") . " $full_file
"; if (conf('debug')) { log_event($GLOBALS['user']->username,' read ',"Error: Unable to get filesize for $full_file",'ampache-catalog'); } } // if no filesize $pattern = "/\.(" . conf('catalog_file_pattern'); if ($parse_m3u) { $pattern .= "|m3u)$/i"; } else { $pattern .= ")$/i"; } /* see if this is an mp3 file and if it is greater than 0 bytes */ if ( preg_match($pattern ,$file) && ($file_size > 0) && (!preg_match('/\.AppleDouble/', $file)) ) { if (is_readable($full_file)) { if (substr($file,-3,3) == 'm3u') { if ($this->import_m3u($full_file)) { echo "   " . _("Added Playlist From") . " $file . . . .
\n"; flush(); } } // if it's an m3u else { /* see if the current song is in the catalog */ $found = $this->check_local_mp3($full_file,$gather_type); /* If not found then insert, gets id3 information * and then inserts it into the database */ if (!$found) { $this->insert_local_song($full_file,$file_size); /* Stupid little cutesie thing */ $this->count++; if ( !($this->count%conf('catalog_echo_count')) ) { echo _("Added") . " $this->count. . . .
\n"; flush(); } //echos song count } // not found } // if it's not an m3u } // is readable else { // not readable, warn user if (conf('debug')) { log_event($_SESSION['userdata']['username'],'read',"$full_file is not readable by ampache",'ampache-catalog'); } echo "$full_file " . _("is not readable by ampache") . ".
\n"; } } //if it's a mp3 and is greater than 0 bytes else { if (conf('debug')) { log_event($_SESSION['userdata']['username'],'read',"$full_file ignored, non audio file or 0 bytes",'ampache-catalog'); } } // else not an audio file or 0 size } //else it's not a directory } //end if not . or .. } //end while if (conf('debug')) { log_event($_SESSION['userdata']['username'],' closedir ',"Finished reading $path closing handle",'ampache-catalog'); } /* 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 /*! @function get_album_art @discussion This runs through all of the albums and trys to find the art for them from the mp3s //FIXME: Make the display a table so it all lines up */ function get_album_art($catalog_id=0,$methods=array()) { if (!$catalog_id) { $catalog_id = $this->id; } // Get all of the albums in this catalog $albums = $this->get_catalog_albums($catalog_id); // Run through them an get the art! foreach ($albums as $album) { flush(); if ($debug) { echo "    " . $album->name . " -- "; } if ($methods['id3']) { $found = $album->get_id3_art(); if ($found && $debug) { echo _("Found in ID3") . "
\n"; } } if ($methods['amazon'] && !$found) { $found = $album->get_amazon_art(); if ($found && $debug) { echo _("Found on Amazon") . "
\n"; } } if ($methods['folder'] && !$found) { $found = $album->get_folder_art(); if ($found && $debug) { echo _("Found in Folder") . "
\n"; } } if (count($methods) == '0' && !$found) { $found = $album->get_art(); if ($found && $debug) { echo _("Found") . "
\n"; } } if (!$found && $debug) { echo "" . _("Not Found") . "
\n"; } if ($found) { $art_found++; } /* Stupid little cutesie thing */ $search_count++; if ( !($search_count%conf('catalog_echo_count')) ) { echo _("Searched") . " $search_count. . . .
\n"; flush(); } //echos song count // Prevent the script from timing out set_time_limit(0); unset($found); } // foreach albums echo "$art_found album's with art. . .
\n"; flush(); } // get_album_art /*! @function get_catalog_albums() @discussion Returns an array of the albums from a catalog */ function get_catalog_albums($catalog_id=0) { $results = array(); /* Use $this->id if nothing is passed */ if (!$catalog_id) { $catalog_id = $this->id; } $sql = "SELECT DISTINCT(album.id) FROM album,song WHERE song.catalog='$catalog_id' AND song.album=album.id"; $db_results = mysql_query($sql, dbh()); while ($r = mysql_fetch_object($db_results)) { $results[] = new Album($r->id); } return $results; } // get_catalog_albums /*! @function get_catalog_files @discussion Returns an array of song objects from a catalog @param $catalog_id=0 Specify the catalog ID you want to get the files of */ function get_catalog_files($catalog_id=0) { $results = array(); /* Use $this->id if nothing passed */ if (!$catalog_id) { $catalog_id = $this->id; } $sql = "SELECT id FROM song WHERE catalog='$catalog_id' AND status='enabled'"; $db_results = mysql_query($sql, dbh()); $results = array(); // return an emty array instead of nothing if no objects while ($r = mysql_fetch_object($db_results)) { $results[] = new Song($r->id); } //end while return $results; } //get_catalog_files /*! @function get_disabled @discussion Gets an array of the disabled songs for all catalogs and returns full song objects with them */ function get_disabled() { global $conf; $results = array(); $sql = "SELECT id FROM song WHERE status='disabled'"; $db_results = mysql_query($sql, dbh()); while ($r = mysql_fetch_array($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(); $path = stripslashes($path); /* 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"; } /* Recurse through this dir and create the files array */ while ( FALSE !== ($file = @readdir($handle)) ) { $full_file = stripslashes($path . "/" . $file); $full_file = str_replace("//","/",$full_file); 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"; 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 /*! @function dump_album_art (Added by Cucumber 20050216) @discussion This runs through all of the albums and trys to dump the art for them into the 'folder.jpg' file in the appropriate dir */ function dump_album_art($catalog_id=0,$methods=array()) { if (!$catalog_id) { $catalog_id = $this->id; } // Get all of the albums in this catalog $albums = $this->get_catalog_albums($catalog_id); echo "
" . _("Starting Dump Album Art") . ". . .

\n"; // Run through them an get the art! foreach ($albums as $album) { flush(); if ($image = $album->get_db_art()) { /* Get the first song in the album */ $songs = $album->get_songs(1); $song = $songs[0]; $dir = dirname($song->file); $extension = substr($image->art_mime,strlen($image->art_mime)-3,3); $preferred_filename = conf('album_art_preferred_filename'); if (!$preferred_filename) { $preferred_filename = "folder.$extension"; } $file = "$dir/$preferred_filename"; if ($file_handle = @fopen($file,"w")) { if (fwrite($file_handle, $image->art)) { $i++; if ( !($i%conf('catalog_echo_count')) ) { echo _("Written") . " $i. . .
\n"; flush(); } //echos song count if (conf('debug')) { log_event($_SESSION['userdata']['username'],'art_write',"$album->name Art written to $file"); } } fclose($file_handle); } // end if fopen else { if (conf('debug')) { log_event($_SESSION['userdata']['username'],'art_write',"Unable to open $file for writting"); } echo "" . _("Error unable to open file for writting") . " [$file]
\n"; } } // end if image } // end foreach echo "
" . _("Album Art Dump Complete") . "   "; echo "[" . _("Return") . "]"; flush(); } // dump_album_art /*! @function update_last_update @discussion updates the last_update of the catalog */ function update_last_update() { $date = time(); $sql = "UPDATE catalog SET last_update='$date' WHERE id='$this->id'"; $db_results = mysql_query($sql, dbh()); } // update_last_update /*! @function update_last_add @discussion updates the last_add of the catalog */ function update_last_add() { $date = time(); $sql = "UPDATE catalog SET last_add='$date' WHERE id='$this->id'"; $db_results = mysql_query($sql, dbh()); } // update_last_add /*! @function new_catalog @discussion The Main array for making a new catalog calls many other child functions within this class @param $path Root path to start from for catalog @param $name Name of the new catalog */ function new_catalog($path,$name, $id3cmd=0, $ren=0, $sort=0, $type=0,$gather_art=0,$parse_m3u=0,$art=array()) { /* Record the time.. time the catalog gen */ $start_time = time(); /* Flush anything that has happened so they don't think it's locked */ flush(); /* * Step one Add this to the catalog table if it's not * already there returns the new catalog_id */ $catalog_id = $this->check_catalog($path); if (!$catalog_id) { $catalog_id = $this->create_catalog_entry($path,$name,$id3cmd, $ren, $sort, $type); } /* Setup the $this with the new information */ $this->id = $catalog_id; $this->path = $path; $this->name = $name; $this->id3_set_command = ($id3cmd)?$id3cmd:''; $this->rename_pattern = ($ren)?$ren:''; $this->sort_pattern = ($sort)?$sort:''; $this->catalog_type = $type; /* Fluf */ echo _("Starting Catalog Build") . " [$name]
\n"; flush(); if ($this->catalog_type == 'remote') { echo _("Running Remote Sync") . ". . .

"; flush(); $this->get_remote_catalog($type=0); return true; } /* Get the songs and then insert them into the db */ $this->add_files($this->path,$type,$parse_m3u); /* Now Adding Album Art? */ if ($gather_art) { echo "
\n" . _("Starting Album Art Search") . ". . .
\n"; flush(); $this->get_album_art(0,$art); } // if we want to gather album art /* Do a little stats mojo here */ $current_time = time(); $time_diff = $current_time - $start_time; if ($time_diff) { $song_per_sec = intval($this->count/$time_diff); } echo _("Catalog Finished") . ". . . " . _("Total Time") . " [" . date("i:s",$time_diff) . "] " . _("Total Songs") . " [" . $this->count . "] " . _("Songs Per Seconds") . " [" . $song_per_sec . "]
\n"; return $catalog_id; } //new_catalog /*! @function update_single_item @discussion updates a single album,artist,song */ 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[0] = new Song($id); break; } // end switch type foreach($songs as $song) { $info = $this->update_song_from_tags($song); if ($info['change']) { echo "
\n\t
  • "; echo "$song->file " . _("Updated") . "\n"; echo $info['text']; echo "\t
  • \n

    "; flush(); } // if change else { echo"
    \n\t
  • "; echo "$song->file
    " . _("No Update Needed") . "\n"; echo "\t
  • \n

    "; flush(); } } // foreach songs } // update_single_item /*! @function update_song_from_tags @discussion updates the song info based on tags */ function update_song_from_tags($song) { $info = new Audioinfo(); $results = $info->Info($song->file); /* Find the correct key */ $key = get_tag_type($results); /* Fill Missing Information */ $results = $song->fill_info($results,$this->sort_pattern . "/" . $this->rename_pattern, $this->id, $key); /* Clean up the tags */ $results = clean_tag_info($results,$key,$song->file); /* Setup the vars */ $new_song = new Song(); $new_song->file = $results['file']; $new_song->title = $results['title']; $new_song->year = $results['year']; $new_song->comment = $results['comment']; $new_song->bitrate = $results['bitrate']; $new_song->rate = $results['rate']; $new_song->mode = $results['mode']; $new_song->size = $results['size']; $new_song->time = $results['time']; $new_song->track = $results['track']; $artist = $results['artist']; $album = $results['album']; $genre = $results['genre']; /* Clean up Old Vars */ unset($results,$key,$info); /* * We have the artist/genre/album name need to check it in the tables * If found then add & return id, else return id */ $new_song->artist = $this->check_artist($artist); $new_song->f_artist = $artist; $new_song->genre = $this->check_genre($genre); $new_song->f_genre = $genre; $new_song->album = $this->check_album($album,$new_song->year); $new_song->f_album = $album . " - " . $new_song->year; $new_song->title = $this->check_title($new_song->title,$new_song->file); $info = $song->compare_song_information($song,$new_song); if ($info['change']) { $song->update_song($song->id,$new_song); } return $info; } // update_song_from_tags /*! @function add_to_catalog @discussion this function adds new files to an existing catalog */ function add_to_catalog($type=0) { echo _("Starting New Song Search on") . " [$this->name] " . _("catalog") . "

    \n"; flush(); if ($this->catalog_type == 'remote') { echo _("Running Remote Update") . ". . .

    "; flush(); $this->get_remote_catalog($type=0); return true; } /* Set the Start time */ $start_time = time(); /* Get the songs and then insert them into the db */ $this->add_files($this->path,$type); /* Do a little stats mojo here */ $current_time = time(); if ($type != "fast_add") { echo "" . _("Starting Album Art Search") . ". . .
    \n"; flush(); $this->get_album_art(); } /* Update the Catalog last_update */ $this->update_last_add(); $time_diff = $current_time - $start_time; if ($time_diff) { $song_per_sec = intval($this->count/$time_diff); } if (!$song_per_sec) { $song_per_sec = "N/A"; } if (!$this->count) { $this->count = 0; } echo "\n
    " . _("Catalog Update Finished") . "... " . _("Total Time") . " [" . date("i:s",$time_diff) . "] " . _("Total Songs") . " [" . $this->count . "] " . _("Songs Per Seconds") . " [" . $song_per_sec . "]

    "; } // add_to_catalog /*! @function get_remote_catalog @discussion get a remote catalog and runs update if needed */ function get_remote_catalog($type=0) { if (!class_exists('xmlrpc_client')) { if (conf('debug')) { log_event($_SESSION['userdata']['username'],'xmlrpc',"Unable to load XMLRPC library"); } echo "" . _("Error") . ": " . _("Unable to load XMLRPC library, make sure XML-RPC is enabled") . "
    \n"; return false; } // first, glean out the information from the path about the server and remote path preg_match("/http:\/\/([^\/]+)\/*(.*)/", $this->path, $match); $server = $match[1]; $path = $match[2]; if ( ! $path ) { $client = new xmlrpc_client("/server.php", $server, 80); } else { $client = new xmlrpc_client("/$path/server.php", $server, 80); } $f = new xmlrpcmsg('remote_server_query', array(new xmlrpcval( conf('web_path'), "string")) ); //if (conf('debug')) { $client->setDebug(1); } $response = $client->send($f); $value = $response->value(); if ( !$response->faultCode() ) { $data = old_xmlrpc_decode($value); // Print out the catalogs we are going to sync //FIXME: We should add catalog level access control foreach ($data as $vars) { $catalog_name = $vars[0]; print("Reading Remote Catalog: $catalog_name [$this->path]
    \n"); } } else { $error_msg = _("Error connecting to") . " " . $server . " " . _("Code") . ": " . $response->faultCode() . " " . _("Reason") . ": " . $response->faultString(); log_event($_SESSION['userdata']['username'],'xmlrpc',$error_msg); echo "

    $error_msg

    "; return; } $f = new xmlrpcmsg('remote_song_query', array(new xmlrpcval( 'song', "string")) ); $response = $client->send($f); $value = $response->value(); if ( !$response->faultCode() ) { $data = old_xmlrpc_decode($value); $this->update_remote_catalog($data,$this->path); } else { $error_msg = _("Error connecting to") . " " . $server . " " . _("Code") . ": " . $response->faultCode() . " " . _("Reason") . ": " . $response->faultString(); log_event($_SESSION['userdata']['username'],'xmlrpc',$error_msg); echo "

    $error_msg

    "; } echo "

    " . _("Completed updating remote catalog(s)") . ".


    \n"; } // get_remote_catalog /*! @function update_remote_catalog @discussion actually updates from the remote data */ function update_remote_catalog($songs,$root_path) { global $settings, $dbh, $artists; /* We need to check the incomming songs to see which ones need to be added */ foreach ($songs as $song) { // Prevent a timeout set_time_limit(0); $song = base64_decode($song); $data = explode("::", $song); $new_song->artist = $this->check_artist($data[0]); $new_song->album = $this->check_album($data[1],$data[4]); $new_song->title = $data[2]; $new_song->comment = $data[3]; $new_song->year = $data[4]; $new_song->bitrate = $data[5]; $new_song->rate = $data[6]; $new_song->mode = $data[7]; $new_song->size = $data[8]; $new_song->time = $data[9]; $new_song->track = $data[10]; $new_song->genre = $this->check_genre($data[11]); $new_song->file = $root_path . "/play/index.php?song=" . $data[12] . "uid=$md5_ip"; $new_song->catalog = $this->id; if (!$song_id = $this->check_remote_song($new_song->file)) { $this->insert_remote_song($new_song); } } // foreach new Songs //FIXME: Delete Songs that were not updated (gone) // now delete invalid entries $this->clean_albums(); $this->clean_stats(); $this->clean_artists(); $this->clean_flagged(); } // update_remote_catalog /*! @function clean_catalog @discussion 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 @param $catalog_id=0 Take the ID of the catalog you want to clean @param $action=0 Delete/Disable, default is disable */ function clean_catalog($catalog_id=0,$action=0) { /* Define the Arrays we will need */ $dead_files = array(); if (!$catalog_id) { $catalog_id = $this->id; } echo "Cleaning the [" . $this->name . "] Catalog...

    "; flush(); /* Get all songs in this catalog */ $sql = "SELECT id,file FROM song WHERE catalog='$catalog_id' AND status='enabled'"; $db_results = mysql_query($sql, dbh()); /* Recurse through files, put @ to prevent errors poping up */ while ($results = mysql_fetch_object($db_results)) { /* Remove slashes while we are checking for its existance */ $results->file = stripslashes($results->file); /* Stupid little cutesie thing */ $this->count++; if ( !($this->count%conf('catalog_echo_count')) ) { echo _("Checking") . " $this->count. . . .
    \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 */ echo "Error File Not Found or 0 Bytes: " . $results->file . "
    "; flush(); /* Add this file to the list for removal from the db */ $dead_files[] = $results; } //if error } //while gettings songs /* Incase there's been a snafo with a mount point on something * don't actually delete from DB here, simply disable and list */ if (count($dead_files)) { foreach ($dead_files as $data) { //FIXME: Until I fix the form, assume delete //if ($action === 'delete_dead') { $sql = "DELETE FROM song WHERE id='$data->id'"; //} // //else { // $sql = "UPDATE song SET status='disabled' WHERE id='$data->id'"; //} $db_results = mysql_query($sql, dbh()); /* DB Error occured */ if (!$db_results) { /* Add Error */ } //if error } //end foreach } // end if dead files /* Step two find orphaned Arists/Albums * This finds artists and albums that no * longer have any songs associated with them */ $this->clean_albums(); $this->clean_artists(); $this->clean_stats(); $this->clean_playlists(); $this->clean_flagged(); /* Return dead files, so they can be listed */ echo "" . _("Catalog Clean Done") . " [" . count($dead_files) . "] " . _("files removed") . "
    \n"; flush(); return $dead_files; } //clean_catalog /*! @function clean_albums @discussion This function cleans out unused albums @param $this->id Depends on the current object */ function clean_albums() { /* Mysql 3.23 doesn't support our cool query so we have to do it a different way */ if (preg_match("/^3\./",mysql_get_server_info())) { $sql = "SELECT album.id FROM album LEFT JOIN song ON song.album = album.id WHERE song.id IS NULL"; $db_results = mysql_query($sql, dbh()); $results = array(); while ($r = mysql_fetch_row($db_results)) { $results[] = $r; } foreach ($results as $dead) { $sql = "DELETE FROM album WHERE id='$dead[0]'"; $db_results = mysql_query($sql,dbh()); } return true; } /* Do a complex delete to get albums where there are no songs */ $sql = "DELETE FROM album USING album LEFT JOIN song ON song.album = album.id WHERE song.id IS NULL"; $db_results = mysql_query($sql, dbh()); } //clean_albums /*! @function clean_flagged @discussion This functions cleans ou unused flagged items */ function clean_flagged() { /* Mysql 3.23 doesn't support our cool query so we have to do it a different way */ if (preg_match("/^3\./",mysql_get_server_info())) { $sql = "SELECT flagged.id FROM flagged LEFT JOIN song ON song.id=flagged.song WHERE song.id IS NULL"; $db_results = mysql_query($sql, dbh()); $results = array(); while ($r = mysql_fetch_row($db_results)) { $results[] = $r; } foreach ($results as $dead) { $sql = "DELETE FROM flagged WHERE id='$dead[0]'"; $db_results = mysql_query($sql, dbh()); } return true; } /* Do a complex delete to get flagged items where the songs are now gone */ $sql = "DELETE FROM flagged USING flagged LEFT JOIN song ON song.id = flagged.song WHERE song.id IS NULL"; $db_results = mysql_query($sql, dbh()); } // clean_flagged /*! @function clean_artists @discussion This function cleans out unused artists @param $this->id Depends on the current object */ function clean_artists() { /* Mysql 3.23 doesn't support our cool query so we have to do it a different way */ if (preg_match("/^3\./",mysql_get_server_info())) { $sql = "SELECT artist.id FROM artist LEFT JOIN song ON song.artist = artist.id WHERE song.id IS NULL"; $db_results = mysql_query($sql, dbh()); $results = array(); while ($r = mysql_fetch_row($db_results)) { $results[] = $r; } foreach ($results as $dead) { $sql = "DELETE FROM artist WHERE id='$dead[0]'"; $db_results = mysql_query($sql,dbh()); } return true; } /* Do a complex delete to get artists where there are no songs */ $sql = "DELETE FROM artist USING artist LEFT JOIN song ON song.artist = artist.id WHERE song.id IS NULL"; $db_results = mysql_query($sql, dbh()); } //clean_artists /* @function clean_playlists @discussion cleans out dead files from playlists @param $this->id depends on the current object */ function clean_playlists() { /* Mysql 3.23 doesn't support our cool query so we have to do it a different way */ if (preg_match("/^3\./",mysql_get_server_infO())) { $sql = "SELECT playlist_data.song FROM playlist_data LEFT JOIN song ON song.id = playlist_data.song WHERE song.file IS NULL"; $db_results = mysql_query($sql, dbh()); $results = array(); while ($r = mysql_fetch_row($db_results)) { $results[] = $r; } foreach ($results as $dead) { $sql = "DELETE FROM playlist_data WHERE song='$dead[0]'"; $db_results = mysql_query($sql, dbh()); } return true; } /* Do a complex delete to get playlist songs where there are no songs */ $sql = "DELETE FROM playlist_data USING playlist_data LEFT JOIN song ON song.id = playlist_data.song WHERE song.file IS NULL"; $db_results = mysql_query($sql, dbh()); } // clean_playlists /*! @function clean_stats @discussion This functions removes stats for songs/albums that no longer exist @param $catalog_id The ID of the catalog to clean */ function clean_stats() { $version = mysql_get_server_info(); /* Mysql 3.23 doesn't support our cool query so we have to do it a different way */ if (preg_match("/^3\./",$version)) { $sql = "SELECT object_count.id FROM object_count LEFT JOIN song ON song.id = object_count.object_id WHERE object_type='song' AND song.id IS NULL"; $db_results = mysql_query($sql, dbh()); $results = array(); while ($r = mysql_fetch_row($db_results)) { $results[] = $r; } foreach ($results as $dead) { $sql = "DELETE FROM object_count WHERE id='$dead[0]'"; $db_results = mysql_query($sql,dbh()); } } // We assume this will be 4.0+ else { /* Crazy SQL Mojo to remove stats where there are no songs */ $sql = "DELETE FROM object_count USING object_count LEFT JOIN song ON song.id=object_count.object_id WHERE object_type='song' AND song.id IS NULL"; $db_results = mysql_query($sql, dbh()); } /* Mysql 3.23 doesn't support our cool query so we have to do it a different way */ if (preg_match("/^3\./",$version)) { $sql = "SELECT object_count.id FROM object_count LEFT JOIN album ON album.id = object_count.object_id WHERE object_type='album' AND album.id IS NULL"; $db_results = mysql_query($sql, dbh()); $results = array(); while ($r = mysql_fetch_row($db_results)) { $results[] = $r; } foreach ($results as $dead) { $sql = "DELETE FROM object_count WHERE id='$dead[0]'"; $db_results = mysql_query($sql,dbh()); } } // We assume 4.0+ Here else { /* Crazy SQL Mojo to remove stats where there are no albums */ $sql = "DELETE FROM object_count USING object_count LEFT JOIN album ON album.id=object_count.object_id WHERE object_type='album' AND album.id IS NULL"; $db_results = mysql_query($sql, dbh()); } /* Mysql 3.23 doesn't support our cool query so we have to do it a different way */ if (preg_match("/^3\./",$version)) { $sql = "SELECT object_count.id FROM object_count LEFT JOIN artist ON artist.id = object_count.object_id WHERE object_type='artist' AND artist.id IS NULL"; $db_results = mysql_query($sql, dbh()); $results = array(); while ($r = mysql_fetch_row($db_results)) { $results[] = $r; } foreach ($results as $dead) { $sql = "DELETE FROM object_count WHERE id='$dead[0]'"; $db_results = mysql_query($sql,dbh()); } } // We assume 4.0+ here else { /* Crazy SQL Mojo to remove stats where ther are no artists */ $sql = "DELETE FROM object_count USING object_count LEFT JOIN artist ON artist.id=object_count.object_id WHERE object_type='artist' AND artist.id IS NULL"; $db_results = mysql_query($sql, dbh()); } } // clean_stats /*! @function verify_catalog @discussion This function compares the DB's information with the ID3 tags @param $catalog_id The ID of the catalog to compare */ function verify_catalog($catalog_id=0,$gather_type=0) { /* Create and empty song for us to use */ $total_updated = 0; /* Set it to this if they don't pass anything */ if (!$catalog_id) { $catalog_id = $this->id; } /* First get the filenames for the catalog */ $sql = "SELECT id FROM song WHERE catalog='$catalog_id' ORDER BY id"; $db_results = mysql_query($sql, dbh()); $number = mysql_num_rows($db_results); echo _("Updating the") . " [ $this->name ] " . _("Catalog") . "
    \n"; echo $number . " " . _("songs found checking tag information.") . "

    \n\n"; flush(); /* Magical Fix so we don't run out of time */ set_time_limit(0); /* Recurse through this catalogs files * and get the id3 tage information, * if it's not blank, and different in * in the file then update! */ while ($results = mysql_fetch_object($db_results)) { $song = new Song($results->id); if (is_readable($song->file)) { unset($skip); /* If they have specified fast_update check the file filemtime to make sure the file has actually changed */ if ($gather_type === "fast_update") { $file_date = filemtime($song->file); if ($file_date < $this->last_update) { $skip = true; } } // if gather_type if ($song->update_time >= $this->last_update) { $skip = true; $song->update_utime($song->id,time()+86400); } // if the file hasn't been modified since the last_update if (!$skip) { $info = $this->update_song_from_tags($song); $album_id = $song->album; if ($info['change']) { echo "
    \n\t
  • "; echo "$song->file " . _("Updated") . "\n"; echo $info['text']; /* If we aren't doing a fast update re-gather album art */ if ($gather_type !== "fast_update" AND !isset($searched_albums[$album_id])) { $album = new Album($song->album); $searched_albums[$album_id] = 1; $found = $album->get_art(); unset($album); if ($found) { $is_found = _(" FOUND"); } echo "
    " . _("Searching for new Album Art") . ". . .$is_found
    \n"; unset($found,$is_found); } elseif (isset($searched_albums[$album_id])) { echo "
    " . _("Album Art Already Found") . ". . .
    \n"; } echo "\t
  • \n
    \n
    \n"; flush(); $total_updated++; } unset($info); } // end skip /* Stupid little cutesie thing */ $this->count++; if ( !($this->count%conf('catalog_echo_count')) ) { echo "Checked $this->count. . . .
    \n"; flush(); } //echos song count } // end if file exists else { echo "
    \n
  • "; echo "$song->file does not exist or is not readable\n"; echo "
  • \n
    \n
    \n"; // Should we remove it from catalog? } } //end foreach /* After we have updated all the songs with the new information clear any empty albums/artists */ $this->clean_albums(); $this->clean_artists(); $this->clean_stats(); $this->clean_flagged(); // Update the last_update $this->update_last_update(); echo "Update Finished. Checked $this->count. $total_updated songs updated.

    "; } //verify_catalog /*! @function create_catalog_entry @discussion Creates a new catalog from path and type @param $path The root path for this catalog @param $name The name of the new catalog */ function create_catalog_entry($path,$name,$id3cmd=0,$ren=0,$sort=0, $type='local') { // Current time $date = time(); $path = sql_escape($path); $name = sql_escape($name); if($id3cmd && $ren && $sort) { $sql = "INSERT INTO catalog (path,name,last_update,id3_set_command,rename_pattern,sort_pattern,catalog_type) " . " VALUES ('$path','$name','$date', '$id3cmd', '$ren', '$sort','$type')"; } else { $sql = "INSERT INTO catalog (path,name,last_update) VALUES ('$path','$name','$date')"; } $db_results = mysql_query($sql, dbh()); $catalog_id = mysql_insert_id(dbh()); return $catalog_id; } //create_catalog_entry /*! @function check_catalog @discussion Checks for the $path already in the catalog table @param $path The root path for the catalog we are checking */ function check_catalog($path) { $path = sql_escape($path); $sql = "SELECT id FROM catalog WHERE path='$path'"; $db_results = mysql_query($sql, dbh()); $results = mysql_fetch_object($db_results); return $results->id; } //check_catalog /*! @function check_artist @discussion Takes $artist checks if there then return id else insert and return id @param $artist The name of the artist */ function check_artist($artist) { // Only get the var ones.. less func calls $cache_limit = conf('artist_cache_limit'); /* Clean up the artist */ $artist = trim($artist); $artist = sql_escape($artist); /* Ohh no the artist has lost it's mojo! */ if (!$artist) { $artist = "Unknown (Orphaned)"; } // Remove the prefix so we can sort it correctly preg_match("/^(The\s|An\s|A\s)(.*)/i",$artist,$matches); if (count($matches)) { $artist = $matches[2]; $prefix = $matches[1]; } // Check to see if we've seen this artist before if (isset($this->artists[$artist])) { return $this->artists[$artist]; } // if we've seen this artist before /* Setup the checking sql statement */ $sql = "SELECT id FROM artist WHERE name LIKE '$artist' "; $db_results = mysql_query($sql, dbh()); /* If it's found */ if ($r = mysql_fetch_object($db_results)) { $artist_id = $r->id; } //if found /* If not found create */ else { $sql = "INSERT INTO artist (name, prefix) VALUES ('$artist', '$prefix')"; $db_results = mysql_query($sql, dbh()); $artist_id = mysql_insert_id(dbh()); if (!$db_results) { echo "Error Inserting Artist:$artist
    "; flush(); } } //not found if ($cache_limit) { $artist_count = count($this->artists); if ($artist_count == $cache_limit) { $this->artists = array_slice($this->artists,1); } if (conf('debug')) { log_event($_SESSION['userdata']['username'],'cache',"Adding $artist with $artist_id to Cache",'ampache-catalog'); } $array = array($artist => $artist_id); $this->artists = array_merge($this->artists, $array); unset($array); } // if cache limit is on.. return $artist_id; } //check_artist /*! @function check_album @disucssion Takes $album and checks if there then return id else insert and return id @param $album The name of the album */ function check_album($album,$album_year=0) { /* Clean up the album name */ $album = trim($album); $album = sql_escape($album); $album_year = intval($album_year); // Set it once to reduce function calls $cache_limit = conf('album_cache_limit'); /* Ohh no the album has lost it's mojo */ if (!$album) { $album = "Unknown (Orphaned)"; } // Remove the prefix so we can sort it correctly preg_match("/^(The\s|An\s|A\s)(.*)/i",$album,$matches); if (count($matches)) { $album = $matches[2]; $prefix = $matches[1]; } // Check to see if we've seen this album before if (isset($this->albums[$album])) { return $this->albums[$album]; } /* Setup the Query */ $sql = "SELECT id FROM album WHERE name LIKE '$album'"; if ($album_year) { $sql .= " AND year='$album_year'"; } $db_results = mysql_query($sql, dbh()); /* If it's found */ if ($r = mysql_fetch_object($db_results)) { $album_id = $r->id; } //if found /* If not found create */ else { $sql = "INSERT INTO album (name, prefix,year) VALUES ('$album', '$prefix','$album_year')"; $db_results = mysql_query($sql, dbh()); $album_id = mysql_insert_id(dbh()); if (!$db_results) { echo "Error Inserting Album:$album
    "; flush(); } } //not found if ($cache_limit > 0) { $albums_count = count($this->albums); if ($albums_count == $cache_limit) { $this->albums = array_slice($this->albums,1); } $array = array($album => $album_id); $this->albums = array_merge($this->albums,$array); unset($array); } // if cache limit is on.. return $album_id; } //check_album /*! @function check_genre @discussion Finds the Genre_id from the text name @param $genre The name of the genre */ function check_genre($genre) { if (!$genre) { return false; } if ($this->genres[$genre]) { return $this->genres[$genre]; } /* Look in the genre table */ $genre = sql_escape($genre); $sql = "SELECT id FROM genre WHERE name LIKE '$genre'"; $db_results = mysql_query($sql, dbh()); $results = mysql_fetch_object($db_results); if (!$results->id) { $sql = "INSERT INTO genre (name) VALUES ('$genre')"; $db_results = mysql_query($sql, dbh()); $results->id = mysql_insert_id(dbh()); } $this->genres[$genre] = $results->id; return $results->id; } //check_genre /*! @function check_title @discussion this checks to make sure something is set on the title, if it isn't it looks at the filename and trys to set the title based on that */ function check_title($title,$file=0) { if (strlen(trim($title)) < 1) { preg_match("/.+\/(.*)\.....?$/",$file,$matches); $title = sql_escape($matches[1]); } return $title; } //check_title /*! @function insert_local_song @discussion Insert a song that isn't already in the database this function is in here so we don't have to create a song object @param $file The file name we are adding (full path) @param $file_info The information of the file, size etc taken from stat() */ function insert_local_song($file,$file_info) { /* Create the Audioinfo object and get info */ $audio_info = new Audioinfo(); $song_obj = new Song(); $results = $audio_info->Info($file); $results['file'] = $file; $key = get_tag_type($results); /* Fill Empty info from filename/path */ $results = $song_obj->fill_info($results,$this->sort_pattern . "/" . $this->rename_pattern,$this->id,$key); /* Clean Up the tags */ $results = clean_tag_info($results,$key,$file); /* Set the vars here... so we don't have to do the '" . $blah['asd'] . "' */ $title = sql_escape($results['title']); $artist = $results['artist']; $album = $results['album']; $genre = $results['genre']; $bitrate = $results['bitrate']; $rate = $results['rate']; $mode = $results['mode']; $size = $results['size']; $song_time = $results['time']; $track = $results['track']; $year = $results['year']; $comment = $results['comment']; $current_time = time(); /* * We have the artist/genre/album name need to check it in the tables * If found then add & return id, else return id */ $artist_id = $this->check_artist($artist); $genre_id = $this->check_genre($genre); $album_id = $this->check_album($album,$year); $title = $this->check_title($title,$file); $add_file = sql_escape($results['file']); $sql = "INSERT INTO song (file,catalog,album,artist,title,bitrate,rate,mode,size,time,track,genre,addition_time,year,comment)" . " VALUES ('$add_file','$this->id','$album_id','$artist_id','$title','$bitrate','$rate','$mode','$size','$song_time','$track','$genre_id','$current_time','$year','$comment')"; $db_results = mysql_query($sql, dbh()); if (!$db_results) { if (conf('debug')) { log_event($_SESSION['userdata']['username'],'insert',"Unable to insert $file -- $sql",'ampache-catalog'); } echo "Error Adding $file
    $sql
    "; flush(); } /* Clear Variables */ unset($results,$audio_info,$song_obj); } // insert_local_song /*! @function insert_remote_song @discussion takes the information gotten from XML-RPC and inserts it into the local database. The filename ends up being the url. */ function insert_remote_song($song) { $url = sql_escape($song->file); $title = $this->check_title($song->title); $title = sql_escape($title); $comment = sql_escape($song->comment); $current_time = time(); $sql = "INSERT INTO song (file,catalog,album,artist,title,bitrate,rate,mode,size,time,track,genre,addition_time,year,comment)" . " VALUES ('$url','$song->catalog','$song->album','$song->artist','$title','$song->bitrate','$song->rate','$song->mode','$song->size','$song->time','$song->track','$song->genre','$current_time','$song->year','$comment')"; $db_results = mysql_query($sql, dbh()); if (!$db_results) { if (conf('debug')) { log_event($_SESSION['userdata']['username'],'insert',"Unable to Add Remote $url -- $sql",'ampache-catalog'); } echo "Error Adding Remote $url
    $sql
    \n"; flush(); } } // insert_remote_song /*! @function check_remote_song @discussion checks to see if a remote song exists in the database or not if it find a song it returns the UID */ function check_remote_song($url) { $url = sql_escape($url); $sql = "SELECT id FROM song WHERE file='$url'"; $db_results = mysql_query($sql, dbh()); if ($r = mysql_fetch_object($db_results)) { return $r->id; } return false; } // check_remote_song /*! @function check_local_mp3 @discussion Checks the song to see if it's there already returns true if found, false if not @param $full_file The full file name that we are checking @param $gather_type=0 If we need to check id3 tags or not */ function check_local_mp3($full_file, $gather_type=0) { if ($gather_type == 'fast_add') { $file_date = filemtime($full_file); if ($file_date < $this->last_add) { return true; } } $full_file = sql_escape($full_file); $sql = "SELECT id FROM song WHERE file = '$full_file'"; $db_results = mysql_query($sql, dbh()); //If it's found then return true if (@mysql_fetch_row($db_results)) { return true; } return false; } //check_local_mp3 /*! @function import_m3u @discussion this takes m3u filename and then attempts to create a Public Playlist based on the filenames listed in the m3u */ function import_m3u($filename) { $m3u_handle = @fopen($filename,'r'); $data = @fread($m3u_handle,filesize($filename)); $results = explode("\n",$data); foreach ($results as $value) { // Remove extra whitespace $value = trim($value); if (preg_match("/\.[A-Za-z0-9]{3}$/",$value)) { $file[0] = str_replace("/","\\",$value); $file[1] = str_replace("\\","/",$value); /* Search for this filename, cause it's a audio file */ $sql = "SELECT id FROM song WHERE file LIKE '%" . sql_escape($file[0]) . "' OR file LIKE '%" . sql_escape($file[1]) . "'"; $db_results = mysql_query($sql, dbh()); $song_id = mysql_result($db_results,'id'); if ($song_id) { $songs[] = $song_id; } } // if it's a file } // end foreach line if (conf('debug')) { log_event($GLOBALS['user']->username,' m3u_parse ',"Parsing $filename - Found: " . count($songs) . " Songs"); } if (count($songs)) { $playlist = new Playlist(); $playlist_name = "M3U - " . basename($filename); $playlist->create_playlist($playlist_name,$GLOBALS['user']->id,'public'); $playlist->add_songs($songs); return true; } return false; } // import_m3u /*! @function delete_catalog @discussion Deletes the catalog and everything assoicated with it assumes $this */ function delete_catalog() { // Do some crazyness to delete all the songs in this catalog // from playlists... $sql = "SELECT playlist_data.song FROM song,playlist_data,catalog WHERE catalog.id=song.catalog AND playlist_data.song=song.id AND catalog.id='$this->id'"; $db_results = mysql_query($sql, dbh()); $results = array(); while ($r = mysql_fetch_object($db_results)) { $results[] = $r; } foreach ($results as $r) { // Clear Playlist Data $sql = "DELETE FROM playlist_data WHERE song='$r->song'"; $db_results = mysql_query($sql, dbh()); } // End Foreach // First remove the songs in this catalog $sql = "DELETE FROM song WHERE catalog = '$this->id'"; $db_results = mysql_query($sql, dbh()); // Next Remove the Catalog Entry it's self $sql = "DELETE FROM catalog WHERE id = '$this->id'"; $db_results = mysql_query($sql, dbh()); // Run the Aritst/Album Cleaners... $this->clean_albums(); $this->clean_artists(); $this->clean_stats(); $this->clean_playlists(); $this->clean_flagged(); } // delete_catalog /*! @function remove_songs @discussion removes all songs sent in $songs array from the database, it doesn't actually delete them... */ function remove_songs($songs) { foreach($songs as $song) { $sql = "DELETE FROM song WHERE id = '$song'"; $db_results = mysql_query($sql, dbh()); } } // remove_songs } //end of catalog class ?>