diff options
author | Karl 'vollmerk' Vollmer <vollmer@ampache.org> | 2005-06-09 16:34:40 +0000 |
---|---|---|
committer | Karl 'vollmerk' Vollmer <vollmer@ampache.org> | 2005-06-09 16:34:40 +0000 |
commit | bcad40a05ab2dc2a341a3227e30b96668bce4500 (patch) | |
tree | 6fca27588d53a1b24705bd2834e9e643bb729bd1 /modules/class | |
download | ampache-bcad40a05ab2dc2a341a3227e30b96668bce4500.tar.gz ampache-bcad40a05ab2dc2a341a3227e30b96668bce4500.tar.bz2 ampache-bcad40a05ab2dc2a341a3227e30b96668bce4500.zip |
New Import
Diffstat (limited to 'modules/class')
-rw-r--r-- | modules/class/access.php | 189 | ||||
-rw-r--r-- | modules/class/album.php | 463 | ||||
-rw-r--r-- | modules/class/artist.php | 207 | ||||
-rw-r--r-- | modules/class/catalog.php | 1934 | ||||
-rw-r--r-- | modules/class/error.php | 94 | ||||
-rw-r--r-- | modules/class/playlist.php | 366 | ||||
-rw-r--r-- | modules/class/song.php | 657 | ||||
-rw-r--r-- | modules/class/stream.php | 291 | ||||
-rw-r--r-- | modules/class/update.php | 880 | ||||
-rw-r--r-- | modules/class/user.php | 604 | ||||
-rw-r--r-- | modules/class/view.php | 229 |
11 files changed, 5914 insertions, 0 deletions
diff --git a/modules/class/access.php b/modules/class/access.php new file mode 100644 index 00000000..6e6afbf2 --- /dev/null +++ b/modules/class/access.php @@ -0,0 +1,189 @@ +<? +/* + + This program 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 + of the License, or (at your option) any later version. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +/*! + @header Access Class +*/ + +class Access { + + /* Variables from DB */ + var $id; + var $name; + var $start; + var $end; + var $level; + + /*! + @function Access + @discussion Access class, for modifing access rights + @param $access_id The ID of access entry + */ + function Access($access_id = 0) { + + /* If we have passed an id then do something */ + if ($access_id) { + + /* Assign id for use in get_info() */ + $this->id = $access_id; + + /* Get the information from the db */ + if ($info = $this->get_info()) { + + /* Assign Vars */ + $this->name = $info->name; + $this->start = $info->start; + $this->end = $info->end; + $this->level = $info->level; + } // if info + + } // if access_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 access_list WHERE id='$this->id'"; + $db_results = mysql_query($sql, dbh()); + + $results = mysql_fetch_object($db_results); + + return $results; + + } //get_info + + /*! + @function create + @discussion creates a new entry + */ + function create($name,$start,$end,$level) { + + $start = ip2int($start); + $end = ip2int($end); + $name = sql_escape($name); + $level = intval($level); + + $sql = "INSERT INTO access_list (`name`,`level`,`start`,`end`) VALUES ". + "('$name','$level','$start','$end')"; + $db_results = mysql_query($sql, dbh()); + + } // create + + /*! + @function delete + @discussion deletes $this access_list entry + */ + function delete($access_id=0) { + + if (!$access_id) { + $access_id = $this->id; + } + + $sql = "DELETE FROM access_list WHERE id='$access_id'"; + $db_results = mysql_query($sql, dbh()); + + } // delete + + /*! + @function check + @discussion check to see if they have rights + */ + function check($needed, $ip) { + + // They aren't using access control + // lets just keep on trucking + if (!conf('access_control')) { + return true; + } + + $ip = ip2int($ip); + + $sql = "SELECT id FROM access_list WHERE start<='$ip' AND end>='$ip' AND level>='$needed'"; + $db_results = mysql_query($sql, dbh()); + + // Yah they have access they can use the mojo + if (mysql_fetch_row($db_results)) { + return true; + } + + // No Access Sucks to be them. + else { + return false; + } + + } // check + + /*! + @function get_access_list + @discussion returns a full listing of all access + rules on this server + */ + function get_access_list() { + + $sql = "SELECT * FROM access_list"; + $db_results = mysql_query($sql, dbh()); + + + while ($r = mysql_fetch_object($db_results)) { + $obj = new Access(); + $obj->id = $r->id; + $obj->start = $r->start; + $obj->end = $r->end; + $obj->name = $r->name; + $obj->level = $r->level; + $results[] = $obj; + } // end while access list mojo + + return $results; + + } // get_access_list + + + /*! + @function get_level_name + @discussion take the int level and return a + named level + */ + function get_level_name() { + + if ($this->level == '75') { + return "Full Access"; + } + if ($this->level == '5') { + return "Demo"; + } + if ($this->level == '25') { + return "Stream"; + } + if ($this->level == '50') { + return "Stream/Download"; + } + + + } // get_level_name + +} //end of access class + +?> diff --git a/modules/class/album.php b/modules/class/album.php new file mode 100644 index 00000000..c95a8ff6 --- /dev/null +++ b/modules/class/album.php @@ -0,0 +1,463 @@ +<?php +/* + Copyright (c) 2004 + Ampache.org + + This program 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 + of the License, or (at your option) any later version. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +/*! + @header Album Class +*/ + +class Album { + + /* Variables from DB */ + var $id; + var $name; + var $year; + var $prefix; + + /*! + @function Album + @discussion Album class, for modifing a song. + @param $album_id The ID of the song + */ + function Album($album_id = 0) { + + /* If we have passed an id then do something */ + if ($album_id) { + + /* Assign id for use in get_info() */ + $this->id = $album_id; + + /* Get the information from the db */ + if ($info = $this->get_info()) { + + /* Assign Vars */ + $this->name = trim($info->prefix . " " . $info->album_name); + $this->songs = $info->song_count; + $this->artist_count = $info->artist_count; + $this->year = $info->year; + $this->artist = trim($info->artist_prefix . " " . $info->artist_name); + $this->artist_id = $info->art_id; + $this->album = $info->album_name; + + $this->prefix = $info->prefix; + } // if info + + } // if album_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 COUNT(DISTINCT(song.artist)) as artist_count,album.prefix,album.year,album.name AS album_name,COUNT(song.id) AS song_count," . + "artist.name AS artist_name,artist.id AS art_id,artist.prefix AS artist_prefix ". + "FROM song,artist,album WHERE album.id='$this->id' AND song.album=album.id AND song.artist=artist.id GROUP BY song.album"; + + $db_results = mysql_query($sql, dbh()); + + $results = mysql_fetch_object($db_results); + + return $results; + + } //get_info + + /*! + @function get_songs + @discussion gets the songs for this album + */ + function get_songs($limit = 0) { + + $results = array(); + + $sql = "SELECT id FROM song WHERE album='$this->id' ORDER BY track, title"; + if ($limit) { $sql .= " LIMIT $limit"; } + $db_results = mysql_query($sql, dbh()); + + while ($r = mysql_fetch_object($db_results)) { + $results[] = new Song($r->id); + } + + return $results; + + } // get_songs + + + /*! + @function format_album + @dicussion reformats this object with f_name, f_songs and f_artist + that contain links etc... + */ + function format_album() { + + $web_path = conf('web_path'); + + /* Truncate the string if it's to long */ + $name = truncate_with_ellipse($this->name,conf('ellipse_threshold_album')); + + $this->f_name = "<a href=\"$web_path/albums.php?action=show&album=" . $this->id . "\" title=\"" . $this->name . "\">" . $name . "</a>"; + $this->f_songs = "<div align=\"center\">" . $this->songs . "</div>"; + if ($this->artist_count == '1') { + $this->f_artist = "<a href=\"$web_path/artists.php?action=show&artist=" . $this->artist_id . "\">" . $this->artist . "</a>"; + } + else { + $this->f_artist = _("Various"); + } + + if ($this->year == '0') { + $this->year = "N/A"; + } + + } // format_album + + /*! + @function get_art + @discussion get art wrapper function + */ + function get_art($fast = 0) { + + /* Check DB first */ + if ($image = $this->get_db_art()) { + return $image; + } + + /* Stop here if we are doing the fast art */ + if ($fast) { return false; } + + /* Create Base Vars */ + $album_art_order = array(); + + /* Attempt to retrive the album art order */ + $config_value = conf('album_art_order'); + $class_methods = get_class_methods('Album'); + + /* If it's not set */ + if (empty($config_value)) { + $album_art_order = array('id3','folder','amazon'); + } + elseif (!is_array($config_value)) { + $album_art_order = array_push($album_art_order,$config_value); + } + else { + $album_art_order = array_merge($album_art_order, conf('album_art_order')); + } + + foreach ($album_art_order AS $method) { + + $method_name = "get_" . $method . "_art"; + + if (in_array($method_name,$class_methods)) { + if ($this->{$method_name}()) { + return $this->get_db_art(); + } // if method finds the art + } // if the method exists + + } // end foreach + + return false; + + } // get_art + + /*! + @function get_id3_art + @discussion looks for art from the id3 tags + */ + function get_id3_art() { + + $songs = $this->get_songs(); + + // Foreach songs in this album + foreach ($songs as $song) { + // If we find a good one, stop looking + $getID3 = new getID3(); + $id3 = $getID3->analyze($song->file); + + if ($id3['format_name'] == "WMA") { + $image = $id3['asf']['extended_content_description_object']['content_descriptors']['13']; + } + else { + $image = $id3['id3v2']['APIC']['0']; + } + if ($image) { + $art = $image['data']; + $mime = $image['mime']; + + // Stick it in the db for next time + $sql = "UPDATE album SET art = '" . sql_escape($art) . "'," . + " art_mime = '" . sql_escape($mime) . "'" . + " WHERE id = '" . $this->id . "'"; + $db_result = mysql_query($sql, dbh()); + + return true; + } // end if image + } // end foreach + + return false; + + } // get_id3_art + + /*! + @function get_folder_art() + @discussion returns the album art from the folder of the mp3s + */ + function get_folder_art() { + + $songs = $this->get_songs(); + + /* See if we are looking for a specific filename */ + $preferred_filename = conf('album_art_preferred_filename'); + + /* Thanks to dromio for origional code */ + /* Added search for any .jpg, png or .gif - Vollmer */ + foreach($songs as $song) { + $dir = dirname($song->file); + + /* Open up the directory */ + $handle = @opendir($dir); + + if (!is_resource($handle)) { + echo "<font class=\"error\">" . _("Error: Unable to open") . " $dir</font><br />\n"; + if (conf('debug')) { log_event($GLOBALS['user']->username,' read ',"Error: Unable to open $dir for album art read"); } + } + + /* Recurse through this dir and create the files array */ + while ( FALSE !== ($file = @readdir($handle)) ) { + $extension = substr($file,strlen($file)-3,4); + + /* If it's an image file */ + if ($extension == "jpg" || $extension == "gif" || $extension == "png" || $extension == "jp2") { + + if ($file == $preferred_filename) { + $found = 1; + $album_art_filename = array('file' => $file, 'ext' => $extension); + break; + } + elseif (!$preferred_filename) { + $found = 1; + $album_art_filename = array('file' => $file, 'ext' => $extension); + break; + } + else { + $found = 1; + $album_art_filename = array('file' => $file, 'ext' => $extension); + } + + } // end if it's an image + + } // end while reading dir + @closedir($handle); + + if ($found) { + $handle = fopen($dir."/".$album_art_filename['file'], "rb"); + $mime = "image/" . $album_art_filename['ext']; + $art = ''; + while(!feof($handle)) { + $art .= fread($handle, 1024); + } + fclose($handle); + $sql = "UPDATE album SET art = '" . sql_escape($art) . "'," . + " art_mime = '" . sql_escape($mime) . "'" . + " WHERE id = '$this->id'"; + $db_results = mysql_query($sql, dbh()); + return true; + } // if found + } // end foreach songs + + return false; + + } // get_folder_art() + + /*! + @function get_db_art() + @discussion returns the album art from the db + */ + function get_db_art() { + + $sql = "SELECT art,art_mime FROM album WHERE id='$this->id' AND art_mime IS NOT NULL"; + $db_results = mysql_query($sql, dbh()); + + $results = mysql_fetch_object($db_results); + + return $results; + + } // get_db_art + + + /*! + @function get_amazon_art + @discussion searches amazon for the + album art + */ + function get_amazon_art() { + + return $this->find_art(); + + } // get_amazon_art + + /*! + @function get_random_songs + @discussion gets a random number, and + a random assortment of songs from this + album + */ + function get_random_songs() { + + $results = array(); + + $sql = "SELECT id FROM song WHERE album='$this->id' ORDER BY RAND() LIMIT " . rand(1,$this->songs); + $db_results = mysql_query($sql, dbh()); + + while ($r = mysql_fetch_array($db_results)) { + $results[] = $r[0]; + } + + return $results; + + } // get_random_songs + + /*! + @function clear_art + @discussion clears the album art from the DB + */ + function clear_art() { + + $sql = "UPDATE album SET art=NULL, art_mime=NULL WHERE id='$this->id'"; + $db_results = mysql_query($sql, dbh()); + + } // clear_art + + /*! + @function find_art + @discussion searches amazon or a url + for the album art + //FIXME: Rename this POS + */ + function find_art($coverurl = '') { + + // No coverurl specified search amazon + if (empty($coverurl)) { + $amazon = new AmazonSearch(conf('amazon_developer_key')); + // Prevent the script from timing out + set_time_limit(0); + $search_term = $this->artist . " " . $this->name; + $amazon->search(array('artist' => $this->artist, 'album' => $this->name, 'keywords' => $serch_term)); + // Only do the second search if the first actually returns something + if (count($amazon->results)) { + $amazon->lookup($amazon->results); + } + + /* Log this if we're doin debug */ + if (conf('debug')) { + log_event($_SESSION['userdata']['username'],' amazon-xml ',"Searched using $search_term with " . conf('amazon_developer_key') . " as key " . count($amazon->results) . " results found"); + } + + //FIXME: For now just pull the first one we find + foreach ($amazon->results as $key=>$value) { + $results = $value; + break; + } //FIXME: + + } // if no cover + // If we've specified a coverurl, create a fake Amazon array with it + else { + $results = array('LargeImage' => $coverurl); + } + + // If we have results of some kind + if (is_array($results)) { + + /* Recurse through the images found */ + $possible_keys = array("LargeImage","MediumImage","SmallImage"); + + foreach ($possible_keys as $key) { + if (strlen($results[$key])) { + break; + } + + + } // foreach + + // Rudimentary image type detection, only JPG and GIF allowed. + if (substr($results[$key], -4 == ".jpg")) { + $mime = "image/jpg"; + } + elseif (substr($results[$key], -4 == ".gif")) { + $mime = "image/gif"; + } + else { + return false; + } + + /* Create Snoopy Object and pull info */ + $snoopy = new Snoopy; + $snoopy->fetch($results[$key]); + $art = $snoopy->results; + + // Skip 1x1 size images + if (function_exists('ImageCreateFromString')) { + $im = @ImageCreateFromString($art); + if (@imagesx($im) == 1 || @imagesy($im) == 1 && $im) { + return false; + } + } + + // Push the image into the database + $sql = "UPDATE album SET art = '" . sql_escape($art) . "'," . + " art_mime = '" . sql_escape($mime) . "'" . + " WHERE id = '$this->id'"; + $db_results = mysql_query($sql, dbh()); + + return true; + + } // if we've got something + + /* Default to false */ + return false; + + } // find_art + + /*! + @function get_song_ids + @discussion returns a list of song_ids on the album + get_songs returns a list of song objects + */ + + // it seems get_songs really should call this, + // but I don't feel comfortable imposing that - RCR + function get_song_ids( $limit = 0 ) { + $results = array(); + $sql = "SELECT id FROM song WHERE album='$this->id' ORDER BY track, title"; + if ($limit) { $sql .= " LIMIT $limit"; } + $db_results = mysql_query($sql, dbh()); + + while ($r = mysql_fetch_object($db_results)) { + $results[] = $r->id; + } + return( $results ); + } // get_song_ids + +} //end of album class + +?> diff --git a/modules/class/artist.php b/modules/class/artist.php new file mode 100644 index 00000000..a0b4caa7 --- /dev/null +++ b/modules/class/artist.php @@ -0,0 +1,207 @@ +<?php +/* + + Copyright (c) 2004 Ampache.org + All rights reserved. + + This program 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 + of the License, or (at your option) any later version. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +/*! + @header Artist Class +*/ + +class Artist { + + /* Variables from DB */ + var $id; + var $name; + var $songs; + var $albums; + var $prefix; + + /*! + @function Artist + @discussion Song class, for modifing a song. + @param $song_id The ID of the song + */ + function Artist($song_id = 0) { + + /* If we have passed an id then do something */ + if ($song_id) { + + /* Assign id for use in get_info() */ + $this->id = $song_id; + + /* Get the information from the db */ + if ($info = $this->get_info()) { + + /* Assign Vars */ + $this->name = $info->name; + $this->prefix = $info->prefix; + } // if info + + } // if song_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 artist WHERE id='$this->id'"; + $db_results = mysql_query($sql, dbh()); + + $results = mysql_fetch_object($db_results); + + return $results; + + } //get_info + + /*! + @function get_albums + @discussion gets the albums for this artist + */ + function get_albums() { + + $results = array(); + + $sql = "SELECT DISTINCT(album.id) FROM song,album WHERE song.album=album.id AND song.artist='$this->id' ORDER BY album.name"; + $db_results = mysql_query($sql, dbh()); + + while ($r = mysql_fetch_object($db_results)) { + $results[] = new Album($r->id); + } + + return $results; + + } // get_albums + + /*! + @function get_songs + @discussion gets the songs for this artist + */ + function get_songs() { + + $sql = "SELECT song.id FROM song WHERE song.artist='$this->id'"; + $db_results = mysql_query($sql, dbh()); + + while ($r = mysql_fetch_object($db_results)) { + $results[] = new Song($r->id); + } + + return $results; + + } // get_songs + + /*! + @function get_random_songs + @discussion gets a random number, and + a random assortment of songs from this + album + */ + function get_random_songs() { + + $results = array(); + + $sql = "SELECT id FROM song WHERE artist='$this->id' ORDER BY RAND() LIMIT " . rand(1,$this->songs); + $db_results = mysql_query($sql, dbh()); + + while ($r = mysql_fetch_array($db_results)) { + $results[] = $r[0]; + } + + return $results; + + } // get_random_songs + + /*! + @function get_count + @discussion gets the album and song count of + this artist + */ + function get_count() { + + /* Define vars */ + $songs = 0; + $albums = 0; + + $sql = "SELECT COUNT(song.id) FROM song WHERE song.artist='$this->id' GROUP BY song.album"; + $db_results = mysql_query($sql, dbh()); + + while ($r = mysql_fetch_array($db_results)) { + $songs += $r[0]; + $albums++; + } + + /* Set Object Vars */ + $this->songs = $songs; + $this->albums = $albums; + + return true; + + } // get_count + + /*! + @function format_artist + @discussion this function takes an array of artist + information and reformats the relevent values + so they can be displayed in a table for example + it changes the title into a full link. + */ + function format_artist() { + + /* Combine prefix and name, trim then add ... if needed */ + $name = truncate_with_ellipse(trim($this->prefix . " " . $this->name)); + + $this->f_name = $this->name; + $this->full_name = trim($this->prefix . " " . $this->name); + //FIXME: This shouldn't be set like this, f_name should be like this + $this->link = "<a href=\"" . conf('web_path') . "/artists.php?action=show&artist=" . $this->id . "\" title=\"" . $this->full_name . "\">" . + $name . "</a>"; + $this->name = $this->link; + return $artist; + + } // format_artist + + + /*! + @function show_albums + @discussion displays the show albums by artist page + */ + function show_albums() { + + /* Set Vars */ + $web_path = conf('web_path'); + + + $albums = $this->get_albums(); + $this->format_artist(); + $artist = $this; + + require (conf('prefix') . "/templates/show_artist.inc"); + + } // show_albums + + +} //end of artist class + +?> diff --git a/modules/class/catalog.php b/modules/class/catalog.php new file mode 100644 index 00000000..9affc95a --- /dev/null +++ b/modules/class/catalog.php @@ -0,0 +1,1934 @@ +<? +/* + + This program 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 + of the License, or (at your option) any later version. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +/*! + @header Catalog Class + This class handles all actual work in regards to the catalog, it contains functions for creating/listing/updated the catalogs. +*/ + +class Catalog { + + var $name; + var $last_update; + var $last_add; + var $id3_set_command; + var $rename_pattern; + var $sort_pattern; + var $catalog_type; + + // Used in functions + var $albums = array(); + var $artists = array(); + var $genres = array(); + + /*! + @function Catalog + @discussion Catalog class constructor, pulls catalog information + @param $catalog_id The ID of the catalog you want to build information from + */ + function Catalog($catalog_id = 0) { + + /* If we have passed an id then do something */ + if ($catalog_id) { + /* Assign id for use in get_info() */ + $this->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 "<font class=\"error\">" . _("Error: Unable to open") . " $path</font><br />\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 "<font class=\"error\">" . _("Error: Unable to change to directory") . " $path</font><br />\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 "<font class=\"error\">" . _("Error: Unable to get filesize for") . " $full_file <br />"; + 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 . . . .<br />\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. . . . <br />\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") . ".<br />\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") . "<br />\n"; } + } + if ($methods['amazon'] && !$found) { + $found = $album->get_amazon_art(); + if ($found && $debug) { echo _("Found on Amazon") . "<br />\n"; } + } + if ($methods['folder'] && !$found) { + $found = $album->get_folder_art(); + if ($found && $debug) { echo _("Found in Folder") . "<br />\n"; } + } + if (count($methods) == '0' && !$found) { + $found = $album->get_art(); + if ($found && $debug) { echo _("Found") . "<br />\n"; } + } + + if (!$found && $debug) { echo "<font class=\"error\">" . _("Not Found") . "</font><br />\n"; } + + if ($found) { $art_found++; } + + + /* Stupid little cutesie thing */ + $search_count++; + if ( !($search_count%conf('catalog_echo_count')) ) { + echo _("Searched") . " $search_count. . . . <br />\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. . .<br />\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 "<font class=\"error\">" . _("Error: Unable to open") . " $path</font><br />\n"; } + + /* Change dir so we can tell if it's a directory */ + if (!@chdir($path)) { + echo "<font class=\"error\">Error: Unable to change to $path directory</font><br />\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 "<br /><b>" . _("Starting Dump Album Art") . ". . .</b><br><br />\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. . . <br />\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 "<font class=\"error\">" . _("Error unable to open file for writting") . " [$file] </font><br />\n"; + } + + } // end if image + + } // end foreach + + echo "<br /><b>" . _("Album Art Dump Complete") . "</b> "; + echo "<a href=\"" . conf('web_path') . "/admin/catalog.php" . "\">[" . _("Return") . "]</a>"; + + 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]<br />\n"; + flush(); + + + if ($this->catalog_type == 'remote') { + echo _("Running Remote Sync") . ". . .<br /><br />"; + 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 "<br />\n<b>" . _("Starting Album Art Search") . ". . .</b><br />\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 . "]<br />\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 "<dl>\n\t<li>"; + echo "<b>$song->file " . _("Updated") . "</b>\n"; + echo $info['text']; + echo "\t</li>\n</dl><hr align=\"left\" width=\"50%\" />"; + flush(); + } // if change + else { + echo"<dl>\n\t<li>"; + echo "<b>$song->file</b><br />" . _("No Update Needed") . "\n"; + echo "\t</li>\n</dl><hr align=\"left\" width=\"50%\" />"; + 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") . " <b>[$this->name]</b> " . _("catalog") . "<br /><br />\n"; + flush(); + + if ($this->catalog_type == 'remote') { + echo _("Running Remote Update") . ". . .<br /><br />"; + 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 "<b>" . _("Starting Album Art Search") . ". . .</b><br />\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<br />" . _("Catalog Update Finished") . "... " . _("Total Time") . " [" . date("i:s",$time_diff) . "] " . + _("Total Songs") . " [" . $this->count . "] " . _("Songs Per Seconds") . " [" . $song_per_sec . "]<br /><br />"; + + } // 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 "<font class=\"error\"><b>" . _("Error") . "</b>: " . _("Unable to load XMLRPC library, make sure XML-RPC is enabled") . "<br />\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("<b>Reading Remote Catalog: $catalog_name</b> [$this->path]<br />\n"); + } + } + else { + $error_msg = _("Error connecting to") . " " . $server . " " . _("Code") . ": " . $response->faultCode() . " " . _("Reason") . ": " . $response->faultString(); + log_event($_SESSION['userdata']['username'],'xmlrpc',$error_msg); + echo "<p class=\"error\">$error_msg</p>"; + 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 "<p class=\"error\">$error_msg</p>"; + } + + echo "<p>" . _("Completed updating remote catalog(s)") . ".</p><hr>\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 <b>[" . $this->name . "]</b> Catalog...<br /><br />"; + 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. . . . <br />\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 "<font class=\"error\">Error File Not Found or 0 Bytes: " . $results->file . "</font><br />"; + 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 "<b>" . _("Catalog Clean Done") . " [" . count($dead_files) . "] " . _("files removed") . "</b><br />\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") . " <b>[ $this->name ]</b> " . _("Catalog") . "<br />\n"; + echo $number . " " . _("songs found checking tag information.") . "<br /><br />\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 "<dl>\n\t<li>"; + echo "<b>$song->file " . _("Updated") . "</b>\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 "<br /><b>" . _("Searching for new Album Art") . ". . .$is_found</b><br />\n"; + unset($found,$is_found); + } + elseif (isset($searched_albums[$album_id])) { + echo "<br /><b>" . _("Album Art Already Found") . ". . .</b><br />\n"; + } + echo "\t</li>\n</dl>\n<hr align=\"left\" width=\"50%\" />\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. . . . <br />\n"; + flush(); + } //echos song count + + } // end if file exists + + else { + echo "<dl>\n <li>"; + echo "<b>$song->file does not exist or is not readable</b>\n"; + echo " </li>\n</dl>\n<hr align=\"left\" width=\"50%\" />\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.<br /><br />"; + + } //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 <br />"; + 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 <br />"; + 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 "<span style=\"color: #F00;\">Error Adding $file </span><br />$sql<br />"; + 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 "<span style=\"color: #FOO;\">Error Adding Remote $url </span><br />$sql<br />\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 + +?> diff --git a/modules/class/error.php b/modules/class/error.php new file mode 100644 index 00000000..9283e29d --- /dev/null +++ b/modules/class/error.php @@ -0,0 +1,94 @@ +<?php +/* + + Copyright (c) 2001 - 2005 Ampache.org + All rights reserved. + + This program 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 + of the License, or (at your option) any later version. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +/*! + @header Error handler requires error_results() function + +*/ + + +class Error { + + //Basic Componets + var $error_state=0; + + /* Generated values */ + var $errors = array(); + + /*! + @function error + @discussion this is the constructor for the error class + */ + function Error() { + + return true; + + } //constructor + + /*! + @function add_error + @discussion adds an error to the static array stored in + error_results() + */ + function add_error($name,$description) { + + $array = array($name=>$description); + + error_results($array); + $this->error_state = 1; + + return true; + + } // add_error + + + /*! + @function has_error + @discussion returns true if the name given has an error, + false if it doesn't + */ + function has_error($name) { + + $results = error_results($name); + + if (!empty($results)) { + return true; + } + + return false; + + } // has_error + + /*! + @function print_error + @discussion prints out the error for a name if it exists + */ + function print_error($name) { + + if ($this->has_error($name)) { + echo "<div class=\"fatalerror\">" . error_results($name) . "</div>\n"; + } + + } // print_error + +} //end error class +?> diff --git a/modules/class/playlist.php b/modules/class/playlist.php new file mode 100644 index 00000000..130537af --- /dev/null +++ b/modules/class/playlist.php @@ -0,0 +1,366 @@ +<? +/* + + Copyright (c) 2001 - 2005 Ampache.org + All rights reserved. + + This program 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 + of the License, or (at your option) any later version. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +*/ +/*! + @header Playlist Class + This class handles all actual work in regards to playlists. +*/ + +class Playlist { + + // Variables from DB + var $id; + var $name; + var $owner; + var $type; + var $time; + var $items; + + /*! + @function Playlist + @discussion Playlist class + @param $playlist_id The ID of the playlist + */ + function Playlist($playlist_id = 0) { + + /* If we have an id then do something */ + if ($playlist_id) { + // Assign id + $this->id = $playlist_id; + + // Get the information from the db + $this->refresh_object(); + } + + } + + + + /*! + @function refresh_object + @discussion Reads playlist information from the db and updates the Playlist object with it + */ + function refresh_object() { + + $dbh = dbh(); + + if ($this->id) { + $sql = "SELECT name, owner, type, date FROM playlist" . + " WHERE id = '$this->id'"; + $db_results = mysql_query($sql, $dbh); + + if ($r = mysql_fetch_object($db_results)) { + $this->name = $r->name; + $this->owner = $r->owner; + $this->type = $r->type; + $this->time = $r->date; + $this->items = array(); + + // Fetch playlist items + $sql = "SELECT song, track FROM playlist_data" . + " WHERE playlist = '$this->id'" . + " ORDER BY track"; + $db_results = mysql_query($sql, $dbh); + + while ($r = mysql_fetch_object($db_results)) { + $this->items[] = array("song_id" => $r->song, "track" => $r->track); + } + } + + return TRUE; + } + + return FALSE; + + } + + + /*! + @function create_playlist + @discussion Creates an empty playlist, given a name, owner_id, and type. + */ + function create_playlist($name, $owner_id, $type) { + + $dbh = dbh(); + + if (isset($name) && isset($owner_id) && isset($type) && $this->check_type($type)) { + $name = sql_escape($name); + $sql = "INSERT INTO playlist" . + " (name, owner, type)" . + " VALUES ('$name', '$owner_id', '$type')"; + $db_results = mysql_query($sql, $dbh); + if ($this->id = mysql_insert_id($dbh)) { + $this->refresh_object(); + return TRUE; + } + } + + return FALSE; + + } + + + /*! + @function delete + @discussion Deletes the playlist. + */ + function delete() { + + $dbh = dbh(); + + if ($this->id) { + $sql = "DELETE FROM playlist_data" . + " WHERE playlist = '$this->id'"; + $db_results = mysql_query($sql, $dbh); + + $sql = "DELETE FROM playlist" . + " WHERE id = '$this->id'"; + $db_results = mysql_query($sql, $dbh); + + // Clean up this object + foreach (get_object_vars($this) as $var) { + unset($var); + } + + return TRUE; + } + + return FALSE; + + } + + + /*! + @function update_track_numbers + @discussion Reads an array of song_ids and track numbers to update + */ + function update_track_numbers($changes) { + + $dbh = dbh(); + + if ($this->id && isset($changes) && is_array($changes)) { + foreach ($changes as $change) { + // Check for valid song_id + $sql = "SELECT count(*) FROM song WHERE id = '" . $change['song_id'] . "'"; + $db_results = mysql_query($sql, $dbh); + $r = mysql_fetch_row($db_results); + if ($r[0] == 1) { + $sql = "UPDATE playlist_data SET" . + " track = '" . $change['track'] . "'" . + " WHERE playlist = '$this->id'". + " AND song = '" . $change['song_id'] . "'"; + $db_results = mysql_query($sql, $dbh); + } + } + + // Refresh the playlist object + $this->refresh_object(); + + return TRUE; + } + + return FALSE; + + } + + + /*! + @function add_songs + @discussion Reads an array of song_ids to add to the playlist + */ + function add_songs($song_ids) { + + $dbh = dbh(); + + if ($this->id && isset($song_ids) && is_array($song_ids)) { + foreach ($song_ids as $song_id) { + $song = new Song($song_id); + if (isset($song->id)) { + $sql = "INSERT INTO playlist_data" . + " (playlist, song, track)" . + " VALUES ('$this->id', '$song->id', '$song->track')"; + $db_results = mysql_query($sql, $dbh); + } + } + + // Refresh the playlist object + $this->refresh_object(); + + return TRUE; + } + + return FALSE; + + } + + + /*! + @function remove_songs + @discussion Reads an array of song_ids to remove from the playlist + */ + function remove_songs($song_ids) { + + $dbh = dbh(); + + if ($this->id && isset($song_ids) && is_array($song_ids)) { + foreach ($song_ids as $song_id) { + $sql = "DELETE FROM playlist_data" . + " WHERE song = '$song_id'" . + " AND playlist = '$this->id'"; + $db_results = mysql_query($sql, $dbh); + } + + // Refresh the playlist object + $this->refresh_object(); + + return TRUE; + } + + return FALSE; + + } + + + /*! + @function check_type + @discussion Checks for a valid playlist type + */ + function check_type($type) { + + if (isset($type)) { + if ($type === 'public' || $type === 'private') { + return TRUE; + } + } + + return FALSE; + + } + + + /*! + @function update_type + @discussion Updates the playlist type + */ + function update_type($type) { + + $dbh = dbh(); + + if ($this->id && isset($type) && $this->check_type($type)) { + $sql = "UPDATE playlist SET type = '$type'" . + " WHERE id = '$this->id'"; + $db_results = mysql_query($sql, $dbh); + + // Refresh the playlist object + $this->refresh_object(); + + return TRUE; + } + + return FALSE; + + } + + + /*! + @function update_name + @discussion Updates the playlist name + */ + function update_name($name) { + + $dbh = dbh(); + + if ($this->id && isset($name)) { + $name = sql_escape($name); + $sql = "UPDATE playlist SET name = '$name'" . + " WHERE id = '$this->id'"; + $db_results = mysql_query($sql, $dbh); + + // Refresh the playlist object + $this->refresh_object(); + + return TRUE; + } + + return FALSE; + + } + + + /*! + @function get_songs + @discussion Returns an array of song_ids for the playlist + */ + function get_songs() { + + $song_ids = array(); + + if ($this->id && is_array($this->items)) { + foreach ($this->items as $item) { + $song_ids[] = $item['song_id']; + } + } + + return $song_ids; + + } // get_songs + + /*! + @function get_random_songs + @discussion gets a random set of the songs in this + playlist + */ + function get_random_songs() { + + $sql = "SELECT COUNT(song) FROM playlist_data WHERE playlist = '$this->id'"; + $db_results = mysql_query($sql, dbh()); + + $total_songs = mysql_fetch_row($db_results); + + $limit = rand(1,$total_songs[0]); + + // Fetch playlist items + $sql = "SELECT song, track FROM playlist_data" . + " WHERE playlist = '$this->id'" . + " ORDER BY RAND() LIMIT $limit"; + $db_results = mysql_query($sql, dbh()); + while ($r = mysql_fetch_object($db_results)) { + $song_ids[] = $r->song; + } + + return $song_ids; + } // get_random_songs + + /*! + @function show_import + @discussion shows the import from file template + */ + function show_import() { + + require (conf('prefix') . "/templates/show_import_playlist.inc.php"); + + } // show_import + + +} //end of playlist class + +?> diff --git a/modules/class/song.php b/modules/class/song.php new file mode 100644 index 00000000..f42f55a8 --- /dev/null +++ b/modules/class/song.php @@ -0,0 +1,657 @@ +<? +/* + + Copyright (c) 2004 Ampache.org + All rights reserved. + + This program 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 + of the License, or (at your option) any later version. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +/*! + @header Song Class +*/ + +class Song { + + /* Variables from DB */ + var $id; + var $file; + var $album; + var $artist; + var $title; + var $year; + var $comment; + var $bitrate; + var $rate; + var $mode; + var $size; + var $time; + var $track; + var $genre; + var $type; + var $mime; + var $played; + var $addition_time; + var $update_time; + + /*! + @function Song + @discussion Song class, for modifing a song. + @param $song_id The ID of the song + */ + function Song($song_id = 0) { + + /* If we have passed an id then do something */ + if ($song_id) { + + /* Assign id for use in get_info() */ + $this->id = $song_id; + + /* Get the information from the db */ + if ($info = $this->get_info()) { + + /* Assign Vars */ + $this->file = $info->file; + $this->album = $info->album; + $this->artist = $info->artist; + $this->title = $info->title; + $this->comment = $info->comment; + $this->year = $info->year; + $this->bitrate = $info->bitrate; + $this->rate = $info->rate; + $this->mode = $info->mode; + $this->size = $info->size; + $this->time = $info->time; + $this->track = $info->track; + $this->genre = $info->genre; + $this->addition_time = $info->addition_time; + $this->catalog = $info->catalog; + $this->played = $info->played; + $this->update_time = $info->update_time; + $this->flagid = $info->flagid; + $this->flaguser = $info->flaguser; + $this->flagtype = $info->flagtype; + $this->flagcomment = $info->flagcomment; + $this->status = $info->status; + + // Format the Type of the song + $this->format_type(); + } + + } + + } //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 song.id,file,catalog,album,song.comment,year,artist,". + "title,bitrate,rate,mode,size,time,track,genre,played,status,update_time,". + "addition_time,flagged.id as flagid,flagged.user as flaguser,flagged.type ". + "as flagtype,flagged.date as flagdate,flagged.comment as flagcomment FROM ". + "song LEFT JOIN flagged ON song.id = flagged.song WHERE song.id = '$this->id'"; + $db_results = mysql_query($sql, dbh()); + + $results = mysql_fetch_object($db_results); + + return $results; + + } //get_info + + /*! + @function format_type + @discussion gets the type of song we are trying to + play, used to set mime headers and to trick + players into playing them correctly + */ + function format_type() { + + preg_match('/\.([A-Za-z0-9]+)$/', $this->file,$results); + + $this->type = $results[1]; + + switch ($this->type) { + case "spx": + case "ogg": + $this->mime = "application/x-ogg"; + break; + case "wma": + case "WMA": + case "asf": + $this->mime = "audio/x-ms-wma"; + break; + case "mp3": + case "mpeg3": + $this->mime = "audio/mpeg"; + break; + case "rm": + $this->mime = "audio/x-realaudio"; + break; + case "flac"; + $this->mime = "audio/x-flac"; + break; + case 'aac': + case 'mp4': + case 'm4a': + $this->mime = "audio/mp4"; + break; + case 'mpc': + $this->mime = "audio/x-musepack"; + break; + default: + $this->mime = "audio/mpeg"; + break; + } + + } // get_type + /*! + @function get_album_songs + @discussion gets an array of song objects based on album + */ + function get_album_songs($album_id) { + + $sql = "SELECT id FROM song WHERE album='$album_id'"; + $db_results = mysql_query($sql, libglue_param(libglue_param('dbh_name'))); + + while ($r = mysql_fetch_object($db_results)) { + $results[] = new Song($r->id); + } + + return $results; + + } // get_album_songs + + /*! + @function get_album_name + @discussion gets the name of $this->album + */ + function get_album_name() { + + $sql = "SELECT name,prefix FROM album WHERE id='$this->album'"; + $db_results = mysql_query($sql, dbh()); + + $results = mysql_fetch_array($db_results); + + if ($results['prefix']) { + return $results['prefix'] . " " .$results['name']; + } + else { + return $results['name']; + } + + } // get_album_name + + /*! + @function get_artist_name + @discussion gets the name of $this->artist + */ + function get_artist_name() { + + $sql = "SELECT name,prefix FROM artist WHERE id='$this->artist'"; + $db_results = mysql_query($sql, dbh()); + + $results = mysql_fetch_array($db_results); + + if ($results['prefix']) { + return $results['prefix'] . " " . $results['name']; + } + else { + return $results['name']; + } + + } // get_album_name + + /*! + @function get_genre_name + @discussion gets the name of the genre + */ + function get_genre_name() { + + $sql = "SELECT name FROM genre WHERE id='$this->genre'"; + $db_results = mysql_query($sql, dbh()); + + $results = mysql_fetch_array($db_results); + + return $results['name']; + + } // get_genre_name + /*! + @function compare_song_information + @discussion this compares the new ID3 tags of a file against + the ones in the database to see if they have changed + it returns false if nothing has changes, or the true + if they have. + @param $song The origional song object + @param $new_song The new version of the song + */ + function compare_song_information($song,$new_song) { + + if ($song->title == "No Title Found") { $song->title = false; } + + + if (trim($song->title) != trim($new_song->title) && strlen($new_song->title) > 0) { + $array['change'] = true; + $array['text'] .= "<br />" . _("Title") . " [$song->title] " . _("updated to") . " [$new_song->title]\n"; + } // if title + if ($song->bitrate != $new_song->bitrate) { + $array['change'] = true; + $array['text'] .= "<br />" . _("Bitrate") . " [$song->bitrate] " . _("updated to") . " [$new_song->bitrate]\n"; + } // if bitrate + if ($song->rate != $new_song->rate) { + $array['change'] = true; + $array['text'] .= "<br />" . _("Rate") . " [$song->rate] " . _("updated to") . " [$new_song->rate]\n"; + } // if rate + if ($song->mode != $new_song->mode) { + $array['change'] = true; + $array['text'] .= "<br />" . _("Mode") . " [$song->mode] " . _("updated to") . " [$new_song->mode]\n"; + } // if mode + if ($song->time != $new_song->time) { + $array['change'] = true; + $array['text'] .= "<br />" . _("Time") . " [$song->time] " . _("updated to") . " [$new_song->time]\n"; + } // if time + if ($song->track != $new_song->track) { + $array['change'] = true; + $array['text'] .= "<br />" . _("Track") . " [$song->track] " . _("updated to") . " [$new_song->track]\n"; + } // if track + if ($song->size != $new_song->size) { + $array['change'] = true; + $array['text'] .= "<br />" . _("Filesize") . " [$song->size] " . _("updated to") . " [$new_song->size]\n"; + } // if artist + if ($song->artist != $new_song->artist) { + $array['change'] = true; + $name = $song->get_artist_name(); + $array['text'] .= "<br />" . _("Artist") . " [$name] " . _("updated to") . " [$new_song->f_artist]\n"; + } // if artist + if ($song->album != $new_song->album) { + $array['change'] = true; + $name = $song->get_album_name() . " - " . $song->year; + $array['text'] .= "<br />" . _("Album") . " [$name] " . _("updated to") . " [$new_song->f_album]\n"; + } // if album + if ($song->year != $new_song->year) { + $array['change'] = true; + $array['text'] .= "<br />" . _("Year") . " [$song->year] " . _("updated to") . " [$new_song->year]\n"; + } // if year + if (trim($song->comment) != trim($new_song->comment)) { + $array['change'] = true; + $array['text'] .= "<br />" . _("Comment") . " [$song->comment] " . _("updated to") . " [$new_song->comment]\n"; + } // if comment + if ($song->genre != $new_song->genre) { + $array['change'] = true; + $name = $song->get_genre_name(); + $array['text'] .= "<br />" . _("Genre") . " [$name] " . _("updated to") . " [$new_song->f_genre]\n"; + } // if genre + + return $array; + + } // compare_song_information + + /*! + @function update_song + @discussion this is the main updater for a song it actually + calls a whole bunch of mini functions to update + each little part of the song... lastly it updates + the "update_time" of the song + @param $song_id The id of the song we are updating + @param $new_song A object with the new song params + */ + function update_song($song_id, $new_song) { + + $this->update_title($new_song->title,$song_id); + $this->update_bitrate($new_song->bitrate,$song_id); + $this->update_rate($new_song->rate,$song_id); + $this->update_mode($new_song->mode,$song_id); + $this->update_size($new_song->size,$song_id); + $this->update_time($new_song->time,$song_id); + $this->update_track($new_song->track,$song_id); + $this->update_artist($new_song->artist,$song_id); + $this->update_genre($new_song->genre,$song_id); + $this->update_album($new_song->album,$song_id); + $this->update_year($new_song->year,$song_id); + $this->update_comment($new_song->comment,$song_id); + $this->update_played('false',$song_id); + $this->update_utime($song_id); + + } // update_song + + /*! + @function update_year + @discussion update the year tag + */ + function update_year($new_year,$song_id=0) { + + if ($_SESSION['userdata']['access'] === 'admin') { + $this->update_item('year',$new_year,$song_id); + } + } // update_year + + /*! + @function update_comment + @discussion updates the comment field + */ + function update_comment($new_comment,$song_id=0) { + + if ($_SESSION['userdata']['access'] === 'admin') { + $this->update_item('comment',$new_comment,$song_id); + } + } // update_comment + + /*! + @function update_title + @discussion updates the title field + */ + function update_title($new_title,$song_id=0) { + + if ($_SESSION['userdata']['access'] === 'admin') { + $this->update_item('title',$new_title,$song_id); + } + } // update_title + + /*! + @function update_bitrate + @discussion updates the bitrate field + */ + function update_bitrate($new_bitrate,$song_id=0) { + + if ($_SESSION['userdata']['access'] === 'admin') { + $this->update_item('bitrate',$new_bitrate,$song_id); + } + + } // update_bitrate + + /*! + @function update_rate + @discussion updates the rate field + */ + function update_rate($new_rate,$song_id=0) { + + if ($_SESSION['userdata']['access'] === 'admin') { + $this->update_item('rate',$new_rate,$song_id); + } + + } // update_rate + + /*! + @function update_mode + @discussion updates the mode field + */ + function update_mode($new_mode,$song_id=0) { + + if ($_SESSION['userdata']['access'] === 'admin') { + $this->update_item('mode',$new_mode,$song_id); + } + + } // update_mode + + /*! + @function update_size + @discussion updates the size field + */ + function update_size($new_size,$song_id=0) { + + if ($_SESSION['userdata']['access'] === 'admin') { + $this->update_item('size',$new_size,$song_id); + } + + } // update_size + + /*! + @function update_time + @discussion updates the time field + */ + function update_time($new_time,$song_id=0) { + + if ($_SESSION['userdata']['access'] === 'admin') { + $this->update_item('time',$new_time,$song_id); + } + + } // update_time + + /*! + @function update_track + @discussion this updates the track field + */ + function update_track($new_track,$song_id=0) { + + if ($_SESSION['userdata']['access'] === 'admin') { + $this->update_item('track',$new_track,$song_id); + } + + } // update_track + + /*! + @function update_artist + @discussion updates the artist field + */ + function update_artist($new_artist,$song_id=0) { + + if ($_SESSION['userdata']['access'] === 'admin') { + $this->update_item('artist',$new_artist,$song_id); + } + + } // update_artist + + /*! + @function update_genre + @discussion updates the genre field + */ + function update_genre($new_genre,$song_id=0) { + + if ($_SESSION['userdata']['access'] === 'admin') { + $this->update_item('genre',$new_genre,$song_id); + } + + } // update_genre + + /*! + @function update_album + @discussion updates the album field + */ + function update_album($new_album,$song_id=0) { + + if ($_SESSION['userdata']['access'] === 'admin') { + $this->update_item('album',$new_album,$song_id); + } + + } // update_album + + /*! + @function update_utime + @discussion sets a new update time + */ + function update_utime($song_id=0,$time=0) { + + if (!$time) { $time = time(); } + + if ($_SESSION['userdata']['access'] === 'admin') { + $this->update_item('update_time',$time,$song_id); + } + + } // update_utime + + /*! + @function update_played + @discussion sets the played flag + */ + function update_played($new_played,$song_id=0) { + + $this->update_item('played',$new_played,$song_id); + + } // update_played + + + /*! + @function update_enabled + @discussion sets the enabled flag + */ + function update_enabled($new_enabled,$song_id=0) { + + if ($_SESSION['userdata']['access'] === 'admin' || $_SESSION['userdata']['access'] === '100') { + $this->update_item('status',$new_enabled,$song_id); + } + + } // update_enabled + + /*! + @function update_item + @discussion this is a generic function that is called + by all the other update functions... + @param $field The field we are updating + @param $value The new value for said field + @param $song_id ID of the song, uses $this->id by default + */ + function update_item($field,$value,$song_id=0) { + + if (!$song_id) { $song_id = $this->id; } + + $value = sql_escape($value); + + $sql = "UPDATE song SET $field='$value' WHERE id='$song_id'"; + $db_results = mysql_query($sql, dbh()); + + $this->{$field} = $value; + + } //update_item + + + /*! + @function format_song + @discussion this takes a song object + and formats it for display + and returns the object cleaned up + */ + function format_song() { + + // Format the filename + preg_match("/^.*\/(.*?)$/",$this->file, $short); + $this->f_file = htmlspecialchars($short[1]); + + // Format the album name + $this->f_album_full = $this->get_album_name(); + $this->f_album = truncate_with_ellipse($this->f_album_full,conf('ellipse_threshold_album')); + + // Format the artist name + $this->f_artist_full = $this->get_artist_name(); + $this->f_artist = truncate_with_ellipse($this->f_artist_full,conf('ellipse_threshold_artist')); + + // Format the title + $this->f_title = truncate_with_ellipse($this->title,conf('ellipse_threshold_title')); + + // Create A link inclduing the title + $this->f_link = "<a href=\"" . conf('web_path') . "/song.php?action=m3u&song=" . $this->id . "\">$this->f_title</a>"; + + // Format the Bitrate + $this->f_bitrate = intval($this->bitrate/1000) . "-" . strtoupper($this->mode); + + // Format Genre + $this->f_genre = $this->get_genre_name(); + + // Format the Time + $min = floor($this->time/60); + $sec = sprintf("%02d", ($this->time%60) ); + $this->f_time = $min . ":" . $sec; + + // Format the size + $this->f_size = sprintf("%.2f",($this->size/1048576)); + + // Set style + if (preg_match("/id3/", $this->flagtype)) { $this->f_style = "style=\"color: #33c;\""; } + elseif (preg_match("/(mp3|del|sort|ren)/", $this->flagtype)) { $this->f_style = "style=\"color: #C00;\""; } + if ($this->status === 'disabled') { $this->f_style = "style=\"text-decoration: line-through;\""; } + + return true; + + } // format_song + + /*! + * @function get_rel_path + * @discussion returns the path of the song file stripped of the catalog path + * used for mpd playback + */ + function get_rel_path($file_path=0,$catalog_id=0) { + + if (!$file_path) { + $info = $this->get_info( ); + $file_path = $info->file; + } + if (!$catalog_id) { + $catalog_id = $info->catalog; + } + $catalog = new Catalog( $catalog_id ); + $info = $catalog->get_info( ); + $catalog_path = $info->path; + return( str_replace( $catalog_path . "/", "", $file_path ) ); + + } // get_rel_path + + + /*! + @function fill_info + @discussion this takes the $results from getid3 and attempts to fill + as much information as possible from the file name using the + pattern set in the current catalog + */ + function fill_info($results,$pattern,$catalog_id,$key) { + + $filename = $this->get_rel_path($results['file'],$catalog_id); + + if (!strlen($results[$key]['title'])) { + $results[$key]['title'] = $this->get_info_from_filename($filename,$pattern,"%t"); + } + if (!strlen($results[$key]['track'])) { + $results[$key]['track'] = $this->get_info_from_filename($filename,$pattern,"%T"); + } + if (!strlen($results[$key]['year'])) { + $results[$key]['year'] = $this->get_info_from_filename($filename,$pattern,"%y"); + } + if (!strlen($results[$key]['album'])) { + $results[$key]['album'] = $this->get_info_from_filename($filename,$pattern,"%A"); + } + if (!strlen($results[$key]['artist'])) { + $results[$key]['artist'] = $this->get_info_from_filename($filename,$pattern,"%a"); + } + if (!strlen($results[$key]['genre'])) { + $results[$key]['genre'] = $this->get_info_from_filename($filename,$pattern,"%g"); + } + + return $results; + + } // fill_info + + /*! + @function get_info_from_filename + @discussion get information from a filename based on pattern + */ + function get_info_from_filename($file,$pattern,$tag) { + + $preg_pattern = preg_replace("/$tag/","(.+)",$pattern); + $preg_pattern = preg_replace("/\%\w/",".+",$preg_pattern); + $preg_pattern = "/" . str_replace("/","\/",$preg_pattern) . "\..+/"; + + preg_match($preg_pattern,$file,$matches); + + return stripslashes($matches[1]); + + } // get_info_from_filename + +} //end of song class + +?> diff --git a/modules/class/stream.php b/modules/class/stream.php new file mode 100644 index 00000000..3472127a --- /dev/null +++ b/modules/class/stream.php @@ -0,0 +1,291 @@ +<?php +/* + + Copyright (c) 2001 - 2005 Ampache.org + All rights reserved. + + This program 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 + of the License, or (at your option) any later version. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +/*! + @header Stream Class +*/ + +class Stream { + + /* Variables from DB */ + var $type; + var $web_path; + var $songs = array(); + var $sess; + + /*! + @function stream + @discussion constructor for the stream class + */ + function Stream($type='m3u', $song_ids=0) { + + $this->type = $type; + $this->songs = $song_ids; + $this->web_path = conf('web_path'); + + if (conf('force_http_play')) { + $port = conf('http_port'); + $this->web_path = preg_replace("/https/", "http",$this->web_path); + $this->web_path = preg_replace("/:\d+/",":$port",$this->web_path); + } + + $this->sess = session_id(); + $this->user_id = $_SESSION['userdata']['id']; + + } //constructor + + /*! + @function start + @discussion runs this and depending on the type passed it will + call the correct function + */ + function start() { + + $methods = get_class_methods('Stream'); + $create_function = "create_" . $this->type; + if (in_array($create_function,$methods)) { + $this->{$create_function}(); + } + // Assume M3u incase they've pooched the type + else { + $this->create_m3u(); + } + + } // start + + /*! + @function create_simplem3u + @discussion this creates a simple m3u + without any of the extended information + */ + function create_simple_m3u() { + + header("Cache-control: public"); + header("Content-Disposition: filename=playlist.m3u"); + header("Content-Type: audio/x-mpegurl;"); + foreach ($this->songs as $song_id) { + $song = new Song($song_id); + if ($song->type == ".flac") { $song->type = ".ogg"; } + if($GLOBALS['user']->prefs['play_type'] == 'downsample') { + $ds = $GLOBALS['user']->prefs['sample_rate']; + } + echo "$this->web_path/play/index.php?song=$song_id&uid=$this->user_id&sid=$this->sess&ds=$ds&stupidwinamp=." . $song->type . "\n"; + } // end foreach + + } // simple_m3u + + /*! + @function create_m3u + @discussion creates an m3u file + */ + function create_m3u() { + + // Send the client an m3u playlist + header("Cache-control: public"); + header("Content-Disposition: filename=playlist.m3u"); + header("Content-Type: audio/x-mpegurl;"); + echo "#EXTM3U\n"; + foreach($this->songs as $song_id) { + $song = new Song($song_id); + $song->format_song(); + if ($song->type == ".flac") { $song->type = ".ogg"; } + $song_name = $song->f_artist_full . " - " . $song->title . "." . $song->type; + echo "#EXTINF:$song->time,$song_name\n"; + $sess = $_COOKIE[libglue_param('sess_name')]; + if($GLOBALS['user']->prefs['play_type'] == 'downsample') { + $ds = $GLOBALS['user']->prefs['sample_rate']; + } + echo "$this->web_path/play/index.php?song=$song_id&uid=$this->user_id&sid=$this->sess&ds=$ds&name=/" . rawurlencode($song_name) . "\n"; + } // end foreach + + } // create_m3u + + /*! + @function create_pls + @discussion creates a pls file + */ + function create_pls() { + + // Send the client a pls playlist + header("Cache-control: public"); + header("Content-Disposition: filename=playlist.pls"); + header("Content-Type: audio/x-scpls;"); + echo "[Playlist]\n"; + echo "NumberOfEntries=" . count($this->songs) . "\n"; + foreach ($this->songs as $song_id) { + $i++; + $song = new Song($song_id); + $song->format_song(); + if ($song->type == ".flac") { $song->type = ".ogg"; } + $song_name = $song->f_artist_full . " - " . $song->title . "." . $song->type; + if($GLOBALS['user']->prefs['play_type'] == 'downsample') { + $ds = $GLOBALS['user']->prefs['sample_rate']; + } + $song_url = $this->web_path . "/play/index.php?song=$song_id&uid=$this->user_id&sid=$this->sess&ds=$ds&stupidwinamp=." . $song->type; + echo "File" . $i . "=$song_url\n"; + echo "Title" . $i . "=$song_name\n"; + echo "Length" . $i . "=-1\n"; + } // end foreach songs + echo "Version=2\n"; + + } // create_pls + + /*! + @function create_asx + @discussion creates an ASZ playlist (Thx Samir Kuthiala) + */ + function create_asx() { + + header("Cache-control: public"); + header("Content-Disposition: filename=playlist.asx"); + header("Content-Type: video/x-ms-asf;"); + + echo "<ASX version = \"3.0\" BANNERBAR=\"AUTO\">\n"; + echo "<TITLE>Ampache ASX Playlist</TITLE>"; + + foreach ($this->songs as $song_id) { + $song = new Song($song_id); + $song->format_song(); + $song_name = $song->f_artist_full . " - " . $song->title . "." . $song->type; + echo "<ENTRY>\n"; + echo "<TITLE>".$song->f_album_full ." - ". $song->f_artist_full ." - ". $song->title ."</TITLE>\n"; + echo "<AUTHOR>".$song->f_artist_full."</AUTHOR>\n"; + $sess = $_COOKIE[libglue_param('sess_name')]; + if ($GLOBALS['user']->prefs['play_type'] == 'downsample') { + $ds = $GLOBALS['user']->prefs['sample_rate']; + } + echo "<REF HREF = \"". conf('web_path') . "/play/index.php?song=$song_id&uid=$this->user_id&sid=$sess&ds=$ds&name=/" . rawurlencode($song_name) . "\" />\n"; + echo "</ENTRY>\n"; + + } // end foreach + + echo "</ASX>\n"; + + } // create_asx + + /*! + @function create_icecast2 + @discussion pushes an icecast stream + */ + function create_icecast2() { + + echo "ICECAST2<br>\n"; + + // Play the song locally using local play configuration + if (count($this->songs) > 0) { + echo "ICECAST2<br>\n"; + exec("killall ices"); + $filename = conf('icecast_tracklist'); + echo "$filename " . _("Opened for writting") . "<br>\n"; + + /* Open the file for writting */ + if (!$handle = @fopen($filename, "w")) { + log_event($_SESSION['userdata']['username'],"icecast","Fopen: $filename Failed"); + echo _("Error, cannot write") . " $filename<br>\n"; + exit; + } + + /* Foreach through songs */ + foreach($this->songs as $song_id) { + $song = new Song($song_id); + echo "$song->file<br>\n"; + $line = "$song->file\n"; + if (!fwrite($handle, $line)) { + log_event($_SESSION['userdata']['username'],"icecast","Fwrite: Unabled to write $line into $filename"); + echo _("Error, cannot write song in file") . " $song->file --> $filename"; + exit; + } // if write fails + + } // foreach songs + + echo $filename . " " . _("Closed after write") . "<br>\n"; + fclose($handle); + $cmd = conf('icecast_command'); + $cmd = str_replace("%FILE%", $filename, $cmd); + if (conf('debug')) { + log_event($_SESSION['userdata']['username'],"icecast","Exec: $cmd"); + } + exec($cmd); + exit; + + } // if songs + + + } // create_icecast2 + + /*! + @function create_local_play + @discussion pushes out localplay mojo + */ + function create_local_play() { + + foreach($this->songs as $song_id) { + $song = new Song($song_id); + $song->format_song(); + $song_name = $song->f_artist_full . " - " . $song->title . "." . $song->type; + $url = escapeshellarg("$this->web_path/play/?song=$song_id&uid=$this->user_id&sid=$this->sess&name=" . rawurlencode($song_name)); + $localplay_add = conf('localplay_add'); + $localplay_add = str_replace("%URL%", $url, $localplay_add); + if (conf('debug')) { + log_event($_SESSION['userdata']['username'],"localplay","Exec: $localplay_add"); + } + exec($localplay_add); + header("Location: " . conf('web_path') . "/index.php"); + } + + } // create_localplay + + /*! + @function create_mpd + @discussion function that passes information to + MPD + */ + function create_mpd() { + + /* Create the MPD object */ + $myMpd = @new mpd(conf('mpd_host'),conf('mpd_port'),conf('mpd_pass')); + + /* Add the files to the MPD playlist */ + addToPlaylist($myMpd,$this->songs); + + header ("Location: " . return_referer()); + + } // create_mpd + + + /*! + @function create_slim + @discussion this function passes the correct mojo to the slim + class which is in turn passed to the slimserver + */ + function create_slim() { + + + + + + } // create_slim + + +} //end of stream class + +?> diff --git a/modules/class/update.php b/modules/class/update.php new file mode 100644 index 00000000..bd776e70 --- /dev/null +++ b/modules/class/update.php @@ -0,0 +1,880 @@ +<?php +/* + + Copyright (c) 2001 - 2005 Ampache.org + All rights reserved. + + This program 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 + of the License, or (at your option) any later version. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/*! + @header Update Class + @discussion this class handles updating from one version of + maintain to the next. Versions are a 6 digit number + 220000 + ^ + Major Revision + + 220000 + ^ + Minor Revision + + The last 4 digits are a build number... + If Minor can't go over 9 Major can go as high as we want +*/ + +class Update { + + var $key; + var $value; + var $versions; // array containing version information + + /*! + @function Update + @discussion Constructor, pulls out information about + the desired key + */ + function Update ( $key=0 ) { + + if ($key) { + $info = $this->get_info(); + $this->key = $key; + $this->value = $info->value; + $this->versions = $this->populate_version(); + } + + } // constructor + + /*! + @function get_info + @discussion gets the information for the zone + */ + function get_info() { + global $conf; + + $sql = "SELECT * FROM update_info WHERE key='$this->key'"; + $db_results = mysql_query($sql, dbh()); + + return mysql_fetch_object($db_results); + + } //get_info + + /*! + @function get_version + @discussion this checks to see what version you are currently running + because we may not have the update_info table we have to check + for it's existance first. + */ + function get_version() { + + + /* Make sure that update_info exits */ + $sql = "SHOW TABLES LIKE 'update_info'"; + $db_results = mysql_query($sql, dbh()); + // If no table + if (!mysql_num_rows($db_results)) { + + $version = '310000'; + + } // if table isn't found + + else { + // If we've found the update_info table, let's get the version from it + $sql = "SELECT * FROM update_info WHERE `key`='db_version'"; + $db_results = mysql_query($sql, dbh()); + $results = mysql_fetch_object($db_results); + $version = $results->value; + } + + return $version; + + } // get_version + + /*! + @function format_version + @discussion make the version number pretty + */ + function format_version($data) { + + $new_version = substr($data,0,strlen($data) - 5) . "." . substr($data,strlen($data)-5,1) . " Build:" . + substr($data,strlen($data)-4,strlen($data)); + + return $new_version; + + } // format_version + + /*! + @function need_update + @discussion checks to see if we need to update + maintain at all + */ + function need_update() { + + $current_version = $this->get_version(); + + if (!is_array($this->versions)) { + $this->versions = $this->populate_version(); + } + + /* + Go through the versions we have and see if + we need to apply any updates + */ + foreach ($this->versions as $update) { + if ($update['version'] > $current_version) { + return true; + } + + } // end foreach version + + return false; + + } // need_update + + + /*! + @function populate_version + @discussion just sets an array the current differences + that require an update + */ + function populate_version() { + + /* Define the array */ + $version = array(); + + /* Version 3.2 Build 0001 */ + $update_string = "- Add update_info table to the database<br />" . + "- Add Now Playing Table<br />" . + "- Add album art columns to album table<br />" . + "- Compleatly Changed Preferences table<br />" . + "- Added Upload table<br />"; + $version[] = array('version' => '320001', 'description' => $update_string); + + $update_string = "- Add back in catalog_type for XML-RPC Mojo<br />" . + "- Add level to access list to allow for play/download/xml-rpc share permissions<br />" . + "- Changed access_list table to allow start-end (so we can set full ip ranges)<br />" . + "- Add default_play to preferences to allow quicktime/localplay/stream<br />" . + "- Switched Artist ID from 10 --> 11 to match other tables<br />"; + $version[] = array('version' => '320002', 'description' => $update_string); + + $update_string = "- Added a last_seen field user table to track users<br />" . + "- Made preferences table key/value based<br />"; + + $version[] = array('version' => '320003', 'description' => $update_string); + + $update_string = "- Added play_type to preferences table<br />" . + "- Removed multicast,downsample,localplay from preferences table<br />" . + "- Dropped old config table which was no longer needed<br />"; + + $version[] = array('version' => '320004', 'description' => $update_string); + + $update_string = "- Added type to preferences to allow for site/user preferences<br />"; + + $version[] = array('version' => '330000', 'description' => $update_string); + + $update_string = "- Added Year to album table<br />" . + "- Increased length of password field in User table<br />"; + + $version[] = array('version' => '330001', 'description' => $update_string); + + $update_string = "- Changed user.access to varchar from enum for more flexibility<br />" . + "- Added catalog.private for future catalog access control<br />" . + "- Added user_catalog table for future catalog access control<br />"; + + + $version[] = array('version' => '330002', 'description' => $update_string); + + $update_string = "- Added user_preferences table to once and for all fix preferences.<br />" . + "- Moved Contents of preferences into new table, and modifies old preferences table.<br />"; + + $version[] = array('version' => '330003', 'description' => $update_string); + + $update_string = "- Changed song comment from varchar255 in order to handle comments longer than 255 chr.<br />" . + "- Added Language and Playlist Type as a per user preference.<br />" . + "- Added Level to Catalog_User table for future use.<br />" . + "- Added gather_types to Catalog table for future use.<br />"; + + + $version[] = array('version' => '330004', 'description' => $update_string); + + $update_string = "- Added Theme config option.<br />"; + + $version[] = array('version' => '331000', 'description' => $update_string); + + $update_string = "- Added Elipse Threshold Preferences.<br />"; + + $version[] = array('version' => '331001', 'description' => $update_string); + + + return $version; + + } // populate_version + + /*! + @function display_update + @discussion This displays a list of the needed + updates to the database. This will actually + echo out the list... + */ + function display_update() { + + $current_version = $this->get_version(); + if (!is_array($this->versions)) { + $this->versions = $this->populate_version(); + } + + echo "<ul>\n"; + + foreach ($this->versions as $version) { + + if ($version['version'] > $current_version) { + $updated = true; + echo "<b>Version: " . $this->format_version($version['version']) . "</b><br />"; + echo $version['description'] . "<br />\n"; + } // if newer + + } // foreach versions + + echo "</ul>\n"; + + if (!$updated) { echo "<p align=\"center\">No Updates Needed [<a href=\"" . conf('web_path') . "\">Return]</a></p>"; } + } // display_update + + /*! + @function run_update + @discussion This function actually updates the db. + it goes through versions and finds the ones + that need to be run. Checking to make sure + the function exists first. + */ + function run_update() { + + /* Nuke All Active session before we start the mojo */ + $sql = "DELETE * FROM session"; + $db_results = mysql_query($sql, dbh()); + + + $methods = array(); + + $current_version = $this->get_version(); + + $methods = get_class_methods('Update'); + + if (!is_array($this->versions)) { + $this->versions = $this->populate_version(); + } + + foreach ($this->versions as $version) { + + + // If it's newer than our current version + // let's see if a function exists and run the + // bugger + if ($version['version'] > $current_version) { + $update_function = "update_" . $version['version']; + if (in_array($update_function,$methods)) { + $this->{$update_function}(); + } + + } + + } // end foreach version + + } // run_update + + /*! + @function set_version + @discussion sets a new version takes + a key and value + */ + function set_version($key,$value) { + + $sql = "UPDATE update_info SET value='$value' WHERE `key`='$key'"; + $db_results = mysql_query($sql, dbh()); + + } //set_version + + /*! + @function update_320001 + @discussion Migration function for 3.2 Build 0001 + */ + function update_320001() { + + // Add the update_info table to the database + $sql = "CREATE TABLE `update_info` (`key` VARCHAR( 128 ) NOT NULL ,`value` VARCHAR( 255 ) NOT NULL ,INDEX ( `key` ) )"; + $db_results = mysql_query($sql, dbh()); + + // Insert the first version info + $sql = "INSERT INTO update_info (`key`,`value`) VALUES ('db_version','320001')"; + $db_results = mysql_query($sql, dbh()); + + // Add now_playing table to database + $sql = "CREATE TABLE now_playing (" . + "id int(11) unsigned NOT NULL auto_increment, " . + "song_id int(11) unsigned NOT NULL default '0', " . + "user_id int(11) unsigned default NULL, " . + "start_time int(11) unsigned NOT NULL default '0', " . + "PRIMARY KEY (id) " . + ") TYPE=MyISAM"; + $db_results = mysql_query($sql, dbh()); + + // Add the upload table to the database + $sql = "CREATE TABLE upload ( id int(11) unsigned NOT NULL auto_increment, `user` int(11) unsigned NOT NULL," . + "`file` varchar(255) NOT NULL , `comment` varchar(255) NOT NULL , action enum('add','quarantine','delete') NOT NULL default 'quarantine', " . + "addition_time int(11) unsigned default '0', PRIMARY KEY (id), KEY action (`action`), KEY user (`user`) )"; + $db_results = mysql_query($sql, dbh()); + + /* + Ok we need to compleatly tweak the preferences table + first things first, nuke the damn thing so we can + setup our new mojo + */ + $sql = "DROP TABLE `preferences`"; + $db_results = mysql_query($sql, dbh()); + + $sql = "CREATE TABLE `preferences` (`id` INT( 11 ) UNSIGNED NOT NULL AUTO_INCREMENT , `user` INT( 11 ) UNSIGNED NOT NULL ," . + "`download` ENUM( 'true', 'false' ) DEFAULT 'false' NOT NULL , `upload` ENUM( 'disabled', 'html', 'gui' ) DEFAULT 'disabled' NOT NULL ," . + "`downsample` ENUM( 'true', 'false' ) DEFAULT 'false' NOT NULL , `local_play` ENUM( 'true', 'false' ) DEFAULT 'false' NOT NULL ," . + "`multicast` ENUM( 'true', 'false' ) DEFAULT 'false' NOT NULL , `quarantine` ENUM( 'true', 'false' ) DEFAULT 'true' NOT NULL ," . + "`popular_threshold` INT( 11 ) UNSIGNED DEFAULT '10' NOT NULL , `font` VARCHAR( 255 ) DEFAULT 'Verdana, Helvetica, sans-serif' NOT NULL ," . + "`bg_color1` VARCHAR( 32 ) DEFAULT '#ffffff' NOT NULL , `bg_color2` VARCHAR( 32 ) DEFAULT '#000000' NOT NULL , `base_color1` VARCHAR( 32 ) DEFAULT '#bbbbbb' NOT NULL , " . + "`base_color2` VARCHAR( 32 ) DEFAULT '#dddddd' NOT NULL , `font_color1` VARCHAR( 32 ) DEFAULT '#222222' NOT NULL , " . + "`font_color2` VARCHAR( 32 ) DEFAULT '#000000' NOT NULL , `font_color3` VARCHAR( 32 ) DEFAULT '#ffffff' NOT NULL , " . + "`row_color1` VARCHAR( 32 ) DEFAULT '#cccccc' NOT NULL , `row_color2` VARCHAR( 32 ) DEFAULT '#bbbbbb' NOT NULL , " . + "`row_color3` VARCHAR( 32 ) DEFAULT '#dddddd' NOT NULL , `error_color` VARCHAR( 32 ) DEFAULT '#990033' NOT NULL , " . + "`font_size` INT( 11 ) UNSIGNED DEFAULT '10' NOT NULL , `upload_dir` VARCHAR( 255 ) NOT NULL , " . + "`sample_rate` INT( 11 ) UNSIGNED DEFAULT '32' NOT NULL , PRIMARY KEY ( `id` ), KEY user (`user`) )"; + $db_results = mysql_query($sql, dbh()); + + $sql = "INSERT INTO preferences (`user`,`font_size`) VALUES ('0','12')"; + $db_results = mysql_query($sql, dbh()); + + // Now we need to give everyone some preferences + $sql = "SELECT * FROM user"; + $db_results = mysql_query($sql, dbh()); + + while ($r = mysql_fetch_object($db_results)) { + $users[] = $r; + } + + foreach ($users as $user) { + $sql = "INSERT INTO preferences (`user`) VALUES ('$user->id')"; + $db_results = mysql_query($sql, dbh()); + } + + // Add album art columns to album table + $sql = "ALTER TABLE album ADD art MEDIUMBLOB, ADD art_mime VARCHAR(128)"; + $db_result = mysql_query($sql, dbh()); + + } // update_320001 + + /*! + @function update_320002 + @discussion update to alpha 2 + */ + function update_320002() { + + /* Add catalog_type back in for XML-RPC */ + $sql = "ALTER TABLE `catalog` ADD `catalog_type` ENUM( 'local', 'remote' ) DEFAULT 'local' NOT NULL AFTER `path`"; + $db_results = mysql_query($sql, dbh()); + + /* Add default_play to pick between stream/localplay/quicktime */ + $sql = "ALTER TABLE `preferences` ADD `default_play` VARCHAR( 128 ) DEFAULT 'stream' NOT NULL AFTER `popular_threshold`"; + $db_results = mysql_query($sql, dbh()); + + /* Should be INT(11) Why not eah? */ + $sql = "ALTER TABLE `artist` CHANGE `id` `id` INT( 11 ) UNSIGNED NOT NULL AUTO_INCREMENT"; + $db_results = mysql_query($sql, dbh()); + + /* Add level to access_list so we can limit playback/download/xml-rpc share */ + $sql = "ALTER TABLE `access_list` ADD `level` SMALLINT( 3 ) UNSIGNED DEFAULT '5' NOT NULL"; + $db_results = mysql_query($sql, dbh()); + + /* Shouldn't be zero fill... not needed */ + $sql = "ALTER TABLE `user` CHANGE `offset_limit` `offset_limit` INT( 5 ) UNSIGNED DEFAULT '00050' NOT NULL"; + $db_results = mysql_query($sql, dbh()); + + /* Let's knock it up a notch 11.. BAM */ + $sql = "ALTER TABLE `user` CHANGE `id` `id` INT( 11 ) UNSIGNED NOT NULL AUTO_INCREMENT"; + $db_results = mysql_query($sql, dbh()); + + /* Change IP --> Start */ + $sql = "ALTER TABLE `access_list` CHANGE `ip` `start` INT( 11 ) UNSIGNED NOT NULL"; + $db_results = mysql_query($sql, dbh()); + + /* Add End */ + $sql = "ALTER TABLE `access_list` ADD `end` INT( 11 ) UNSIGNED NOT NULL AFTER `start`"; + $db_results = mysql_query($sql, dbh()); + + /* Update Version */ + $this->set_version('db_version', '320002'); + + } // update_320002 + + + /*! + @function update_320003 + @discussion updates to the alpha 3 of 3.2 + */ + function update_320003() { + + /* Add last_seen to user table */ + $sql = "ALTER TABLE `user` ADD `last_seen` INT( 11 ) UNSIGNED NOT NULL"; + $db_results = mysql_query($sql, dbh()); + + /* + Load the preferences table into an array + so we can migrate it to the new format + */ + $sql = "SELECT * FROM preferences"; + $db_results = mysql_query($sql, dbh()); + + $results = array(); + + while ($r = mysql_fetch_object($db_results)) { + $results[$r->user]['download'] = $r->download; + $results[$r->user]['upload'] = $r->upload; + $results[$r->user]['downsample'] = $r->downsample; + $results[$r->user]['local_play'] = $r->local_play; + $results[$r->user]['multicast'] = $r->multicast; + $results[$r->user]['quarantine'] = $r->quarantine; + $results[$r->user]['popular_threshold'] = $r->popular_threshold; + $results[$r->user]['default_play'] = $r->default_play; + $results[$r->user]['font'] = $r->font; + $results[$r->user]['bg_color1'] = $r->bg_color1; + $results[$r->user]['bg_color2'] = $r->bg_color2; + $results[$r->user]['base_color1'] = $r->base_color1; + $results[$r->user]['base_color2'] = $r->base_color2; + $results[$r->user]['font_color1'] = $r->font_color1; + $results[$r->user]['font_color2'] = $r->font_color2; + $results[$r->user]['font_color3'] = $r->font_color3; + $results[$r->user]['row_color1'] = $r->row_color1; + $results[$r->user]['row_color2'] = $r->row_color2; + $results[$r->user]['row_color3'] = $r->row_color3; + $results[$r->user]['error_color'] = $r->error_color; + $results[$r->user]['font_size'] = $r->font_size; + $results[$r->user]['upload_dir'] = $r->upload_dir; + $results[$r->user]['sample_rate'] = $r->sample_rate; + + } // while preferences + + /* Drop the preferences table so we can start over */ + $sql = "DROP TABLE `preferences`"; + $db_results = mysql_query($sql, dbh()) or die('Query failed: ' . mysql_error()); + + /* Create the new preferences table */ + $sql = "CREATE TABLE `preferences` (`key` VARCHAR( 255 ) NOT NULL , `value` VARCHAR( 255 ) NOT NULL , `user` INT( 11 ) UNSIGNED NOT NULL)"; + $db_results = mysql_query($sql, dbh()); + + $sql = "ALTER TABLE `preferences` ADD INDEX ( `key` )"; + $db_results = mysql_query($sql, dbh()); + + $sql = "ALTER TABLE `preferences` ADD INDEX ( `user` )"; + $db_results = mysql_query($sql, dbh()); + + + $user = new User(); + + /* Populate the mofo! */ + foreach ($results as $key => $data) { + + $user->add_preference('download',$results[$key]['download'],$key); + $user->add_preference('upload',$results[$key]['upload'], $key); + $user->add_preference('downsample',$results[$key]['downsample'], $key); + $user->add_preference('local_play', $results[$key]['local_play'], $key); + $user->add_preference('multicast', $results[$key]['multicast'], $key); + $user->add_preference('quarantine', $results[$key]['quarantine'], $key); + $user->add_preference('popular_threshold',$results[$key]['popular_threshold'], $key); + $user->add_preference('font', $results[$key]['font'], $key); + $user->add_preference('bg_color1',$results[$key]['bg_color1'], $key); + $user->add_preference('bg_color2',$results[$key]['bg_color2'], $key); + $user->add_preference('base_color1',$results[$key]['base_color1'], $key); + $user->add_preference('base_color2',$results[$key]['base_color2'], $key); + $user->add_preference('font_color1',$results[$key]['font_color1'], $key); + $user->add_preference('font_color2',$results[$key]['font_color2'], $key); + $user->add_preference('font_color3',$results[$key]['font_color3'], $key); + $user->add_preference('row_color1',$results[$key]['row_color1'], $key); + $user->add_preference('row_color2',$results[$key]['row_color2'], $key); + $user->add_preference('row_color3',$results[$key]['row_color3'], $key); + $user->add_preference('error_color', $results[$key]['error_color'], $key); + $user->add_preference('font_size', $results[$key]['font_size'], $key); + $user->add_preference('upload_dir', $results[$key]['upload_dir'], $key); + $user->add_preference('sample_rate', $results[$key]['sample_rate'], $key); + + } // foreach preferences + + /* Update Version */ + $this->set_version('db_version', '320003'); + + } // update_320003 + + /*! + @function update_320004 + @discussion updates to the 320004 + version of the db + */ + function update_320004() { + + $results = array(); + + $sql = "SELECT * FROM preferences WHERE `key`='local_play' AND `value`='true'"; + $db_results = mysql_query($sql, dbh()); + + while ($r = mysql_fetch_object($db_results)) { + $results[$r->user] = 'local_play'; + } + + $sql = "SELECT * FROM preferences WHERE `key`='downsample' AND `value`='true'"; + $db_results = mysql_query($sql, dbh()); + + while ($r = mysql_fetch_object($db_results)) { + $results[$r->user] = 'downsample'; + } + + $sql = "SELECT * FROM preferences WHERE `key`='multicast' AND `value`='true'"; + $db_results = mysql_query($sql, dbh()); + + while ($r = mysql_fetch_object($db_results)) { + $results[$r->user] = 'multicast'; + } + + $sql = "SELECT DISTINCT(user) FROM preferences"; + $db_results = mysql_query($sql, dbh()); + + while ($r = mysql_fetch_object($db_results)) { + if (!isset($results[$r->user])) { + $results[$r->user] = 'normal'; + } + } + + foreach ($results as $key => $value) { + $sql = "INSERT INTO preferences (`key`,`value`,`user`) VALUES ('play_type','$value','$key')"; + $db_results = mysql_query($sql, dbh()); + } + + $sql = "DELETE FROM preferences WHERE `key`='downsample'"; + $db_results = mysql_query($sql, dbh()); + + $sql = "DELETE FROM preferences WHERE `key`='local_play'"; + $db_results = mysql_query($sql, dbh()); + + $sql = "DELETE FROM preferences WHERE `key`='multicast'"; + $db_results = mysql_query($sql, dbh()); + + $sql = "DROP TABLE `config`"; + $db_results = mysql_query($sql, dbh()); + + /* Update Version */ + $this->set_version('db_version', '320004'); + + } // update_320004 + + /*! + @function update_330000 + @discussion updates to 3.3 Build 0 + */ + function update_330000() { + + /* Add Type to preferences */ + $sql = "ALTER TABLE `preferences` ADD `type` VARCHAR( 128 ) NOT NULL"; + $db_results = mysql_query($sql, dbh()); + + /* Set Type on current preferences */ + $sql = "UPDATE `preferences` SET type='user'"; + $db_results = mysql_query($sql, dbh()); + + /* Add New Preferences */ + $new_prefs[] = array('key' => 'local_length', 'value' => libglue_param('local_length')); + $new_prefs[] = array('key' => 'site_title', 'value' => conf('site_title')); + $new_prefs[] = array('key' => 'access_control', 'value' => conf('access_control')); + $new_prefs[] = array('key' => 'xml_rpc', 'value' => conf('xml_rpc')); + $new_prefs[] = array('key' => 'lock_songs', 'value' => conf('lock_songs')); + $new_prefs[] = array('key' => 'force_http_play', 'value' => conf('force_http_play')); + $new_prefs[] = array('key' => 'http_port', 'value' => conf('http_port')); + $new_prefs[] = array('key' => 'do_mp3_md5', 'value' => conf('do_mp3_md5')); + $new_prefs[] = array('key' => 'catalog_echo_count', 'value' => conf('catalog_echo_count')); + $new_prefs[] = array('key' => 'no_symlinks', 'value' => conf('no_symlinks')); + $new_prefs[] = array('key' => 'album_cache_limit', 'value' => conf('album_cache_limit')); + $new_prefs[] = array('key' => 'artist_cache_limit', 'value' => conf('artist_cache_limit')); + $new_prefs[] = array('key' => 'memory_limit', 'value' => conf('memory_limit')); + $new_prefs[] = array('key' => 'refresh_limit', 'value' => conf('refresh_interval')); + + foreach ($new_prefs as $pref) { + $sql = "INSERT INTO `preferences` (`key`,`value`,`type`) VALUES ('".$pref['key']."','".$pref['value']."','system')"; + $db_results = mysql_query($sql, dbh()); + } + + + /* Update Version */ + $this->set_version('db_version','330000'); + + + } // update_330000 + + + /*! + @function update_330001 + @discussion adds year to album and tweaks + the password field in session + */ + function update_330001() { + + /* Add Year to Album Table */ + $sql = "ALTER TABLE `album` ADD `year` INT( 4 ) UNSIGNED NOT NULL AFTER `prefix`"; + $db_results = mysql_query($sql, dbh()); + + /* Alter Password Field */ + $sql = "ALTER TABLE `user` CHANGE `password` `password` VARCHAR( 64 ) NOT NULL"; + $db_results = mysql_query($sql, dbh()); + + /* Update Version */ + $this->set_version('db_version', '330001'); + + } // update_330001 + + /*! + @function update_330002 + @discussion changes user.access from enum to a + varchr field + */ + function update_330002() { + + /* Alter user table */ + $sql = "ALTER TABLE `user` CHANGE `access` `access` VARCHAR( 64 ) NOT NULL"; + $db_results = mysql_query($sql, dbh()); + + /* Add private option to catalog */ + $sql = "ALTER TABLE `catalog` ADD `private` INT( 1 ) UNSIGNED DEFAULT '0' NOT NULL AFTER `enabled`"; + $db_results = mysql_query($sql, dbh()); + + /* Add new user_catalog table */ + $sql = "CREATE TABLE `user_catalog` ( `user` INT( 11 ) UNSIGNED NOT NULL , `catalog` INT( 11 ) UNSIGNED NOT NULL )"; + $db_results = mysql_query($sql, dbh()); + + /* Update Version */ + $this->set_version('db_version', '330002'); + + } // update_330002 + + /*! + @function update_330003 + @discussion adds user_preference and modifies the + existing preferences table + */ + function update_330003() { + + /* Add new user_preference table */ + $sql = "CREATE TABLE `user_preference` ( `user` INT( 11 ) UNSIGNED NOT NULL , `preference` INT( 11 ) UNSIGNED NOT NULL, `value` VARCHAR( 255 ) NOT NULL )"; + $db_results = mysql_query($sql, dbh()); + + /* Add indexes */ + $sql = "ALTER TABLE `user_preference` ADD INDEX ( `user` )"; + $db_results = mysql_query($sql, dbh()); + + $sql = "ALTER TABLE `user_preference` ADD INDEX ( `preference` )"; + $db_results = mysql_query($sql, dbh()); + + /* Pull and store all preference information */ + $sql = "SELECT * FROM preferences"; + $db_results = mysql_query($sql, dbh()); + + $results = array(); + + while ($r = mysql_fetch_object($db_results)) { + $results[] = $r; + } + + + /* Re-combobulate preferences table */ + + /* Drop the preferences table so we can start over */ + $sql = "DROP TABLE `preferences`"; + $db_results = mysql_query($sql, dbh()) or die('Query failed: ' . mysql_error()); + + /* Insert new preference table */ + $sql = "CREATE TABLE `preferences` ( `id` INT ( 11 ) UNSIGNED NOT NULL AUTO_INCREMENT, `name` VARCHAR ( 128 ) NOT NULL, `value` VARCHAR ( 255 ) NOT NULL," . + " `description` VARCHAR ( 255 ) NOT NULL, `level` INT ( 11 ) UNSIGNED NOT NULL DEFAULT '100', `type` VARCHAR ( 128 ) NOT NULL, `locked` SMALLINT ( 1 ) NOT NULL Default '1'" . + ", PRIMARY KEY ( `id` ) )"; + $db_results = mysql_query($sql, dbh()) or die("Query failed: " . mysql_error()); + + /* Create Array of Preferences */ + $new_prefs = array(); + + $new_prefs[] = array('name' => 'download', 'value' => '0', 'description' => 'Allow Downloads', 'level' => '100', 'locked' => '0', 'type' => 'user'); + $new_prefs[] = array('name' => 'upload', 'value' => '0', 'description' => 'Allow Uploads', 'level' => '100', 'locked' => '0', 'type' => 'user'); + $new_prefs[] = array('name' => 'quarantine', 'value' => '1', 'description' => 'Quarantine All Uploads', 'level' => '100', 'locked' => '0', 'type' => 'user'); + $new_prefs[] = array('name' => 'popular_threshold', 'value' => '10', 'description' => 'Popular Threshold', 'level' => '25', 'locked' => '0', 'type' => 'user'); + $new_prefs[] = array('name' => 'font', 'value' => 'Verdana, Helvetica, sans-serif', 'description' => 'Interface Font', 'level' => '25', 'locked' => '0', 'type' => 'user'); + $new_prefs[] = array('name' => 'bg_color1', 'value' => '#ffffff', 'description' => 'Background Color 1', 'level' => '25', 'locked' => '0', 'type' => 'user'); + $new_prefs[] = array('name' => 'bg_color2', 'value' => '#000000', 'description' => 'Background Color 2', 'level' => '25', 'locked' => '0', 'type' => 'user'); + $new_prefs[] = array('name' => 'base_color1', 'value' => '#bbbbbb', 'description' => 'Base Color 1', 'level' => '25', 'locked' => '0', 'type' => 'user'); + $new_prefs[] = array('name' => 'base_color2', 'value' => '#dddddd', 'description' => 'Base Color 2', 'level' => '25', 'locked' => '0', 'type' => 'user'); + $new_prefs[] = array('name' => 'font_color1', 'value' => '#222222', 'description' => 'Font Color 1', 'level' => '25', 'locked' => '0', 'type' => 'user'); + $new_prefs[] = array('name' => 'font_color2', 'value' => '#000000', 'description' => 'Font Color 2', 'level' => '25', 'locked' => '0', 'type' => 'user'); + $new_prefs[] = array('name' => 'font_color3', 'value' => '#ffffff', 'description' => 'Font Color 3', 'level' => '25', 'locked' => '0', 'type' => 'user'); + $new_prefs[] = array('name' => 'row_color1', 'value' => '#cccccc', 'description' => 'Row Color 1', 'level' => '25', 'locked' => '0', 'type' => 'user'); + $new_prefs[] = array('name' => 'row_color2', 'value' => '#bbbbbb', 'description' => 'Row Color 2', 'level' => '25', 'locked' => '0', 'type' => 'user'); + $new_prefs[] = array('name' => 'row_color3', 'value' => '#dddddd', 'description' => 'Row Color 3', 'level' => '25', 'locked' => '0', 'type' => 'user'); + $new_prefs[] = array('name' => 'error_color', 'value' => '#990033', 'description' => 'Error Color', 'level' => '25', 'locked' => '0', 'type' => 'user'); + $new_prefs[] = array('name' => 'font_size', 'value' => '10', 'description' => 'Font Size', 'level' => '25', 'locked' => '0', 'type' => 'user'); + $new_prefs[] = array('name' => 'upload_dir', 'value' => '/tmp', 'description' => 'Upload Directory', 'level' => '25', 'locked' => '0', 'type' => 'user'); + $new_prefs[] = array('name' => 'sample_rate', 'value' => '32', 'description' => 'Downsample Bitrate', 'level' => '25', 'locked' => '0', 'type' => 'user'); + $new_prefs[] = array('name' => 'refresh_limit', 'value' => '0', 'description' => 'Refresh Rate for Homepage', 'level' => '100', 'locked' => '0', 'type' => 'system'); + $new_prefs[] = array('name' => 'local_length', 'value' => '900', 'description' => 'Session Expire in Seconds', 'level' => '100', 'locked' => '0', 'type' => 'system'); + $new_prefs[] = array('name' => 'site_title', 'value' => 'For The Love of Music', 'description' => 'Website Title', 'level' => '100', 'locked' => '0', 'type' => 'system'); + $new_prefs[] = array('name' => 'lock_songs', 'value' => '0', 'description' => 'Lock Songs', 'level' => '100', 'locked' => '1', 'type' => 'system'); + $new_prefs[] = array('name' => 'force_http_play', 'value' => '1', 'description' => 'Forces Http play regardless of port', 'level' => '100', 'locked' => '1', 'type' => 'system'); + $new_prefs[] = array('name' => 'http_port', 'value' => '80', 'description' => 'Non-Standard Http Port', 'level' => '100', 'locked' => '1', 'type' => 'system'); + $new_prefs[] = array('name' => 'catalog_echo_count', 'value' => '100', 'description' => 'Catalog Echo Interval', 'level' => '100', 'locked' => '0', 'type' => 'system'); + $new_prefs[] = array('name' => 'no_symlinks', 'value' => '0', 'description' => 'Don\'t Follow Symlinks', 'level' => '100', 'locked' => '0', 'type' => 'system'); + $new_prefs[] = array('name' => 'album_cache_limit', 'value' => '25', 'description' => 'Album Cache Limit', 'level' => '100', 'locked' => '0', 'type' => 'system'); + $new_prefs[] = array('name' => 'artist_cache_limit', 'value' => '50', 'description' => 'Artist Cache Limit', 'level' => '100', 'locked' => '0', 'type' => 'system'); + $new_prefs[] = array('name' => 'play_type', 'value' => 'stream', 'description' => 'Type of Playback', 'level' => '25', 'locked' => '0', 'type' => 'user'); + $new_prefs[] = array('name' => 'direct_link', 'value' => '1', 'description' => 'Allow Direct Links', 'level' => '100', 'locked' => '0', 'type' => 'user'); + + foreach ($new_prefs as $prefs) { + + $sql = "INSERT INTO preferences (`name`,`value`,`description`,`level`,`locked`,`type`) VALUES ('" . $prefs['name'] . "','" . $prefs['value'] ."','". $prefs['description'] ."','" . $prefs['level'] ."','". $prefs['locked'] ."','" . $prefs['type'] . "')"; + $db_results = mysql_query($sql, dbh()); + + } // foreach prefs + + + /* Re-insert Data into preferences table */ + + $user = new User(); + $users = array(); + + foreach ($results as $old_pref) { + // This makes sure that true/false yes no get turned into 0/1 + $temp_array = fix_preferences(array('old' => $old_pref->value)); + $old_pref->value = $temp_array['old']; + $user->add_preference($old_pref->key,$old_pref->value,$old_pref->user); + $users[$old_pref->user] = 1; + } // end foreach old preferences + + /* Fix missing preferences */ + foreach ($users as $userid => $data) { + $user->fix_preferences($userid); + } // end foreach user + + /* Update Version */ + $this->set_version('db_version', '330003'); + + } // update_330003 + + /*! + @function update_330004 + @discussion changes comment from varchar to text + and also adds a few preferences options and + adds the per db art functions + */ + function update_330004() { + + /* Change comment field in song */ + $sql = "ALTER TABLE `song` CHANGE `comment` `comment` TEXT NOT NULL"; + $db_results = mysql_query($sql, dbh()); + + /* Add Extra Preferences */ + $sql = "INSERT INTO `preferences` ( `id` , `name` , `value` , `description` , `level` , `type` , `locked` ) VALUES ('', 'lang', 'en_US', 'Language', '100', 'user', '0')"; + $db_results = mysql_query($sql, dbh()); + + $sql = "INSERT INTO `preferences` ( `id` , `name` , `value` , `description` , `level` , `type` , `locked` ) VALUES ('', 'playlist_type','m3u','Playlist Type','100','user','0')"; + $db_results = mysql_query($sql, dbh()); + + /* Add Gathertype to Catalog for future use */ + $sql = "ALTER TABLE `catalog` ADD `gather_types` VARCHAR( 255 ) NOT NULL AFTER `sort_pattern`"; + $db_results = mysql_query($sql, dbh()); + + /* Add level to user_catalog for future use */ + $sql = "ALTER TABLE `user_catalog` ADD `level` SMALLINT( 3 ) DEFAULT '25' NOT NULL AFTER `catalog`"; + $db_results = mysql_query($sql, dbh()); + + /* Fix existing preferences */ + $sql = "SELECT id FROM user"; + $db_results = mysql_query($sql, dbh()); + + $user = new User(0); + + while ($results = mysql_fetch_array($db_results)) { + $user->fix_preferences($results[0]); + } + + /* Update Version */ + $this->set_version('db_version', '330004'); + + } // update_330004 + + /*! + @function update_331000 + @discussion this updates is for 3.3.1 it adds + the theme preference. + */ + function update_331000() { + + + /* Add new preference */ + $sql = "INSERT INTO `preferences` (`id`,`name`,`value`,`description`,`level`,`type`,`locked`) VALUES ('','theme_name','classic','Theme','0','user','0')"; + $db_results = mysql_query($sql, dbh()); + + /* Fix existing preferecnes */ + $sql = "SELECT DISTINCT(user) FROM user_preference"; + $db_results = mysql_query($sql, dbh()); + + $user = new User(0); + + while ($results = mysql_fetch_array($db_results)) { + $user->fix_preferences($results[0]); + } + + /* Update Version */ + $this->set_version('db_version','331000'); + + } // update_331000 + + /*! + @function update_331001 + @discussion this adds a few more user preferences + */ + function update_331001() { + + /* Add new preference */ + $sql = "INSERT INTO `preferences` (`id`,`name`,`value`,`description`,`level`,`type`,`locked`) VALUES ('','ellipse_threshold_album','27','Album Ellipse Threshold','0','user','0')"; + $db_results = mysql_query($sql, dbh()); + + $sql = "INSERT INTO `preferences` (`id`,`name`,`value`,`description`,`level`,`type`,`locked`) VALUES ('','ellipse_threshold_artist','27','Artist Ellipse Threshold','0','user','0')"; + $db_results = mysql_query($sql, dbh()); + + $sql = "INSERT INTO `preferences` (`id`,`name`,`value`,`description`,`level`,`type`,`locked`) VALUES ('','ellipse_threshold_title','27','Title Ellipse Threshold','0','user','0')"; + $db_results = mysql_query($sql, dbh()); + + /* Fix existing preferecnes */ + $sql = "SELECT DISTINCT(user) FROM user_preference"; + $db_results = mysql_query($sql, dbh()); + + $user = new User(0); + + while ($results = mysql_fetch_array($db_results)) { + $user->fix_preferences($results[0]); + } + + /* Update Version */ + $this->set_version('db_version','331001'); + + } // update_331001 + +} // end update class + +?> diff --git a/modules/class/user.php b/modules/class/user.php new file mode 100644 index 00000000..e5c2771b --- /dev/null +++ b/modules/class/user.php @@ -0,0 +1,604 @@ +<?php +/* + + Copyright (c) 2001 - 2005 Ampache.org + All rights reserved. + + This program 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 + of the License, or (at your option) any later version. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/*! + @header User Object + View object that is thrown into their session + +*/ + + +class User { + + //Basic Componets + var $username; + var $id=0; + var $fullname; + var $access; + var $offset_limit=25; + var $email; + var $last_seen; + + function User($username=0,$uid=0) { + + if (!$username && !$uid) { + return true; + } + + $this->username = $username; + $this->id = $uid; + $info = $this->get_info(); + $this->username = $info->username; + $this->id = $info->id; + $this->id = $info->id; + $this->fullname = $info->fullname; + $this->access = $info->access; + $this->offset_limit = $info->offset_limit; + $this->email = $info->email; + $this->last_seen = $info->last_seen; + $this->set_preferences(); + + // Make sure the Full name is always filled + if (strlen($this->fullname) < 1) { $this->fullname = $this->username; } + + } // User + + + /*! + @function get_info + @dicussion gets the info! + */ + function get_info() { + + if ($this->username) { + $sql = "SELECT * FROM user WHERE username='$this->username'"; + } + else { + $sql = "SELECT * FROM user WHERE id='$this->id'"; + } + $db_results = mysql_query($sql, dbh()); + + return mysql_fetch_object($db_results); + + } // get_info + + /*! + @function get_preferences + @discussion gets the prefs for this specific + user and returns them as an array + */ + function get_preferences() { + + $sql = "SELECT preferences.name, preferences.description, preferences.type, user_preference.value FROM preferences,user_preference WHERE user_preference.user='$this->id' AND user_preference.preference=preferences.id AND preferences.type='user'"; + $db_results = mysql_query($sql, dbh()); + + while ($r = mysql_fetch_object($db_results)) { + $results[] = $r; + } + + return $results; + + } // get_preferences + + /*! + @function set_preferences + @discussion sets the prefs for this specific + user + */ + function set_preferences() { + + $sql = "SELECT preferences.name,user_preference.value FROM preferences,user_preference WHERE user_preference.user='$this->id' " . + "AND user_preference.preference=preferences.id AND preferences.type='user'"; + $db_results = mysql_query($sql, dbh()); + + while ($r = mysql_fetch_object($db_results)) { + $this->prefs[$r->name] = $r->value; + } + } // get_preferences + + /*! + @function get_favorites + @discussion returns an array of your $type + favorites + */ + function get_favorites($type) { + + $sql = "SELECT * FROM object_count" . + " WHERE count > 0" . + " AND object_type = '$type'" . + " AND userid = '" . $this->id . "'" . + " ORDER BY count DESC LIMIT " . conf('popular_threshold'); + $db_result = mysql_query($sql, dbh()); + + $items = array(); + $web_path = conf('web_path'); + + while ($r = @mysql_fetch_object($db_result) ) { + /* If its a song */ + if ($type == 'song') { + $data = new Song($r->object_id); + $data->count = $r->count; + $data->format_song(); + $data->f_name = $data->f_link; + $items[] = $data; + } + /* If its an album */ + elseif ($type == 'album') { + $data = new Album($r->object_id); + $data->count = $r->count; + $data->format_album(); + $items[] = $data; + } + /* If its an artist */ + elseif ($type == 'artist') { + $data = new Artist($r->object_id); + $data->count = $r->count; + $data->format_artist(); + $data->f_name = $data->link; + $items[] = $data; + } + + } // end while + + return $items; + + } // get_favorites + + /*! + @function is_xmlrpc + @discussion checks to see if this is a valid + xmlrpc user + */ + function is_xmlrpc() { + + /* If we aren't using XML-RPC return true */ + if (!conf('xml_rpc')) { + return false; + } + + //FIXME: Ok really what we will do is check the MD5 of the HTTP_REFERER + //FIXME: combined with the song title to make sure that the REFERER + //FIXME: is in the access list with full rights + return true; + + } // is_xmlrpc + + /*! + @function is_logged_in + @discussion checks to see if $this user is logged in + */ + function is_logged_in() { + + $sql = "SELECT id FROM session WHERE username='$this->id'" . + " AND expire > ". time(); + $db_results = mysql_query($sql,dbh()); + + if (mysql_num_rows($db_results)) { + return true; + } + + return false; + + } // is_logged_in + + /*! + @function has_access + @discussion this function checkes to see if this user has access + to the passed action (pass a level requirement) + */ + function has_access($needed_level) { + + if ($this->access == "admin") { $level = 100; } + elseif ($this->access == "user") { $level = 25; } + else { $level = $this->access; } + + if (!conf('use_auth') || conf('demo_mode')) { return true; } + + if ($level >= $needed_level) { return true; } + + return false; + + } // has_access + + /*! + @function update_preference + @discussion updates a single preference if the query fails + it attempts to insert the preference instead + */ + function update_preference($preference_id, $value, $id=0) { + + if (!$id) { + $id = $this->id; + } + + $value = sql_escape($value); + //FIXME: + // Do a has_access check here... + + $sql = "UPDATE user_preference SET value='$value' WHERE user='$id' AND preference='$preference_id'"; + $db_results = @mysql_query($sql, dbh()); + + } // update_preference + + /*! + @function add_preference + @discussion adds a new preference + @param $key preference name + @param $value preference value + @param $id user is + */ + function add_preference($preference_id, $value, $id=0) { + + if (!$id) { + $id = $this->id; + } + + $value = sql_escape($value); + + if (!is_numeric($preference_id)) { + $sql = "SELECT id FROM preferences WHERE `name`='$preference_id'"; + $db_results = mysql_query($sql, dbh()); + $r = mysql_fetch_array($db_results); + $preference_id = $r[0]; + } // end if it's not numeric + + $sql = "INSERT user_preference SET `user`='$id' , `value`='$value' , `preference`='$preference_id'"; + $db_results = mysql_query($sql, dbh()); + + } // add_preference + + /*! + @function update_username + @discussion updates their username + */ + function update_username($new_username) { + + $new_username = sql_escape($new_username); + $sql = "UPDATE user SET username='$new_username' WHERE id='$this->id'"; + $db_results = mysql_query($sql, dbh()); + + } // update_username + + /*! + @function update_fullname + @discussion updates their fullname + */ + function update_fullname($new_fullname) { + + $new_fullname = sql_escape($new_fullname); + $sql = "UPDATE user SET fullname='$new_fullname' WHERE id='$this->id'"; + $db_results = mysql_query($sql, dbh()); + + } // update_username + + /*! + @function update_email + @discussion updates their email address + */ + function update_email($new_email) { + + $new_email = sql_escape($new_email); + $sql = "UPDATE user SET email='$new_email' WHERE id='$this->id'"; + $db_results = mysql_query($sql, dbh()); + + } // update_email + + /*! + @function update_offset + @discussion this updates the users offset_limit + */ + function update_offset($new_offset) { + + $new_offset = sql_escape($new_offset); + $sql = "UPDATE user SET offset_limit='$new_offset' WHERE id='$this->id'"; + $db_results = mysql_query($sql, dbh()); + + } // update_offset + + /*! + @function update_access + @discussion updates their access level + */ + function update_access($new_access) { + + /* Check for all disable */ + if ($new_access == 'disabled') { + $sql = "SELECT id FROM user WHERE access != 'disabled' AND id != '$this->id'"; + $db_results = mysql_query($sql,dbh()); + if (!mysql_num_rows($db_results)) { return false; } + } + + /* Prevent Only User accounts */ + if ($new_access == 'user') { + $sql = "SELECT id FROM user WHERE (access='admin' OR access='100') AND id != '$this->id'"; + $db_results = mysql_query($sql, dbh()); + if (!mysql_num_rows($db_results)) { return false; } + } + + $new_access = sql_escape($new_access); + $sql = "UPDATE user SET access='$new_access' WHERE id='$this->id'"; + $db_results = mysql_query($sql, dbh()); + + } // update_access + + /*! + @function update_last_seen + @discussion updates the last seen data for this user + */ + function update_last_seen() { + + $sql = "UPDATE user SET last_seen='" . time() . "' WHERE id='$this->id'"; + $db_results = mysql_query($sql, dbh()); + + } // update_last_seen + + /*! + @function update_user_stats + @discussion updates the playcount mojo for this + specific user + */ + function update_stats($song_id) { + + $song_info = new Song($song_id); + $user = $this->id; + $dbh = dbh(); + + if (!$song_info->file) { return false; } + + $time = time(); + + // Play count for this song + $sql = "UPDATE object_count" . + " SET date = '$time', count=count+1" . + " WHERE object_type = 'song'" . + " AND object_id = '$song_id' AND userid = '$user'"; + $db_result = mysql_query($sql, $dbh); + + $rows = mysql_affected_rows(); + if (!$rows) { + $sql = "INSERT INTO object_count (object_type,object_id,date,count,userid)" . + " VALUES ('song','$song_id','$time','1','$user')"; + $db_result = mysql_query($sql, $dbh); + } + + // Play count for this artist + $sql = "UPDATE object_count" . + " SET date = '$time', count=count+1" . + " WHERE object_type = 'artist'" . + " AND object_id = '" . $song_info->artist . "' AND userid = '$user'"; + $db_result = mysql_query($sql, $dbh); + + $rows = mysql_affected_rows(); + if (!$rows) { + $sql = "INSERT INTO object_count (object_type,object_id,date,count,userid)" . + " VALUES ('artist','".$song_info->artist."','$time','1','$user')"; + $db_result = mysql_query($sql, $dbh); + } + + // Play count for this album + $sql = "UPDATE object_count" . + " SET date = '$time', count=count+1" . + " WHERE object_type = 'album'" . + " AND object_id = '".$song_info->album."' AND userid = '$user'"; + $db_result = mysql_query($sql, $dbh); + + $rows = mysql_affected_rows(); + if (!$rows) { + $sql = "INSERT INTO object_count (object_type,object_id,date,count,userid)" . + "VALUES ('album','".$song_info->album."','$time','1','$user')"; + $db_result = mysql_query($sql, $dbh); + } + + + } // update_stats + + /*! + @function create + @discussion inserts a new user into ampache + */ + function create($username, $fullname, $email, $password, $access) { + + /* Lets clean up the fields... */ + $username = sql_escape($username); + $fullname = sql_escape($fullname); + $email = sql_escape($email); + + /* Now Insert this new user */ + $sql = "INSERT INTO user (username, fullname, email, password, access) VALUES" . + " ('$username','$fullname','$email',PASSWORD('$password'),'$access')"; + $db_results = mysql_query($sql, dbh()); + if (!$db_results) { return false; } + $user_id = mysql_insert_id(dbh()); + + /* Populates any missing preferences, in this case all of them */ + $this->fix_preferences($user_id); + + return $user_id; + + } // new + + /*! + @function update_password + @discussion updates a users password + */ + function update_password($new_password) { + + $sql = "UPDATE user SET password=PASSWORD('$new_password') WHERE id='$this->id'"; + $db_results = mysql_query($sql, dbh()); + + return true; + } // update_password + + + /*! + @function format_favorites + @discussion takes an array of objects and formats them corrrectly + and returns a simply array with just <a href values + */ + function format_favorites($items) { + + // The length of the longest item + $maxlen = strlen($items[0]->count); + + // Go through the favs + foreach ($items as $data) { + + // Make all number lengths equal + $len = strlen($data->count); + while ($len < $maxlen) { + $data->count = "0" . $data->count; + $len++; + } + + $results[] = "<li>[$data->count] - $data->f_name</li>\n"; + + } // end foreach items + + return $results; + + } // format_favorites + + /*! + @function fix_preferences + @discussion this makes sure that the specified user + has all the correct preferences. This function + should be run whenever a system preference is run + it's a cop out... FIXME! + */ + function fix_preferences($user_id = 0) { + + if (!$user_id) { + $user_id = $this->id; + } + + /* Get All Preferences */ + $sql = "SELECT * FROM user_preference WHERE user='$user_id'"; + $db_results = mysql_query($sql, dbh()); + + while ($r = mysql_fetch_object($db_results)) { + /* Check for duplicates */ + if (isset($results[$r->preference])) { + $r->value = sql_escape($r->value); + $sql = "DELETE FROM user_preference WHERE user='$user_id' AND preference='$r->preference' AND value='$r->value'"; + $delete_results = mysql_query($sql, dbh()); + } // duplicate + else { + $results[$r->preference] = $r; + } + } // while results + + /* + If we aren't the 0 user before we continue then grab the + 0 user's values + */ + if ($user_id != '0') { + $sql = "SELECT user_preference.preference,user_preference.value FROM user_preference,preferences " . + "WHERE user_preference.preference = preferences.id AND user_preference.user='0' AND preferences.type='user'"; + $db_results = mysql_query($sql, dbh()); + while ($r = mysql_fetch_object($db_results)) { + $zero_results[$r->preference] = $r->value; + } + } // if not user 0 + + + $sql = "SELECT * FROM preferences"; + if ($user_id != '0') { + $sql .= " WHERE type='user'"; + } + $db_results = mysql_query($sql, dbh()); + + + while ($r = mysql_fetch_object($db_results)) { + + /* Check if this preference is set */ + if (!isset($results[$r->id])) { + if (isset($zero_results[$r->id])) { + $r->value = $zero_results[$r->id]; + } + $sql = "INSERT INTO user_preference (`user`,`preference`,`value`) VALUES ('$user_id','$r->id','$r->value')"; + $insert_db = mysql_query($sql, dbh()); + } + } // while preferences + + } // fix_preferences + + + /*! + @function delete_stats + @discussion deletes the stats for this user + */ + function delete_stats() { + + $sql = "DELETE FROM object_count WHERE userid='" . $this->id . "'"; + $db_results = mysql_query($sql, dbh()); + + } // delete_stats + + /*! + @function delete + @discussion deletes this user and everything assoicated with it + */ + function delete() { + + /* + Before we do anything make sure that they aren't the last + admin + */ + if ($this->has_access(100)) { + $sql = "SELECT * FROM user WHERE (level='admin' OR level='100') AND id!='" . $this->id . "'"; + $db_results = mysql_query($sql, dbh()); + if (!mysql_num_rows($db_results)) { + return false; + } + } // if this is an admin check for others + + // Delete their playlists + $sql = "DELETE FROM playlist WHERE owner='$this->id'"; + $db_results = mysql_query($sql, dbh()); + + // Delete any stats they have + $sql = "DELETE FROM object_count WHERE userid='$this->id'"; + $db_results = mysql_query($sql, dbh()); + + // Delete their preferences + $sql = "DELETE FROM preferences WHERE user='$this->id'"; + $db_results = mysql_query($sql, dbh()); + + // Delete the user itself + $sql = "DELETE FROM user WHERE id='$this->id'"; + $db_results = mysql_query($sql, dbh()); + + return true; + + } // delete + + /*! + @function is_online + @parameter delay how long since last_seen in seconds default of 20 min + @description calcs difference between now and last_seen + if less than delay, we consider them still online + */ + function is_online( $delay = 1200 ) { + return time() - $this->last_seen <= $delay; + } + +} //end class +?> diff --git a/modules/class/view.php b/modules/class/view.php new file mode 100644 index 00000000..f9de4ee6 --- /dev/null +++ b/modules/class/view.php @@ -0,0 +1,229 @@ +<? +/* + + Copyright (c) 2004 Ampache.org + All rights reserved. + + $CVSHeader: ampache/modules/class/artist.php,v 1.1 2004/03/25 09:12:57 vollmerk Exp $ + $Source: /data/cvsroot/ampache/modules/class/artist.php,v $ + + This program 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 + of the License, or (at your option) any later version. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +/*! + @header View Object of crappyness + View object that is thrown into their session + +*/ + + +class View { + + //Basic Componets + var $base_sql; + var $offset; + var $offset_limit; + var $sort_order; //asc or desc + var $sort_type; + var $action; + var $total_items; + + //generate a new view + function View($base_sql=0,$script=0,$sort_type=0,$total_items=0,$offset_limit=0) { + global $conf; + + // If we don't have a base sql, stop here + if (!is_string($base_sql)) { + return true; + } + + //Convert all 's into "s + $base_sql = str_replace("'",'"',$base_sql); + + $this->base_sql = $base_sql; + if ($offset_limit) { $this->offset_limit = $offset_limit; } + else { $this->offset_limit = $_SESSION['offset_limit']; } + if ($this->offset_limit < '1') { $this->offset_limit = '50'; } + $this->script = $script; + $this->sort_type = $sort_type; + $this->sort_order = "ASC"; + $this->offset = 0; + $this->total_items = $total_items; + + // Set the session + $_SESSION['view_offset_limit'] = $this->offset_limit; + $_SESSION['view_sort_type'] = $this->sort_type; + $_SESSION['view_offset'] = $this->offset; + $_SESSION['view_base_sql'] = $this->base_sql; + $_SESSION['view_sort_order'] = $this->sort_order; + $_SESSION['view_script'] = $this->script; + $_SESSION['view_total_items'] = $this->total_items; + $this->sql = $this->generate_sql(); + + } //constructor + + //takes all the parts and makes a full blown sql statement + function generate_sql() { + global $conf; + + $sql = $this->base_sql . " ORDER BY " . $this->sort_type ." ". $this->sort_order ." LIMIT " . $this->offset . "," . $this->offset_limit; + + return $sql; + + } //generate_sql + + //change the sort order from asc to desc or vise versa + function change_sort($new_sort=0) { + global $conf; + + if ($new_sort) { + $this->sort_order = $new_sort; + } + elseif ($this->sort_order == "DESC") { + $this->sort_order = "ASC"; + } + else { + $this->sort_order = "DESC"; + } + + $_SESSION['view_sort_order'] = $this->sort_order; + + $this->sql = $this->generate_sql(); + + return; + + } //change_sort + + //change the base sql + function change_sql($base_sql) { + global $conf; + + //Convert all 's into "s + $base_sql = str_replace("'",'"',$base_sql); + + $this->base_sql = $base_sql; + + $_SESSION['view_base_sql'] = $this->base_sql; + + $this->sql = $this->generate_sql(); + + } //change_sql + + //change offset + function change_offset($offset=0) { + global $conf; + + if (isset($offset)) { + $this->offset = $offset; + } + else { + $this->offset = $this->offset + $this->offset_limit; + } + + $_SESSION['view_offset'] = $this->offset; + + $this->sql = $this->generate_sql(); + + } //change_offset + + //change sort_type + function change_sort_type($sort_type) { + + $this->sort_type = $sort_type; + + $_SESSION['view_sort_type'] = $this->sort_type; + + $this->sql = $this->generate_sql(); + + } //change_sort_type + + /*! + @function change_offset_limit + @discussion changes the offset limit, sets the session + var and generates the sql statement + */ + function change_offset_limit($offset_limit) { + + $this->offset_limit = $offset_limit; + + $_SESSION['view_offset_limit'] = $this->offset_limit; + + $this->sql = $this->generate_sql(); + + } // change_offset_limit + + /*! + @function initialize + @discussion initializes the view object, checks $_REQUEST + for changes to the view object + */ + function initialize() { + + if ($_REQUEST['sort_type']) { + $this->change_sort_type($_REQUEST['sort_type']); + } + + if (isset($_REQUEST['offset'])) { + $this->change_offset($_REQUEST['offset']); + } + + if ($_REQUEST['base_sql']) { + $this->change_sql($_REQUEST['base_sql']); + } + + if (isset($_REQUEST['sort_order'])) { + $this->change_sort($_REQUEST['sort_order']); + } + + if ($_REQUEST['offset_limit']) { + $this->change_offset_limit($_REQUEST['offset_limit']); + } + + } // initialize + + + /*! + @function import_session_view + @discussion this imports the view from the session for use.. + this keeps us from having to globalize anything + wohoo! + */ + function import_session_view() { + + $this->sort_type = $_SESSION['view_sort_type']; + $this->offset = $_SESSION['view_offset']; + $this->base_sql = $_SESSION['view_base_sql']; + $this->sort_order = $_SESSION['view_sort_order']; + $this->script = $_SESSION['view_script']; + $this->total_items = $_SESSION['view_total_items']; + + + if ($_SESSION['view_offset_limit']) { + $this->offset_limit = $_SESSION['view_offset_limit']; + } + else { + $this->offset_limit = $_SESSION['offset_limit']; + } + + + $this->sql = $this->generate_sql(); + + } // import_session_view + + + +} //end class +?> |