diff options
author | Paul Arthur <flowerysong00@yahoo.com> | 2011-04-02 00:22:55 -0400 |
---|---|---|
committer | Paul Arthur <flowerysong00@yahoo.com> | 2011-04-02 00:48:58 -0400 |
commit | a9da6a6fa22325ba0dfecd4d46ae23305473796f (patch) | |
tree | acef914ee602bfeb3eed98f5f06e79603a6eb74f | |
parent | 91a6eb3a682667f49122fab5d807e8650c0d3959 (diff) | |
download | ampache-a9da6a6fa22325ba0dfecd4d46ae23305473796f.tar.gz ampache-a9da6a6fa22325ba0dfecd4d46ae23305473796f.tar.bz2 ampache-a9da6a6fa22325ba0dfecd4d46ae23305473796f.zip |
Reworked search
Still has tentacles and should have been integrated into the existing
API/Browse implementation better, but it's functional.
31 files changed, 2095 insertions, 712 deletions
@@ -53,6 +53,18 @@ switch ($_REQUEST['action']) { $media_ids = $playlist->get_songs(); $name = $playlist->name; break; + case 'smartplaylist': + $search = new Search('song', $_REQUEST['id']); + $sql = $search->to_sql(); + $sql = $sql['base'] . ' ' . $sql['table_sql'] . ' WHERE ' . + $sql['where_sql']; + $db_results = Dba::read($sql); + $media_ids = array(); + while ($row = Dba::fetch_assoc($db_results)) { + $media_ids[] = $row['id']; + } + $name = $search->name; + break; case 'album': $album = new Album($_REQUEST['id']); $media_ids = $album->get_songs(); @@ -66,7 +78,22 @@ switch ($_REQUEST['action']) { case 'browse': $id = scrub_in($_REQUEST['browse_id']); $browse = new Browse($id); - $media_ids = $browse->get_saved(); + $browse_media_ids = $browse->get_saved(); + $media_ids = array(); + foreach ($browse_media_ids as $media_id) { + switch ($_REQUEST['type']) { + case 'album': + $album = new Album($media_id); + $media_ids = array_merge($media_ids, $album->get_songs()); + break; + case 'song': + $media_ids[] = $media_id; + break; + case 'video': + $media_ids[] = array('Video', $media_id); + break; + } // switch on type + } // foreach media_id $name = 'Batch-' . date("dmY",time()); default: // Rien a faire @@ -55,6 +55,7 @@ switch ($_REQUEST['action']) { case 'album': case 'artist': case 'playlist': + case 'smartplaylist': case 'live_stream': case 'video': case 'song': @@ -108,6 +109,11 @@ switch($_REQUEST['action']) { $browse->set_filter('playlist_type','1'); $browse->show_objects(); break; + case 'smartplaylist': + $browse->set_sort('type', 'ASC'); + $browse->set_filter('playlist_type','1'); + $browse->show_objects(); + break; case 'video': $browse->set_sort('title','ASC'); $browse->show_objects(); diff --git a/lib/class/api.class.php b/lib/class/api.class.php index 508d38c2..9bd659a4 100644 --- a/lib/class/api.class.php +++ b/lib/class/api.class.php @@ -594,11 +594,13 @@ class Api { /** * search_songs - * This returns the songs and returns... songs + * This searches the songs and returns... songs */ public static function search_songs($input) { + $array['rule_1'] = 'anywhere'; + $array['rule_1_input'] = $input['filter']; + $array['rule_1_operator'] = 0; - $array['s_all'] = $input['filter']; ob_end_clean(); xmlData::set_offset($input['offset']); @@ -608,7 +610,7 @@ class Api { //Run search references these variables, ooh the huge manatee unset($input['limit'],$input['offset']); - $results = run_search($array); + $results = Search::run($array); echo xmlData::songs($results); diff --git a/lib/class/browse.class.php b/lib/class/browse.class.php index 56eda8b7..c997c478 100644 --- a/lib/class/browse.class.php +++ b/lib/class/browse.class.php @@ -188,6 +188,11 @@ class Browse extends Query { require_once Config::get('prefix') . '/templates/show_localplay_playlist.inc.php'; show_box_bottom(); break; + case 'smartplaylist': + show_box_top(_('Smart Playlists') . $match, $class); + require_once Config::get('prefix') . '/templates/show_smartplaylists.inc.php'; + show_box_bottom(); + break; case 'catalog': show_box_top(_('Catalogs'), $class); require_once Config::get('prefix') . '/templates/show_catalogs.inc.php'; diff --git a/lib/class/playlist.class.php b/lib/class/playlist.class.php index 6624540c..42638820 100644 --- a/lib/class/playlist.class.php +++ b/lib/class/playlist.class.php @@ -46,13 +46,9 @@ * @link http://www.ampache.org/ * @since Class available since Release 1.0 */ -class Playlist extends database_object { +class Playlist extends playlist_object { /* Variables from the database */ - public $id; - public $name; - public $user; - public $type; public $genre; public $date; @@ -94,43 +90,33 @@ class Playlist extends database_object { } // build_cache /** - * format - * This takes the current playlist object and gussies it up a little - * bit so it is presentable to the users + * get_playlists + * Returns a list of playlists accessible by the current user. */ - public function format() { - - $this->f_name = truncate_with_ellipsis($this->name,Config::get('ellipse_threshold_title')); - $this->f_link = '<a href="' . Config::get('web_path') . '/playlist.php?action=show_playlist&playlist_id=' . $this->id . '">' . $this->f_name . '</a>'; - - $this->f_type = ($this->type == 'private') ? get_user_icon('lock',_('Private')) : ''; + public static function get_playlists() { + $sql = "SELECT `id` from `playlist` WHERE `type`='public' OR " . + "`user`='" . $GLOBALS['user']->id . "' ORDER BY `name`"; + $db_results = Dba::read($sql); - $client = new User($this->user); + $results = array(); - $this->f_user = $client->fullname; + while ($row = Dba::fetch_assoc($db_results)) { + $results[] = $row['id']; + } - } // format + return $results; + } // get_playlists /** - * has_access - * This function returns true or false if the current user - * has access to this playlist + * format + * This takes the current playlist object and gussies it up a little + * bit so it is presentable to the users */ - public function has_access() { - - if (!Access::check('interface','25')) { - return false; - } - if ($this->user == $GLOBALS['user']->id) { - return true; - } - else { - return Access::check('interface','100'); - } - - return false; + public function format() { + parent::format(); + $this->f_link = '<a href="' . Config::get('web_path') . '/playlist.php?action=show_playlist&playlist_id=' . $this->id . '">' . $this->f_name . '</a>'; - } // has_access + } // format /** * get_track diff --git a/lib/class/playlist_object.abstract.php b/lib/class/playlist_object.abstract.php new file mode 100644 index 00000000..def7b3f2 --- /dev/null +++ b/lib/class/playlist_object.abstract.php @@ -0,0 +1,72 @@ +<?php +/* vim:set tabstop=8 softtabstop=8 shiftwidth=8 noexpandtab: */ +/* + + Copyright (c) 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 v2 + as published by the Free Software Foundation. + + 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. +*/ + +/** + * playlist_object + * Abstracting out functionality needed by both normal and smart playlists + */ +abstract class playlist_object extends database_object { + + // Database variables + public $id; + public $name; + public $user; + public $type; + + /** + * format + * This takes the current playlist object and gussies it up a little + * bit so it is presentable to the users + */ + public function format() { + + $this->f_name = truncate_with_ellipsis($this->name,Config::get('ellipse_threshold_title')); + $this->f_type = ($this->type == 'private') ? get_user_icon('lock',_('Private')) : ''; + + $client = new User($this->user); + + $this->f_user = $client->fullname; + + } // format + + /** + * has_access + * This function returns true or false if the current user + * has access to this playlist + */ + public function has_access() { + + if (!Access::check('interface','25')) { + return false; + } + if ($this->user == $GLOBALS['user']->id) { + return true; + } + else { + return Access::check('interface','100'); + } + + return false; + + } // has_access + + +} // end playlist_object diff --git a/lib/class/query.class.php b/lib/class/query.class.php index 898e8029..11095b80 100644 --- a/lib/class/query.class.php +++ b/lib/class/query.class.php @@ -144,6 +144,10 @@ class Query { 'alpha_match', 'starts_with' ), + 'smartplaylist' => array( + 'alpha_match', + 'starts_with' + ), 'tag' => array( 'tag', 'object_type', @@ -194,6 +198,10 @@ class Query { 'name', 'user' ), + 'smartplaylist' => array( + 'name', + 'user' + ), 'shoutbox' => array( 'date', 'user', @@ -465,6 +473,7 @@ class Query { case 'video': case 'playlist': case 'playlist_song': + case 'smartplaylist': case 'song': case 'flagged': case 'catalog': @@ -735,6 +744,10 @@ class Query { $this->set_select("`playlist`.`id`"); $sql = "SELECT %%SELECT%% FROM `playlist` "; break; + case 'smartplaylist': + self::set_select('`search`.`id`'); + $sql = "SELECT %%SELECT%% FROM `search` "; + break; case 'flagged': $this->set_select("`flagged`.`id`"); $sql = "SELECT %%SELECT%% FROM `flagged` "; @@ -1127,6 +1140,20 @@ class Query { break; } // end filter break; + case 'smartplaylist': + switch ($filter) { + case 'alpha_match': + $filter_sql = " `search`.`name` LIKE '%" . Dba::escape($value) . "%' AND "; + break; + case 'starts_with': + $filter_sql = " `search`.`name` LIKE '" . Dba::escape($value) . "%' AND "; + break; + case 'playlist_type': + $user_id = intval($GLOBALS['user']->id); + $filter_sql = " (`search`.`type` = 'public' OR `search`.`user`='$user_id') AND "; + break; + } // end switch on $filter + break; case 'tag': switch ($filter) { case 'alpha_match': @@ -1251,6 +1278,19 @@ class Query { break; } // end switch break; + case 'smartplaylist': + switch ($field) { + case 'type': + $sql = "`search`.`type`"; + break; + case 'name': + $sql = "`search`.`name`"; + break; + case 'user': + $sql = "`search`.`user`"; + break; + } // end switch on $field + break; case 'live_stream': switch ($field) { case 'name': diff --git a/lib/class/random.class.php b/lib/class/random.class.php index 575cf8fb..5472bb80 100644 --- a/lib/class/random.class.php +++ b/lib/class/random.class.php @@ -254,120 +254,60 @@ class Random implements media { * This processes the results of a post from a form and returns an * array of song items that were returned from said randomness */ - public static function advanced($data) { + public static function advanced($type, $data) { /* Figure out our object limit */ $limit = intval($data['random']); // Generate our matchlist - if ($data['catalog'] != '-1') { - $matchlist['catalog'] = $data['catalog']; - } - if ($data['genre'][0] != '-1') { - $matchlist['genre'] = $data['genre']; - } - /* If they've passed -1 as limit then don't get everything */ + /* If they've passed -1 as limit then get everything */ if ($data['random'] == "-1") { unset($data['random']); } else { $limit_sql = "LIMIT " . Dba::escape($limit); } - $where = "1=1 "; - if (is_array($matchlist)) { - foreach ($matchlist as $type => $value) { - if (is_array($value)) { - foreach ($value as $v) { - if (!strlen($v)) { continue; } - $v = Dba::escape($v); - if ($v != $value[0]) { $where .= " OR $type='$v' "; } - else { $where .= " AND ( $type='$v'"; } - } - $where .= ")"; - } - elseif (strlen($value)) { - $value = Dba::escape($value); - $where .= " AND $type='$value' "; - } - } // end foreach - } // end if matchlist - - switch ($data['random_type']) { - case 'full_album': - $query = "SELECT `album`.`id` FROM `song` INNER JOIN `album` ON `song`.`album`=`album`.`id` " . - "WHERE $where GROUP BY `song`.`album` ORDER BY RAND() $limit_sql"; - $db_results = Dba::read($query); - while ($row = Dba::fetch_assoc($db_results)) { - $albums_where .= " OR `song`.`album`=" . $row['id']; - } - $albums_where = ltrim($albums_where," OR"); - $sql = "SELECT `song`.`id`,`song`.`size`,`song`.`time` FROM `song` WHERE $albums_where ORDER BY `song`.`album`,`song`.`track` ASC"; - break; - case 'full_artist': - $query = "SELECT `artist`.`id` FROM `song` INNER JOIN `artist` ON `song`.`artist`=`artist`.`id` " . - "WHERE $where GROUP BY `song`.`artist` ORDER BY RAND() $limit_sql"; - $db_results = Dba::read($query); - while ($row = Dba::fetch_row($db_results)) { - $artists_where .= " OR song.artist=" . $row[0]; - } - $artists_where = ltrim($artists_where," OR"); - $sql = "SELECT song.id,song.size,song.time FROM song WHERE $artists_where ORDER BY RAND()"; - break; - case 'unplayed': - $uid = Dba::escape($GLOBALS['user']->id); - $sql = "SELECT object_id,COUNT(`id`) AS `total` FROM `object_count` WHERE `user`='$uid' GROUP BY `object_id`"; - $db_results = Dba::read($sql); - - $in_sql = "`id` IN ("; + $search_data = Search::clean_request($data); - while ($row = Dba::fetch_assoc($db_results)) { - $row['object_id'] = Dba::escape($row['object_id']); - $in_sql .= "'" . $row['object_id'] . "',"; - } + $search_info = false; - $in_sql = rtrim($in_sql,',') . ')'; + if (count($search_data) > 1) { + $search = new Search($type); + $search->parse_rules($search_data); + $search_info = $search->to_sql(); + } - $sql = "SELECT song.id,song.size,song.time FROM song " . - "WHERE ($where) AND $in_sql ORDER BY RAND() $limit_sql"; - break; - case 'high_rating': - $sql = "SELECT `rating`.`object_id`,`rating`.`rating` FROM `rating` " . - "WHERE `rating`.`object_type`='song' ORDER BY `rating` DESC"; - $db_results = Dba::read($sql); - - // Get all of the ratings for songs - while ($row = Dba::fetch_assoc($db_results)) { - $results[$row['object_id']][] = $row['rating']; + switch ($type) { + case 'song': + $sql = "SELECT `song`.`id`, `size`, `time` " . + "FROM `song` "; + if ($search_info) { + $sql .= $search_info['table_sql']; + $sql .= ' WHERE ' . $search_info['where_sql']; } - // Calculate the averages - foreach ($results as $key=>$rating_array) { - $average = intval(array_sum($rating_array) / count($rating_array)); - // We have to do this because array_slice doesn't maintain indexes - $new_key = $average . $key; - $ratings[$new_key] = $key; + break; + case 'album': + $sql = "SELECT `album`.`id`, SUM(`song`.`size`) AS `size`, SUM(`song`.`time`) AS `time` FROM `album` "; + if (! $search_info || ! $search_info['join']['song']) { + $sql .= "LEFT JOIN `song` ON `song`.`album`=`album`.`id` "; } - - // Sort it by the value and slice at $limit * 2 so we have a little bit of randomness - krsort($ratings); - $ratings = array_slice($ratings,0,$limit*2); - - $in_sql = "`song`.`id` IN ("; - - // Build the IN query, cause if you're OUT it ain't cool - foreach ($ratings as $song_id) { - $key = Dba::escape($song_id); - $in_sql .= "'$key',"; + if ($search_info) { + $sql .= $search_info['table_sql']; + $sql .= ' WHERE ' . $search_info['where_sql']; } - - $in_sql = rtrim($in_sql,',') . ')'; - - // Apply true limit and order by rand - $sql = "SELECT song.id,song.size,song.time FROM song " . - "WHERE ($where) AND $in_sql ORDER BY RAND() $limit_sql"; + $sql .= ' GROUP BY `album`.`id`'; break; - default: - $sql = "SELECT `id`,`size`,`time` FROM `song` WHERE $where ORDER BY RAND() $limit_sql"; - + case 'artist': + $sql = "SELECT `artist`.`id`, SUM(`song`.`size`) AS `size`, SUM(`song`.`time`) AS `time` FROM `artist` "; + if (! $search_info || ! $search_info['join']['song']) { + $sql .= "LEFT JOIN `song` ON `song`.`artist`=`artist`.`id` "; + } + if ($search_info) { + $sql .= $search_info['table_sql']; + $sql .= ' WHERE ' . $search_info['where_sql']; + } + $sql .= ' GROUP BY `artist`.`id`'; break; - } // end switch on type of random play + } + $sql .= " ORDER BY RAND() $limit_sql"; // Run the query generated above so we can while it $db_results = Dba::read($sql); @@ -380,17 +320,23 @@ class Random implements media { // Convert $new_size = ($row['size'] / 1024) / 1024; - // Only fuzzy 10 times - if ($fuzzy_size > 10) { return $results; } + // Only fuzzy 100 times + if ($fuzzy_size > 100) { + break; + } - // Add and check, skip if over don't return incase theres a smaller one commin round - if (($size_total + $new_size) > $data['size_limit']) { $fuzzy_size++; continue; } + // Add and check, skip if over size + if (($size_total + $new_size) > $data['size_limit']) { + $fuzzy_size++; + continue; + } $size_total = $size_total + $new_size; $results[] = $row['id']; // If we are within 4mb of target then jump ship - if (($data['size_limit'] - floor($size_total)) < 4) { return $results; } + if (($data['size_limit'] - floor($size_total)) < 4) { + break; } } // if size_limit // If length really does matter @@ -398,33 +344,60 @@ class Random implements media { // base on min, seconds are for chumps and chumpettes $new_time = floor($row['time'] / 60); - if ($fuzzy_time > 10) { return $results; } + if ($fuzzy_time > 100) { + break;; + } - // If the new one would go voer skip! - if (($time_total + $new_time) > $data['length']) { $fuzzy_time++; continue; } + // If the new one would go over skip! + if (($time_total + $new_time) > $data['length']) { + $fuzzy_time++; + continue; + } $time_total = $time_total + $new_time; $results[] = $row['id']; // If there are less then 2 min of free space return - if (($data['length'] - $time_total) < 2) { return $results; } - + if (($data['length'] - $time_total) < 2) { + return $results; + } } // if length does matter - if (!$data['size_limit'] AND !$data['length']) { + if (!$data['size_limit'] && !$data['length']) { $results[] = $row['id']; } } // end while results - - return $results; - + switch ($type) { + case 'song': + return $results; + break; + case 'album': + $songs = array(); + foreach ($results as $result) { + $album = new Album($result); + $songs = array_merge($songs, $album->get_songs()); + } + return $songs; + break; + case 'artist': + $songs = array(); + foreach ($results as $result) { + $artist = new Artist($result); + $songs = array_merge($songs, $artist->get_songs()); + } + return $songs; + break; + default: + return false; + break; + } } // advanced /** * get_type_name - * This returns a 'purrty' name for the differnt random types + * This returns a 'purrty' name for the different random types */ public static function get_type_name($type) { diff --git a/lib/class/search.class.php b/lib/class/search.class.php new file mode 100644 index 00000000..f2c3cee9 --- /dev/null +++ b/lib/class/search.class.php @@ -0,0 +1,1033 @@ +<?php +/* vim:set tabstop=8 softtabstop=8 shiftwidth=8 noexpandtab: */ +/* + + Copyright (c) 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 v2 + as published by the Free Software Foundation. + + 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. + +*/ + +/** + * Search Class + * Search-related voodoo. Beware tentacles. + */ + +class Search extends playlist_object { + + public $searchtype; + public $rules; + public $logic_operator = 'AND'; + public $type = 'public'; + + public $basetypes; + public $types; + + /** + * constructor + */ + public function __construct($searchtype = 'song', $id = '') { + $this->searchtype = $searchtype; + if ($id) { + $info = $this->get_info($id); + foreach ($info as $key=>$value) { + $this->$key = $value; + } + + $this->rules = unserialize($this->rules); + } + + // Define our basetypes + + $this->basetypes['numeric'][] = array( + 'name' => 'gte', + 'description' => _('is greater than or equal to'), + 'sql' => '>=' + ); + + $this->basetypes['numeric'][] = array( + 'name' => 'lte', + 'description' => _('is less than or equal to'), + 'sql' => '<=' + ); + + $this->basetypes['numeric'][] = array( + 'name' => 'equal', + 'description' => _('is'), + 'sql' => '<=>' + ); + + $this->basetypes['numeric'][] = array( + 'name' => 'ne', + 'description' => _('is not'), + 'sql' => '<>' + ); + + $this->basetypes['numeric'][] = array( + 'name' => 'gt', + 'description' => _('is greater than'), + 'sql' => '>' + ); + + $this->basetypes['numeric'][] = array( + 'name' => 'lt', + 'description' => _('is less than'), + 'sql' => '<' + ); + + + $this->basetypes['boolean'][] = array( + 'name' => 'true', + 'description' => _('is true') + ); + + $this->basetypes['boolean'][] = array( + 'name' => 'false', + 'description' => _('is false') + ); + + + $this->basetypes['text'][] = array( + 'name' => 'contain', + 'description' => _('contains'), + 'sql' => 'LIKE', + 'preg_match' => array('/^/','/$/'), + 'preg_replace' => array('%', '%') + ); + + $this->basetypes['text'][] = array( + 'name' => 'notcontain', + 'description' => _('does not contain'), + 'sql' => 'NOT LIKE', + 'preg_match' => array('/^/','/$/'), + 'preg_replace' => array('%', '%') + ); + + $this->basetypes['text'][] = array( + 'name' => 'start', + 'description' => _('starts with'), + 'sql' => 'LIKE', + 'preg_match' => '/$/', + 'preg_replace' => '%' + ); + + $this->basetypes['text'][] = array( + 'name' => 'end', + 'description' => _('ends with'), + 'sql' => 'LIKE', + 'preg_match' => '/^/', + 'preg_replace' => '%' + ); + + $this->basetypes['text'][] = array( + 'name' => 'equal', + 'description' => _('is'), + 'sql' => '=' + ); + + $this->basetypes['text'][] = array( + 'name' => 'sounds', + 'description' => _('sounds like'), + 'sql' => 'SOUNDS LIKE' + ); + + $this->basetypes['text'][] = array( + 'name' => 'notsounds', + 'description' => _('does not sound like'), + 'sql' => 'NOT SOUNDS LIKE' + ); + + + $this->basetypes['boolean_numeric'][] = array( + 'name' => 'equal', + 'description' => _('is'), + 'sql' => '<=>' + ); + + $this->basetypes['boolean_numeric'][] = array( + 'name' => 'ne', + 'description' => _('is not'), + 'sql' => '<>' + ); + + + $this->basetypes['boolean_subsearch'][] = array( + 'name' => 'equal', + 'description' => _('is'), + 'sql' => '' + ); + + $this->basetypes['boolean_subsearch'][] = array( + 'name' => 'ne', + 'description' => _('is not'), + 'sql' => 'NOT' + ); + + + $this->basetypes['date'][] = array( + 'name' => 'lt', + 'description' => _('before'), + 'sql' => '>' + ); + + $this->basetypes['date'][] = array( + 'name' => 'gt', + 'description' => _('after'), + 'sql' => '>' + ); + + switch ($searchtype) { + case 'song': + $this->types[] = array( + 'name' => 'anywhere', + 'label' => _('Any searchable text'), + 'type' => 'text', + 'widget' => array('input', 'text') + ); + + $this->types[] = array( + 'name' => 'title', + 'label' => _('Title'), + 'type' => 'text', + 'widget' => array('input', 'text') + ); + + $this->types[] = array( + 'name' => 'album', + 'label' => _('Album'), + 'type' => 'text', + 'widget' => array('input', 'text') + ); + + $this->types[] = array( + 'name' => 'artist', + 'label' => _('Artist'), + 'type' => 'text', + 'widget' => array('input', 'text') + ); + + $this->types[] = array( + 'name' => 'comment', + 'label' => _('Comment'), + 'type' => 'text', + 'widget' => array('input', 'text') + ); + + + $this->types[] = array( + 'name' => 'tag', + 'label' => _('Tag'), + 'type' => 'text', + 'widget' => array('input', 'text') + ); + + $this->types[] = array( + 'name' => 'file', + 'label' => _('Filename'), + 'type' => 'text', + 'widget' => array('input', 'text') + ); + + $this->types[] = array( + 'name' => 'year', + 'label' => _('Year'), + 'type' => 'numeric', + 'widget' => array('input', 'text') + ); + + $this->types[] = array( + 'name' => 'time', + 'label' => _('Length (in minutes)'), + 'type' => 'numeric', + 'widget' => array('input', 'text') + ); + + if (Config::get('ratings')) { + $this->types[] = array( + 'name' => 'rating', + 'label' => _('Rating'), + 'type' => 'numeric', + 'widget' => array( + 'select', + array( + '1 Star', + '2 Stars', + '3 Stars', + '4 Stars', + '5 Stars' + ) + ) + ); + } + + $this->types[] = array( + 'name' => 'bitrate', + 'label' => _('Bitrate'), + 'type' => 'numeric', + 'widget' => array( + 'select', + array( + '32', + '40', + '48', + '56', + '64', + '80', + '96', + '112', + '128', + '160', + '192', + '224', + '256', + '320' + ) + ) + ); + + $this->types[] = array( + 'name' => 'played', + 'label' => _('Played'), + 'type' => 'boolean', + 'widget' => array('input', 'hidden') + ); + + $this->types[] = array( + 'name' => 'added', + 'label' => _('Added'), + 'type' => 'date', + 'widget' => array('input', 'text') + ); + + $this->types[] = array( + 'name' => 'updated', + 'label' => _('Updated'), + 'type' => 'date', + 'widget' => array('input', 'text') + ); + + $catalogs = array(); + foreach (Catalog::get_catalogs() as $catid) { + $catalog = new Catalog($catid); + $catalog->format(); + $catalogs[$catid] = $catalog->f_name; + } + $this->types[] = array( + 'name' => 'catalog', + 'label' => _('Catalog'), + 'type' => 'boolean_numeric', + 'widget' => array('select', $catalogs) + ); + + $playlists = array(); + foreach (Playlist::get_playlists() as $playlistid) { + $playlist = new Playlist($playlistid); + $playlist->format(); + $playlists[$playlistid] = $playlist->f_name; + } + $this->types[] = array( + 'name' => 'playlist', + 'label' => _('Playlist'), + 'type' => 'boolean_numeric', + 'widget' => array('select', $playlists) + ); + + $playlists = array(); + foreach (Search::get_searches() as $playlistid) { + // Slightly different from the above so we don't + // instigate a vicious loop. + $playlists[$playlistid] = Search::get_name_byid($playlistid); + } + $this->types[] = array( + 'name' => 'smartplaylist', + 'label' => _('Smart Playlist'), + 'type' => 'boolean_subsearch', + 'widget' => array('select', $playlists) + ); + break; + case 'album': + $this->types[] = array( + 'name' => 'title', + 'label' => _('Title'), + 'type' => 'text', + 'widget' => array('input', 'text') + ); + + $this->types[] = array( + 'name' => 'year', + 'label' => _('Year'), + 'type' => 'numeric', + 'widget' => array('input', 'text') + ); + + if (Config::get('ratings')) { + $this->types[] = array( + 'name' => 'rating', + 'label' => _('Rating'), + 'type' => 'numeric', + 'widget' => array( + 'select', + array( + '1 Star', + '2 Stars', + '3 Stars', + '4 Stars', + '5 Stars' + ) + ) + ); + } + + $catalogs = array(); + foreach (Catalog::get_catalogs() as $catid) { + $catalog = new Catalog($catid); + $catalog->format(); + $catalogs[$catid] = $catalog->f_name; + } + $this->types[] = array( + 'name' => 'catalog', + 'label' => _('Catalog'), + 'type' => 'boolean_numeric', + 'widget' => array('select', $catalogs) + ); + + + $this->types[] = array( + 'name' => 'tag', + 'label' => _('Tag'), + 'type' => 'text', + 'widget' => array('input', 'text') + ); + break; + case 'video': + $this->types[] = array( + 'name' => 'filename', + 'label' => _('Filename'), + 'type' => 'text', + 'widget' => array('input', 'text') + ); + break; + case 'artist': + $this->types[] = array( + 'name' => 'name', + 'label' => _('Name'), + 'type' => 'text', + 'widget' => array('input', 'text') + ); + $this->types[] = array( + 'name' => 'tag', + 'label' => _('Tag'), + 'type' => 'text', + 'widget' => array('input', 'text') + ); + break; + } // end switch on searchtype + + } // end constructor + + /** + * clean_request + * Sanitizes raw search data + */ + public static function clean_request($data) { + foreach ($data as $key => $value) { + $prefix = substr($key, 0, 4); + $value = trim($value); + + if ($prefix == 'rule' && strlen($value)) { + $request[$key] = Dba::escape($value); + } + } // end foreach $data + + // Figure out if they want an AND based search or an OR based + // search + switch($data['operator']) { + case 'or': + $request['operator'] = 'OR'; + break; + default: + $request['operator'] = 'AND'; + break; + } // end switcn on operator + + return $request; + } // end clean_request + + /** + * get_name_byid + * Returns the name of the saved search corresponding to the given ID + */ + public static function get_name_byid($id) { + $sql = "SELECT `name` FROM `search` WHERE `id`='$id'"; + $db_results = Dba::read($sql); + $r = Dba::fetch_assoc($db_results); + return $r['name']; + } // end get_name_byid + + /** + * get_searches + * Return the IDs of all saved searches accessible by the current user. + */ + public static function get_searches() { + $sql = "SELECT `id` from `search` WHERE `type`='public' OR " . + "`user`='" . $GLOBALS['user']->id . "' ORDER BY `name`"; + $db_results = Dba::read($sql); + + $results = array(); + + while ($row = Dba::fetch_assoc($db_results)) { + $results[] = $row['id']; + } + + return $results; + } // end get_searches + + /** + * run + * This function actually runs the search, and returns an array of the + * results. + */ + public static function run($data) { + $limit = intval($data['limit']); + /* Create an array of the object we need to search on */ + $data = Search::clean_request($data); + + $search = new Search($_REQUEST['type']); + $search->parse_rules($data); + + /* Generate BASE SQL */ + + if ($limit > 0) { + $limit_sql = " LIMIT " . $limit; + } + + $search_info = $search->to_sql(); + $sql = $search_info['base'] . ' ' . $search_info['table_sql'] . + ' WHERE ' . $search_info['where_sql'] . " $limit_sql"; + + $db_results = Dba::read($sql); + + $results = array(); + + while ($row = Dba::fetch_assoc($db_results)) { + $results[] = $row['id']; + } + + return $results; + } // run + + /** + * delete + * Does what it says on the tin. + */ + public function delete() { + $id = Dba::escape($this->id); + $sql = "DELETE FROM `search` WHERE `id`='$id'"; + $db_results = Dba::write($sql); + + return true; + } // end delete + + /** + * format + * Gussy up the data + */ + public function format() { + parent::format(); + $this->f_link = '<a href="' . Config::get('web_path') . '/smartplaylist.php?action=show_playlist&playlist_id=' . $this->id . '">' . $this->f_name . '</a>'; + } // end format + + /** + * get_items + * return an array of the items output by our search (part of the + * playlist interface). + */ + public function get_items() { + $results = array(); + + $sql = $this->to_sql(); + $sql = $sql['base'] . ' ' . $sql['table_sql'] . ' WHERE ' . + $sql['where_sql']; + + $db_results = Dba::read($sql); + + while ($row = Dba::fetch_assoc($db_results)) { + $results[] = array( + 'object_id' => $row['id'], + 'type' => $this->searchtype + ); + } + + return $results; + } // end get_items + + /** + * name_to_basetype + * Iterates over our array of types to find out the basetype for + * the passed string. + */ + public function name_to_basetype($name) { + foreach ($this->types as $type) { + if ($type['name'] == $name) { + return $type['type']; + } + } + return false; + } // end name_to_basetype + + /** + * parse_rules + * Takes an array of sanitized search data from the form and generates + * our real array from it. + */ + public function parse_rules($data) { + $this->rules = array(); + foreach ($data as $rule => $value) { + if (preg_match('/^rule_(\d)$/', $rule, $ruleID)) { + $ruleID = $ruleID[1]; + foreach (explode('|', $data['rule_' . $ruleID . '_input']) as $input) { + $this->rules[] = array( + $value, + $this->basetypes[$this->name_to_basetype($value)][$data['rule_' . $ruleID . '_operator']]['name'], + $input + ); + } + } + } + $this->logic_operator = $data['operator']; + } // end parse_rules + + /** + * save + * Save this search to the database for use as a smart playlist + */ + public function save() { + // Make sure we have a unique name + if (! $this->name) { + $this->name = $GLOBALS['user']->username . ' - ' . date("Y-m-d H:i:s",time()); + } + $sql = "SELECT `id` FROM `search` WHERE `name`='$this->name'"; + $db_results = Dba::read($sql); + if (Dba::num_rows($db_results)) { + $this->name .= uniqid('', true); + } + + // clean up variables for insert + $name = Dba::escape($this->name); + $user = Dba::escape($GLOBALS['user']->id); + $type = Dba::escape($this->type); + $rules = serialize($this->rules); + $logic_operator = $this->logic_operator; + + $sql = "INSERT INTO `search` (`name`, `type`, `user`, `rules`, `logic_operator`) VALUES ('$name', '$type', '$user', '$rules', '$logic_operator')"; + $db_results = Dba::write($sql); + $insert_id = Dba::insert_id(); + $this->id = $insert_id; + return $insert_id; + } // end save + + + /** + * to_js + * Outputs the javascript necessary to re-show the current set of + * rules. + */ + public function to_js() { + foreach ($this->rules as $rule) { + $js .= '<script type="text/javascript">' . + 'SearchRow.add("' . $rule[0] . '","' . + $rule[1] . '","' . $rule[2] . '"); </script>'; + } + return $js; + } // end to_js + + /** + * to_sql + * Call the appropriate real function + */ + public function to_sql() { + return call_user_func( + array($this, $this->searchtype . "_to_sql")); + } // end to_sql + + /** + * update + * This function updates the saved version with the current settings + */ + public function update() { + if (!$this->id) { + return false; + } + + $name = Dba::escape($this->name); + $user = Dba::escape($GLOBALS['user']->id); + $type = Dba::escape($this->type); + $rules = serialize($this->rules); + $logic_operator = $this->logic_operator; + + $sql = "UPDATE `search` SET `name`='$name', `type`='$type', `rules`='$rules', `logic_operator`='$logic_operator' WHERE `id`='" . Dba::escape($this->id) . "'"; + $db_results = Dba::write($sql); + return $db_results; + } // end update + + /** + * mangle_data + * Private convenience function. Mangles the input according to a set + * of predefined rules so that we don't have to include this logic in + * foo_to_sql. + */ + private function mangle_data($data, $type, $operator) { + if ($operator['preg_match']) { + $data = preg_replace( + $operator['preg_match'], + $operator['preg_replace'], + $data + ); + } + + if ($type == 'numeric') { + return intval($data); + } + + if ($type == 'boolean') { + return make_bool($input); + } + + return $data; + } // end mangle_data + + /** + * album_to_sql + * Handles the generation of the SQL for album searches. + */ + private function album_to_sql() { + $sql_logic_operator = $this->logic_operator; + + $where = array(); + $table = array(); + $join = array(); + + foreach ($this->rules as $rule) { + $type = $this->name_to_basetype($rule[0]); + foreach ($this->basetypes[$type] as $operator) { + if ($operator['name'] == $rule[1]) { + break; + } + } + $input = $this->mangle_data($rule[2], $type, $operator); + $sql_match_operator = $operator['sql']; + + switch ($rule[0]) { + case 'title': + $where[] = "`album`.`name` $sql_match_operator '$input'"; + break; + case 'year': + $where[] = "`album`.`year` $sql_match_operator '$input'"; + break; + case 'rating': + $where[] = " `realrating`.`rating` $sql_match_operator '$input'"; + $join['rating'] = true; + break; + case 'catalog': + $where[] = "`song`.`catalog` $sql_match_operator '$input'"; + $join['song'] = true; + break; + case 'tag': + $where[] = "`realtag`.`name` $sql_match_operator '$input'"; + $join['tag'] = true; + break; + default: + // Nae laird! + break; + } // switch on ruletype + } // foreach rule + + $where_sql = implode(" $sql_logic_operator ", $where); + + if ($join['tag']) { + $table['tag'] = "LEFT JOIN (SELECT `object_id`, `name` FROM `tag` " . + "LEFT JOIN `tag_map` ON `tag`.`id`=`tag_map`.`tag_id` " . + "WHERE `tag_map`.`object_type`='album') AS realtag " . + "ON `album`.`id`=`realtag`.`object_id`"; + } + if ($join['song']) { + $table['song'] = "LEFT JOIN `song` ON `song`.`album`=`album`.`id`"; + } + if ($join['rating']) { + $userid = $GLOBALS['user']->id; + $table['rating'] = "LEFT JOIN " . + "(SELECT `object_id`, `rating` FROM `rating` " . + "WHERE `object_type`='album' AND `user`='$userid' " . + "UNION " . + "SELECT `object_id`, FLOOR(AVG(`rating`)) AS 'rating' FROM `rating` " . + "WHERE `object_type`='album' AND " . + "`object_id` NOT IN (SELECT `object_id` FROM `rating` " . + "WHERE `object_type`='album' AND `user`='$userid') " . + "GROUP BY `object_id` " . + ") AS realrating ON `album`.`id` = `realrating`.`object_id`"; + } + + $table_sql = implode(' ', $table); + + return array( + 'base' => 'SELECT DISTINCT(`album`.`id`) FROM `album`', + 'join' => $join, + 'where' => $where, + 'where_sql' => $where_sql, + 'table' => $table, + 'table_sql' => $table_sql + ); + } // album_to_sql + + /** + * artist_to_sql + * Handles the generation of the SQL for artist searches. + */ + private function artist_to_sql() { + $sql_logic_operator = $this->logic_operator; + $where = array(); + $table = array(); + $join = array(); + + foreach ($this->rules as $rule) { + $type = $this->name_to_basetype($rule[0]); + foreach ($this->basetypes[$type] as $operator) { + if ($operator['name'] == $rule[1]) { + break; + } + } + $input = $this->mangle_data($rule[2], $type, $operator); + $sql_match_operator = $operator['sql']; + + switch ($rule[0]) { + case 'name': + $where[] = "`artist`.`name` $sql_match_operator '$input'"; + break; + case 'tag': + $where[] = " realtag`.`name` $sql_match_operator '$input'"; + $join['tag'] = true; + break; + default: + // Nihil + break; + } // switch on ruletype + } // foreach rule + + $where_sql = implode(" $sql_logic_operator ", $where); + + if ($join['tag']) { + $table['tag'] = "LEFT JOIN (SELECT `object_id`, `name` FROM `tag` " . + "LEFT JOIN `tag_map` ON `tag`.`id`=`tag_map`.`tag_id` " . + "WHERE `tag_map`.`object_type`='artist') AS realtag " . + "ON `artist`.`id`=`realtag`.`object_id`"; + } + + $table_sql = implode(' ', $table); + + return array( + 'base' => 'SELECT DISTINCT(`artist`.`id`) FROM `artist`', + 'join' => $join, + 'where' => $where, + 'where_sql' => $where_sql, + 'table' => $table, + 'table_sql' => $table_sql + ); + } // artist_to_sql + + /** + * song_to_sql + * Handles the generation of the SQL for song searches. + */ + private function song_to_sql() { + $sql_logic_operator = $this->logic_operator; + + $where = array(); + $table = array(); + $join = array(); + + foreach ($this->rules as $rule) { + $type = $this->name_to_basetype($rule[0]); + foreach ($this->basetypes[$type] as $operator) { + if ($operator['name'] == $rule[1]) { + break; + } + } + $input = $this->mangle_data($rule[2], $type, $operator); + $sql_match_operator = $operator['sql']; + + switch ($rule[0]) { + case 'anywhere': + $where[] = "(`artist`.`name` $sql_match_operator '$input' OR `album`.`name` $sql_match_operator '$input' OR `song_data`.`comment` $sql_match_operator '$input' OR `song`.`file` $sql_match_operator '$input' OR `song`.`title` $sql_match_operator '$input')"; + $join['album'] = true; + $join['artist'] = true; + $join['song_data'] = true; + break; + case 'tag': + $where[] = "`realtag`.`name` $sql_match_operator '$input'"; + $join['tag'] = true; + break; + case 'title': + $where[] = "`song`.`title` $sql_match_operator '$input'"; + break; + case 'album': + $where[] = "`album`.`name` $sql_match_operator '$input'"; + $join['album'] = true; + break; + case 'artist': + $where[] = "`artist`.`name` $sql_match_operator '$input'"; + $join['artist'] = true; + break; + case 'time': + $input = $input * 60; + $where[] = "`song`.`time` $sql_match_operator '$input'"; + break; + case 'file': + $where[] = "`song`.`file` $sql_match_operator '$input'"; + break; + case 'year': + $where[] = "`song`.`year` $sql_match_operator '$input'"; + break; + case 'comment': + $where[] = "`song_data`.`comment` $sql_match_operator '$input'"; + $join['song_data'] = true; + break; + case 'played': + $where[] = " `song`.`played` = '$input'"; + break; + case 'bitrate': + $input = $input * 1000; + $where[] = "`song`.`bitrate` $sql_match_operator '$input'"; + break; + case 'rating': + $where[] = "`realrating`.`rating` $sql_match_operator '$input'"; + $join['rating'] = true; + break; + case 'catalog': + $where[] = "`song`.`catalog` $sql_match_operator '$input'"; + break; + case 'playlist': + $join['playlist_data'] = true; + $where[] = "`playlist_data`.`playlist` $sql_match_operator '$input'"; + break; + case 'smartplaylist': + $subsearch = new Search('song', $input); + $subsql = $subsearch->to_sql(); + $where[] = "$sql_match_operator (" . $subsql['where_sql'] . ")"; + $join = array_merge($subsql['join'], $join); + break; + case 'added': + $input = strtotime($input); + $where[] = "`song`.`addition_time` $sql_match_operator $input"; + break; + case 'updated': + $input = strtotime($input); + $where[] = "`song`.`update_time` $sql_match_operator $input"; + default: + // NOSSINK! + break; + } // end switch on type + } // end foreach over rules + + $where_sql = implode(" $sql_logic_operator ", $where); + + // now that we know which things we want to JOIN... + if ($join['artist']) { + $table['artist'] = "LEFT JOIN `artist` ON `song`.`artist`=`artist`.`id`"; + } + if ($join['album']) { + $table['album'] = "LEFT JOIN `album` ON `song`.`album`=`album`.`id`"; + } + if ($join['song_data']) { + $table['song_data'] = "LEFT JOIN `song_data` ON `song`.`id`=`song_data`.`song_id`"; + } + if ($join['tag']) { + $table['tag'] = "LEFT JOIN (SELECT `object_id`, `name` FROM `tag` " . + "LEFT JOIN `tag_map` ON `tag`.`id`=`tag_map`.`tag_id` " . + "WHERE `tag_map`.`object_type`='song') AS realtag " . + "ON `song`.`id`=`realtag`.`object_id`"; + } + if ($join['rating']) { + // We do a join on ratings from the table with a + // preference for our own and fall back to the FLOORed + // average of everyone's rating if it's a song we + // haven't rated. + $userid = $GLOBALS['user']->id; + $table['rating'] = "LEFT JOIN " . + "(SELECT `object_id`, `rating` FROM `rating` " . + "WHERE `object_type`='song' AND `user`='$userid' " . + "UNION " . + "SELECT `object_id`, FLOOR(AVG(`rating`)) AS 'rating' FROM `rating` " . + "WHERE `object_type`='song' AND " . + "`object_id` NOT IN (SELECT `object_id` FROM `rating` " . + "WHERE `object_type`='song' AND `user`='$userid') " . + "GROUP BY `object_id` " . + ") AS realrating ON `song`.`id`=`realrating`.`object_id`"; + } + if ($join['playlist_data']) { + $table['playlist_data'] = "LEFT JOIN `playlist_data` ON `song`.`id`=`playlist_data`.`object_id` AND `playlist_data`.`object_type`='song'"; + } + + $table_sql = implode(' ', $table); + + return array( + 'base' => 'SELECT DISTINCT(`song`.`id`) FROM `song`', + 'join' => $join, + 'where' => $where, + 'where_sql' => $where_sql, + 'table' => $table, + 'table_sql' => $table_sql + ); + } // end song_to_sql + + /** + * video_to_sql + * Handles the generation of the SQL for video searches. + */ + private function video_to_sql() { + $sql_logic_operator = $this->logic_operator; + + $where = array(); + + + foreach ($this->rules as $rule) { + $type = $this->name_to_basetype($rule[0]); + foreach ($this->basetypes[$type] as $operator) { + if ($operator['name'] == $rule[1]) { + break; + } + } + $input = $this->mangle_data($rule[2], $type, $operator); + $sql_match_operator = $operator['sql']; + + switch ($rule[0]) { + case 'filename': + $where[] = "`video`.`file` $sql_match_operator '$input'"; + break; + default: + // WE WILLNA BE FOOLED AGAIN! + } // switch on ruletype + } // foreach rule + + $where_sql = explode(" $sql_logic_operator ", $where); + + return array( + 'base' => 'SELECT DISTINCT(`video`.`id`) FROM `video`', + 'where' => $where, + 'where_sql' => $where_sql + ); + } // end video_to_sql + +} // end of Search class +?> diff --git a/lib/class/update.class.php b/lib/class/update.class.php index 0dc1f726..14478de0 100644 --- a/lib/class/update.class.php +++ b/lib/class/update.class.php @@ -371,6 +371,9 @@ class Update { $update_string = '- Modify tmp_browse to allow caching of multiple browses per session.<br />'; $version[] = array('version' => '360005','description' => $update_string); + $update_string = '- Add table for dynamic playlists.<br />'; + $version[] = array('version' => '360006','description' => $update_string); + return $version; } // populate_version @@ -1979,5 +1982,24 @@ class Update { self::set_version('db_version','360005'); } // update_360005 + /** + * update_360006 + * This adds the table for newsearch/dynamic playlists + */ + public static function update_360006() { + $sql = "CREATE TABLE `search` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `user` int(11) NOT NULL, + `type` enum('private','public') CHARACTER SET utf8 DEFAULT NULL, + `rules` mediumtext COLLATE utf8_unicode_ci NOT NULL, + `name` varchar(255) CHARACTER SET utf8 DEFAULT NULL, + `logic_operator` varchar(3) CHARACTER SET utf8 DEFAULT NULL, + PRIMARY KEY (`id`) + ) ENGINE=MyISAM AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci"; + $db_results = Dba::write($sql); + + self::set_version('db_version','360006'); + } + } // end update class ?> diff --git a/lib/init.php b/lib/init.php index d492dc8b..d43c3fc2 100644 --- a/lib/init.php +++ b/lib/init.php @@ -134,7 +134,6 @@ $results['mysql_db'] = $results['database_name']; define('INIT_LOADED','1'); // Library and module includes we can't do with the autoloader -require_once $prefix . '/lib/search.php'; require_once $prefix . '/lib/preferences.php'; require_once $prefix . '/lib/log.lib.php'; require_once $prefix . '/lib/ui.lib.php'; @@ -143,6 +142,7 @@ require_once $prefix . '/lib/batch.lib.php'; require_once $prefix . '/lib/themes.php'; require_once $prefix . '/lib/class/localplay.abstract.php'; require_once $prefix . '/lib/class/database_object.abstract.php'; +require_once $prefix . '/lib/class/playlist_object.abstract.php'; require_once $prefix . '/lib/class/media.interface.php'; require_once $prefix . '/modules/getid3/getid3.php'; require_once $prefix . '/modules/nusoap/nusoap.php'; diff --git a/lib/javascript/search-data.php b/lib/javascript/search-data.php new file mode 100644 index 00000000..11ef68d9 --- /dev/null +++ b/lib/javascript/search-data.php @@ -0,0 +1,49 @@ +<?php +/* vim:set tabstop=8 softtabstop=8 shiftwidth=8 noexpandtab: */ +/** + +Copyright (c) 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 v2 + as published by the Free Software Foundation. + + 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. + +*/ +require_once '../init.php'; + +function arrayToJSON($array) { + $json = '{ '; + foreach ($array as $key => $value) { + $json .= '"' . $key . '" : '; + if (is_array($value)) { + $json .= arrayToJSON($value); + } + else { + $json .= '"' . $value . '"'; + } + $json .= ' , '; + } + $json = rtrim($json, ', '); + return $json . ' }'; +} + +Header('content-type: application/x-javascript'); + +$search = new Search($_REQUEST['type']); + +echo 'var types = $H(\''; +echo arrayToJSON($search->types) . "'.evalJSON());\n"; +echo 'var basetypes = $H(\''; +echo arrayToJSON($search->basetypes) . "'.evalJSON());\n"; +echo 'removeIcon = \'<a href="javascript: void(0)">' . get_user_icon('disable', _('Remove')) . '</a>\';'; +?> diff --git a/lib/javascript/search.js b/lib/javascript/search.js new file mode 100644 index 00000000..35995001 --- /dev/null +++ b/lib/javascript/search.js @@ -0,0 +1,168 @@ +// vim:set tabstop=8 softtabstop=8 shiftwidth=8 noexpandtab: +// +// Copyright (c) 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 v2 +// as published by the Free Software Foundation. +// +// +// 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. + +var rowIter = 1; +var rowCount = 0; + +var SearchRow = { + add: function(ruleType, operator, input) { + if (typeof(ruleType) != 'string') { + ruleType = 0; + } + else { + types.each(function(i) { + if (i.value.name == ruleType) { + ruleType = i.key; + throw $break; + } + }); + } + + if (typeof(operator) != 'string') { + operator = 0; + } + else { + $H(basetypes.get(types.get(ruleType).type)).each(function(i) { + if (i.value.name == operator) { + operator = i.key; + throw $break; + } + }); + } + + var row = document.createElement('tr'); + var cells = new Array(); + for (var i = 0 ; i < 5 ; i++) { + cells[i] = document.createElement('td'); + } + + cells[0].appendChild(SearchRow.constructOptions(ruleType, rowIter)); + cells[1].appendChild(SearchRow.constructOperators(ruleType, rowIter, operator)); + cells[2].appendChild(SearchRow.constructInput(ruleType, rowIter, input)); + cells[3].innerHTML = removeIcon; + + cells.each(function(i) { + row.appendChild(i); + }); + + $('searchtable').appendChild(row); + rowCount++; + + Event.observe(cells[3], 'click', function(e){if(rowCount > 1) { Element.remove(this.parentNode); rowCount--; }}); + + rowIter++; + }, + constructInput: function(ruleType, ruleNumber, input) { + if (input === null || input === undefined) { + input = ''; + } + + widget = $H(types.get(ruleType).widget); + + var inputNode = document.createElement(widget.get('0')); + inputNode.id = 'rule_' + ruleNumber + '_input'; + inputNode.name = 'rule_' + ruleNumber + '_input'; + + switch(widget.get('0')) { + case 'input': + inputNode.setAttribute('type', widget.get('1')); + inputNode.setAttribute('value', input); + break; + case 'select': + $H(widget.get('1')).each(function(i) { + var option = document.createElement('option'); + if ( isNaN(parseInt(i.value)) ) { + realvalue = i.key; + } + else { + realvalue = parseInt(i.value); + } + if ( input == realvalue ) { + option.selected = true; + } + option.value = realvalue; + option.innerHTML = i.value; + inputNode.appendChild(option); + }); + break; + } + + return inputNode; + }, + constructOptions: function(ruleType, ruleNumber) { + var optionsNode = document.createElement('select'); + optionsNode.id = 'rule_' + ruleNumber; + optionsNode.name = 'rule_' + ruleNumber; + + types.each(function(i) { + var option = document.createElement('option'); + option.innerHTML = i.value.label; + option.value = i.value.name; + if ( i.key == ruleType ) { + option.selected = true; + } + optionsNode.appendChild(option); + }); + + Event.observe(optionsNode, 'change', SearchRow.update); + + return optionsNode; + }, + constructOperators: function(ruleType, ruleNumber, operator) { + var operatorNode = document.createElement('select'); + operatorNode.id = 'rule_' + ruleNumber + '_operator'; + operatorNode.name = 'rule_' + ruleNumber + '_operator'; + + basetype = types.get(ruleType).type; + operatorNode.className = 'operator' + basetype; + + $H(basetypes.get(basetype)).each(function(i) { + var option = document.createElement('option'); + option.innerHTML = i.value.description; + option.value = i.key; + if (i.key == operator) { + option.selected = true; + } + operatorNode.appendChild(option); + }); + + return operatorNode; + }, + update: function() { + var r_findID = /rule_(\d+)/; + var targetID = r_findID.exec(this.id)[1]; + + var operator = $('rule_' + targetID + '_operator'); + if (operator.className != 'operator' + types.get(this.selectedIndex).type) { + var operator_cell = operator.parentNode; + Element.remove(operator); + operator_cell.appendChild(SearchRow.constructOperators(this.selectedIndex, targetID)); + } + + var input = $('rule_' + targetID + '_input'); + + if (input.type == 'text') { + var oldinput = input.value; + } + + var input_cell = input.parentNode; + Element.remove(input); + input_cell.appendChild(SearchRow.constructInput(this.selectedIndex, targetID, oldinput)); + } +}; diff --git a/lib/search.php b/lib/search.php deleted file mode 100644 index 992b01d2..00000000 --- a/lib/search.php +++ /dev/null @@ -1,294 +0,0 @@ -<?php -/* vim:set tabstop=8 softtabstop=8 shiftwidth=8 noexpandtab: */ -/** - * Search Library - * - * This library handles all the searching! - * - * PHP version 5 - * - * LICENSE: GNU General Public License, version 2 (GPLv2) - * Copyright (c) 2001 - 2011 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 v2 - * as published by the Free Software Foundation. - * - * 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. - * - * @category Search - * @package Library - * @author Karl Vollmer <vollmer@ampache.org> - * @copyright 2001 - 2011 Ampache.org - * @license http://opensource.org/licenses/gpl-2.0 GPLv2 - * @version PHP 5.2 - * @link http://www.ampache.org/ - * @since File available since Release 1.0 - */ - -/** - * run_search - * this function actually runs the search, and returns an array of the results. Unlike the previous - * function it does not do the display work its self. - */ -function run_search($data) { - - /* Create an array of the object we need to search on */ - foreach ($data as $key=>$value) { - /* Get the first two chars to check - * and see if it's s_ - */ - $prefix = substr($key,0,2); - $value = trim($value); - - if ($prefix == 's_' AND strlen($value)) { - $true_name = substr($key,2,strlen($key)); - $search[$true_name] = Dba::escape($value); - } - - } // end foreach - - /* Figure out if they want a AND based search or a OR based search */ - switch($_REQUEST['operator']) { - case 'or': - $operator = 'OR'; - break; - default: - $operator = 'AND'; - break; - } // end switch on operator - - /* Figure out what type of method they would like to use, exact or fuzzy */ - switch($_REQUEST['method']) { - case 'fuzzy': - $method = "LIKE '%__%'"; - break; - default: - $method = "= '__'"; - break; - } // end switch on method - - $limit = intval($_REQUEST['limit']); - - /* Switch, and run the correct function */ - switch($_REQUEST['object_type']) { - case 'artist': - case 'album': - case 'song': - $function_name = 'search_' . $_REQUEST['object_type']; - if (function_exists($function_name)) { - $results = call_user_func($function_name,$search,$operator,$method,$limit); - return $results; - } - break; - default: - $results = search_song($search,$operator,$method,$limit); - return $results; - break; - } // end switch - - return array(); - -} // run_search - -/** - * search_song - * This function deals specificly with returning song object for the run_search - * function, it assumes that our root table is songs - * @package Search - * @catagory Search - */ -function search_song($data,$operator,$method,$limit) { - - /* Generate BASE SQL */ - - $where_sql = ''; - $table_sql = ''; - $group_sql = ' GROUP BY'; - $select_sql = ','; - $field_sql = ''; - $order_sql = ''; - - if ($limit > 0) { - $limit_sql = " LIMIT $limit"; - } - - foreach ($data as $type=>$value) { - - /* Create correct Value statement based on method */ - - $value_string = str_replace("__",$value,$method); - - switch ($type) { - case 'all': - $additional_soundex = false; - - if (!(strpos($value, '-'))) // if we want a fuzzier search - $additional_soundex = true; - - $where_sql = "( MATCH (`artist2`.`name`, `album2`.`name`, `song`.`title`) AGAINST ('$value' IN BOOLEAN MODE)"; - - if ($additional_soundex) { - $where_sql.= " OR `artist2`.`name` SOUNDS LIKE '$value'"; - $where_sql.= " OR `album2`.`name` SOUNDS LIKE '$value'"; - $where_sql.= " OR `song`.`title` SOUNDS LIKE '$value' "; - } - $where_sql .= ") $operator"; - - $table_sql = " LEFT JOIN `album` as `album2` ON `song`.`album`=`album2`.`id`"; - $table_sql.= " LEFT JOIN `artist` AS `artist2` ON `song`.`artist`=`artist2`.`id`"; - - $order_sql = " ORDER BY"; - - $order_sql.= " MATCH (`artist2`.`name`) AGAINST ('$value' IN BOOLEAN MODE)"; - if ($additional_soundex) $order_sql.= " + (SOUNDEX(`artist2`.`name`)=SOUNDEX('$value')) DESC,"; else $order_sql.= " DESC,"; - - $order_sql.= " MATCH (`album2`.`name`) AGAINST ('$value' IN BOOLEAN MODE)"; - if ($additional_soundex) $order_sql.= " + (SOUNDEX(`album2`.`name`)=SOUNDEX('$value')) DESC,"; else $order_sql.= " DESC,"; - - $order_sql.= " MATCH (`song`.`title`) AGAINST ('$value' IN BOOLEAN MODE)"; - if ($additional_soundex) $order_sql.= " + (SOUNDEX(`song`.`title`)=SOUNDEX('$value')) DESC,"; else $order_sql.= " DESC,"; - - $order_sql.= " `artist2`.`name`,"; - $order_sql.= " `album2`.`name`,"; - $order_sql.= " `song`.`track`,"; - $order_sql.= " `song`.`title`"; - break; - case 'title': - $where_sql .= " `song`.`title` $value_string $operator"; - break; - case 'album': - $where_sql .= " `album`.`name` $value_string $operator"; - $table_sql .= " LEFT JOIN `album` ON `song`.`album`=`album`.`id`"; - break; - case 'artist': - $where_sql .= " `artist`.`name` $value_string $operator"; - $table_sql .= " LEFT JOIN `artist` ON `song`.`artist`=`artist`.`id` "; - break; - case 'year': - if (empty($data["year2"]) && is_numeric($data["year"])) { - $where_sql .= " `song`.`year` $value_string $operator"; - } - elseif (!empty($data["year"]) && is_numeric($data["year"]) && !empty($data["year2"]) && is_numeric($data["year2"])) { - $where_sql .= " (`song`.`year` BETWEEN ".$data["year"]." AND ".$data["year2"].") $operator"; - } - break; - case 'time': - if (!empty($data['time2'])) { - $where_sql .= " `song`.`time` <= " . Dba::escape(intval($data['time2'])*60) . " $operator"; - } - if (!empty($data['time'])) { - $where_sql .= " `song`.`time` >= " . Dba::escape(intval($data['time'])*60) . " $operator"; - } - break; - case 'filename': - $where_sql .= " `song`.`file` $value_string $operator"; - break; - case 'comment': - $table_sql .= ' INNER JOIN `song_data` ON `song`.`id`=`song_data`.`song_id`'; - $where_sql .= " `song_data`.`comment` $value_string $operator"; - break; - case 'played': - /* This is a 0/1 value so bool it */ - $value = make_bool($value); - $where_sql .= " `song`.`played` = '$value' $operator"; - break; - case 'minbitrate': - $value = intval($value); - $where_sql .= " `song`.`bitrate` >= ('$value'*1000) $operator"; - break; - case 'rating': - $value = intval($value); - $userid = $GLOBALS['user']->id; - $rcomparison = '>='; - if ($_REQUEST['s_rating_operator'] == '1') { - $rcomparison = '<='; - } - elseif ($_REQUEST['s_rating_operator'] == '2') { - $rcomparison = '<=>'; - } - // Complex SQL follows - // We do a join on ratings from the table with a - // preference for our own and fall back to the - // FLOORed average of everyone's rating if it's - // a song we haven't rated. - if ($operator == 'AND') { - $table_sql .= ' INNER JOIN'; - } - else { - $table_sql .= ' LEFT JOIN'; - } - $table_sql .= " (SELECT `object_id`, `rating` FROM `rating` WHERE `object_type`='song' AND `user`='$userid' - UNION - SELECT `object_id`, FLOOR(AVG(`rating`)) AS 'rating' FROM `rating` - WHERE `object_type`='song' AND - `object_id` NOT IN (SELECT `object_id` FROM `rating` WHERE `object_type`='song' AND `user`='$userid') - GROUP BY `object_id` - ) AS realrating ON `song`.`id` = `realrating`.`object_id`"; - - $where_sql .= " `realrating`.`rating` $rcomparison '$value' $operator"; - break; - case 'tag': - - // Fill it with one value to prevent sql error on no results - $ids = array('0'); - - $tag_sql = "SELECT `object_id` FROM `tag` LEFT JOIN `tag_map` ON `tag`.`id`=`tag_map`.`tag_id` " . - "WHERE `tag_map`.`object_type`='song' AND `tag`.`name` $value_string "; - $db_results = Dba::read($tag_sql); - - while ($row = Dba::fetch_assoc($db_results)) { - $ids[] = $row['object_id']; - } - - $where_sql = " `song`.`id` IN (" . implode(',',$ids) . ") $operator"; - - break; - default: - // Notzing! - break; - } // end switch on type - - - } // foreach data - - /* Trim off the extra $method's and ,'s then combine the sucka! */ - $where_sql = rtrim($where_sql,$operator); - $group_sql = rtrim($group_sql,','); - $select_sql = rtrim($select_sql,','); - - if ($group_sql == ' GROUP BY') { $group_sql = ''; } - - $base_sql = "SELECT DISTINCT(`song`.`id`) $field_sql $select_sql FROM `song`"; - - $sql = $base_sql . $table_sql . " WHERE " . $where_sql . $group_sql . $order_sql . $limit_sql; - - /** - * Because we might need this for Dynamic Playlist Action - * but we don't trust users to provide this store it in the - * session where they can't get to it! - */ - - $_SESSION['userdata']['stored_search'] = $sql; - - $db_results = Dba::read($sql); - - $results = array(); - - while ($row = Dba::fetch_assoc($db_results)) { - $results[] = $row['id']; - } - - return $results; - -} // search_songs - - -?> @@ -37,18 +37,15 @@ show_header(); switch ($_REQUEST['action']) { case 'get_advanced': - $object_ids = Random::advanced($_POST); + $object_ids = Random::advanced($_REQUEST['type'], $_POST); // We need to add them to the active playlist foreach ($object_ids as $object_id) { - $GLOBALS['user']->playlist->add_object($object_id,'song'); + $GLOBALS['user']->playlist->add_object($object_id, 'song'); } - case 'advanced': default: require_once Config::get('prefix') . '/templates/show_random.inc.php'; -/* require_once Config::get('prefix') . '/templates/show_random_rules.inc.php';*/ - break; } // end switch @@ -39,24 +39,12 @@ show_header(); * action switch */ switch ($_REQUEST['action']) { - case 'quick_search': - /* This needs to be done because we don't know what thing - * they used the quick search to search on until after they've - * submited it - */ - $_REQUEST['s_all'] = $_REQUEST['search_string']; - - if (strlen($_REQUEST['search_string']) < 1) { - Error::add('keyword',_('Error: No Keyword Entered')); - require_once Config::get('prefix') . '/templates/show_search.inc.php'; - break; - } case 'search': $browse = new Browse(); require_once Config::get('prefix') . '/templates/show_search.inc.php'; require_once Config::get('prefix') . '/templates/show_search_options.inc.php'; - $results = run_search($_REQUEST); - $browse->set_type('song'); + $results = Search::run($_REQUEST); + $browse->set_type($_REQUEST['type']); $browse->show_objects($results); $browse->store(); break; @@ -65,6 +53,10 @@ switch ($_REQUEST['action']) { $playlist = new Playlist($playlist_id); show_confirmation(_('Search Saved'),sprintf(_('Your Search has been saved as a track in %s'), $playlist->name),conf('web_path') . "/search.php"); break; + case 'save_as_smartplaylist': + $playlist = new Search(); + $playlist->parse_rules(Search::clean_request($_REQUEST)); + $playlist->save(); default: require_once Config::get('prefix') . '/templates/show_search.inc.php'; break; diff --git a/server/browse.ajax.php b/server/browse.ajax.php index 60d3cb8d..f24511b0 100644 --- a/server/browse.ajax.php +++ b/server/browse.ajax.php @@ -99,6 +99,12 @@ switch ($_REQUEST['action']) { $playlist->delete(); $key = 'playlist_row_' . $playlist->id; break; + case 'smartplaylist': + $playlist = new Search('song', $_REQUEST['id']); + if (!$playlist->has_access()) { exit; } + $playlist->delete(); + $key = 'playlist_row_' . $playlist->id; + break; case 'live_stream': if (!$GLOBALS['user']->has_access('75')) { exit; } $radio = new Radio($_REQUEST['id']); diff --git a/smartplaylist.php b/smartplaylist.php new file mode 100644 index 00000000..fa243ea3 --- /dev/null +++ b/smartplaylist.php @@ -0,0 +1,103 @@ +<?php +/* vim:set tabstop=8 softtabstop=8 shiftwidth=8 noexpandtab: */ +/* + + Copyright (c) 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; version 2 + of the License. + + 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. + +*/ + +require_once 'lib/init.php'; + +// We special-case this so we can send a 302 if the delete succeeded +if ($_REQUEST['action'] == 'delete_playlist') { + // Check rights + $playlist = new Search('song', $_REQUEST['playlist_id']); + if ($playlist->has_access()) { + $playlist->delete(); + // Go elsewhere + header('Location: ' . Config::get('web_path') . '/browse.php?action=smartplaylist'); + } +} + +show_header(); + +/* Switch on the action passed in */ +switch ($_REQUEST['action']) { + case 'create_playlist': + /* Check rights */ + if (!Access::check('interface','25')) { + access_denied(); + break; + } + + foreach ($_REQUEST as $key => $value) { + $prefix = substr($key, 0, 4); + $value = trim($value); + + if ($prefix == 'rule' && strlen($value)) { + $rules[$key] = Dba::escape($value); + } + } + + switch($_REQUEST['operator']) { + case 'or': + $operator = 'OR'; + break; + default: + $operator = 'AND'; + break; + } // end switch on operator + + $playlist_name = scrub_in($_REQUEST['playlist_name']); + + $playlist = new Search('song'); + $playlist->parse_rules($data); + $playlist->logic_operator = $operator; + $playlist->name = $playlist_name; + $playlist->save(); + + break; + case 'delete_playlist': + // If we made it here, we didn't have sufficient rights. + access_denied(); + break; + case 'show_playlist': + $playlist = new Search('song', $_REQUEST['playlist_id']); + $playlist->format(); + require_once Config::get('prefix') . '/templates/show_smartplaylist.inc.php'; + break; + case 'update_playlist': + $playlist = new Search('song', $_REQUEST['playlist_id']); + if ($playlist->has_access()) { + $playlist->parse_rules(Search::clean_request($_REQUEST)); + $playlist->update(); + $playlist->format(); + } + else { + access_denied(); + break; + } + require_once Config::get('prefix') . '/templates/show_smartplaylist.inc.php'; + break; + default: + require_once Config::get('prefix') . '/templates/show_smartplaylist.inc.php'; + break; +} // switch on the action + +show_footer(); +?> diff --git a/templates/show_edit_smartplaylist_row.inc.php b/templates/show_edit_smartplaylist_row.inc.php new file mode 100644 index 00000000..fadd1bc7 --- /dev/null +++ b/templates/show_edit_smartplaylist_row.inc.php @@ -0,0 +1,45 @@ +<?php +/* vim:set tabstop=8 softtabstop=8 shiftwidth=8 noexpandtab: */ +/* + + Copyright (c) 2001 - 2007 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 v2 + as published by the Free Software Foundation. + + 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. + +*/ +?> +<td colspan="6"> +<form method="post" id="edit_playlist_<?php echo $playlist->id; ?>" action="javascript:void(0);"> +<table cellpadding="0" cellspacing="0"> +<tr> + <td> + <input type="text" name="name" size="25" value="<?php echo scrub_out($playlist->name); ?>" /> + </td> + <td> + <?php $name = 'select_' . $playlist->type; ${$name} = ' selected="selected"'; ?> + <select name="pl_type"> + <option value="public"<?php echo $select_public; ?>><?php echo _('Public'); ?></option> + <option value="private"<?php echo $select_private; ?>><?php echo _('Private'); ?></option> + </select> + <td> + <input type="hidden" name="id" value="<?php echo $playlist->id; ?>" /> + <input type="hidden" name="type" value="smartplaylist_row" /> + <?php echo Ajax::button('?action=edit_object&id=' . $playlist->id . '&type=smartplaylist_row','download',_('Save Changes'),'save_playlist_' . $playlist->id,'edit_playlist_' . $playlist->id); ?> + </td> +</tr> +</table> +</form> +</td> + diff --git a/templates/show_edit_smartplaylist_title.inc.php b/templates/show_edit_smartplaylist_title.inc.php new file mode 100644 index 00000000..e6451e66 --- /dev/null +++ b/templates/show_edit_smartplaylist_title.inc.php @@ -0,0 +1,43 @@ +<?php +/* vim:set tabstop=8 softtabstop=8 shiftwidth=8 noexpandtab: */ +/* + + Copyright (c) 2001 - 2007 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 v2 + as published by the Free Software Foundation. + + 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. + +*/ +?> +<form method="post" id="edit_playlist_<?php echo $playlist->id; ?>" action="javascript:void(0);"> +<table cellpadding="0" cellspacing="0"> +<tr> + <td> + <input type="text" name="name" size="25" value="<?php echo scrub_out($playlist->name); ?>" /> + </td> + <td> + <?php $name = 'select_' . $playlist->type; ${$name} = ' selected="selected"'; ?> + <select name="pl_type"> + <option value="public"<?php echo $select_public; ?>><?php echo _('Public'); ?></option> + <option value="private"<?php echo $select_private; ?>><?php echo _('Private'); ?></option> + </select> + <td> + <input type="hidden" name="id" value="<?php echo $playlist->id; ?>" /> + <input type="hidden" name="type" value="smartplaylist_title" /> + <?php echo Ajax::button('?action=edit_object&id=' . $playlist->id . '&type=smartplaylist_title','download',_('Save Changes'),'save_playlist_' . $playlist->id,'edit_playlist_' . $playlist->id); ?> + </td> +</tr> +</table> +</form> + diff --git a/templates/show_random.inc.php b/templates/show_random.inc.php index 65815e5e..b1287ee8 100644 --- a/templates/show_random.inc.php +++ b/templates/show_random.inc.php @@ -33,80 +33,70 @@ ?> <?php show_box_top(_('Play Random Selection')); ?> -<form id="random" method="post" enctype="multipart/form-data" action="<?php echo Config::get('web_path'); ?>/random.php?action=get_advanced"> -<table class="table-data" cellspacing="0" cellpadding="3"> +<form id="random" method="post" enctype="multipart/form-data" action="<?php echo Config::get('web_path'); ?>/random.php?action=get_advanced&type=<?php echo $_REQUEST['type'] ? scrub_out($_REQUEST['type']) : 'song'; ?>"> +<table class="tabledata" cellpadding="3" cellspacing="0"> <tr> - <td><?php echo _('Item count'); ?></td> - <td> - <?php $name = 'random_' . scrub_in($_POST['random']); ${$name} = ' selected="selected"'; ?> - <select name="random"> - <option value="1"<?php echo $random_1; ?>>1</option> - <option value="5"<?php echo $random_5; ?>>5</option> - <option value="10"<?php echo $random_10; ?>>10</option> - <option value="20"<?php echo $random_20; ?>>20</option> - <option value="30"<?php echo $random_30; ?>>30</option> - <option value="50"<?php echo $random_50; ?>>50</option> - <option value="100"<?php echo $random_100; ?>>100</option> - <option value="500"<?php echo $random_500; ?>>500</option> - <option value="1000"<?php echo $random_1000; ?>>1000</option> - <option value="-1" ><?php echo _('All'); ?></option> - </select> - </td> -</tr> -<tr> - <td><?php echo _('Length'); ?></td> - <td> - <?php $name = 'length_' . intval($_POST['length']); ${$name} = ' selected="selected"'; ?> - <select name="length"> - <option value="0"<?php echo $length_0; ?>><?php echo _('Unlimited'); ?></option> - <option value="15"<?php echo $length_15; ?>><?php printf(ngettext('%d minute','%d minutes',15), "15"); ?></option> - <option value="30"<?php echo $length_30; ?>><?php printf(ngettext('%d minute','%d minutes',30), "30"); ?></option> - <option value="60"<?php echo $length_60; ?>><?php printf(ngettext('%d hour','%d hours',1), "1"); ?></option> - <option value="120"<?php echo $length_120; ?>><?php printf(ngettext('%d hour','%d hours',2), "2"); ?></option> - <option value="240"<?php echo $length_240; ?>><?php printf(ngettext('%d hour','%d hours',4), "4"); ?></option> - <option value="480"<?php echo $length_480; ?>><?php printf(ngettext('%d hour','%d hours',8), "8"); ?></option> - <option value="960"<?php echo $length_960; ?>><?php printf(ngettext('%d hour','%d hours',16), "16"); ?></option> - </select> - </td> + <td><?php if ($_REQUEST['type'] != 'song') { ?><a href="<?php echo Config::get('web_path'); ?>/random.php?action=advanced&type=song"><?php echo _('Songs'); ?></a><?php } else { echo _('Songs'); } ?></td> + <td><?php if ($_REQUEST['type'] != 'album') { ?><a href="<?php echo Config::get('web_path'); ?>/random.php?action=advanced&type=album"><?php echo _('Albums'); ?></a><?php } else { echo _('Albums'); } ?></td> + <td><?php if ($_REQUEST['type'] != 'artist') { ?><a href="<?php echo Config::get('web_path'); ?>/random.php?action=advanced&type=artist"><?php echo _('Artists'); ?></a><?php } else { echo _('Artists'); } ?></td> </tr> +<tr><td> </td></tr> +</table> +<table class="tabledata" cellpadding="0" cellspacing="0"> <tr> - <td><?php echo _('Type'); ?></td> - <td> - <?php $name = 'type_' . scrub_in($_POST['random_type']); ${$name} = ' selected="selected"'; ?> - <select name="random_type"> - <option value="normal"<?php echo $type_normal; ?>><?php echo _('Standard'); ?></option> - <option value="unplayed"<?php echo $type_unplayed; ?>><?php echo _('Less Played'); ?></option> - <option value="full_album"<?php echo $type_full_album; ?>><?php echo _('Full Albums'); ?></option> - <option value="full_artist"<?php echo $type_full_artist; ?>><?php echo _('Full Artist'); ?></option> - <?php if (Config::get('ratings')) { ?> - <option value="high_rating"<?php echo $type_high_rating; ?>><?php echo _('Highest Rated'); ?></option> - <?php } ?> - </select> - </td> + <td><?php echo _('Item count'); ?></td> + <td> + <?php $name = 'random_' . scrub_in($_POST['random']); ${$name} = ' selected="selected"'; ?> + <select name="random"> + <option value="1"<?php echo $random_1; ?>>1</option> + <option value="5"<?php echo $random_5; ?>>5</option> + <option value="10"<?php echo $random_10; ?>>10</option> + <option value="20"<?php echo $random_20; ?>>20</option> + <option value="30"<?php echo $random_30; ?>>30</option> + <option value="50"<?php echo $random_50; ?>>50</option> + <option value="100"<?php echo $random_100; ?>>100</option> + <option value="500"<?php echo $random_500; ?>>500</option> + <option value="1000"<?php echo $random_1000; ?>>1000</option> + <option value="-1" ><?php echo _('All'); ?></option> + </select> + </td> </tr> <tr> - <td nowrap="nowrap"><?php echo _('From catalog'); ?></td> - <td> - <?php show_catalog_select('catalog','',$_POST['catalog']); ?> - </td> + <td><?php echo _('Length'); ?></td> + <td> + <?php $name = 'length_' . intval($_POST['length']); ${$name} = ' selected="selected"'; ?> + <select name="length"> + <option value="0"<?php echo $length_0; ?>><?php echo _('Unlimited'); ?></option> + <option value="15"<?php echo $length_15; ?>><?php printf(ngettext('%d minute','%d minutes',15), "15"); ?></option> + <option value="30"<?php echo $length_30; ?>><?php printf(ngettext('%d minute','%d minutes',30), "30"); ?></option> + <option value="60"<?php echo $length_60; ?>><?php printf(ngettext('%d hour','%d hours',1), "1"); ?></option> + <option value="120"<?php echo $length_120; ?>><?php printf(ngettext('%d hour','%d hours',2), "2"); ?></option> + <option value="240"<?php echo $length_240; ?>><?php printf(ngettext('%d hour','%d hours',4), "4"); ?></option> + <option value="480"<?php echo $length_480; ?>><?php printf(ngettext('%d hour','%d hours',8), "8"); ?></option> + <option value="960"<?php echo $length_960; ?>><?php printf(ngettext('%d hour','%d hours',16), "16"); ?></option> + </select> + </td> </tr> <tr> - <td><?php echo _('Size Limit'); ?></td> - <td> - <?php $name = 'size_' . intval($_POST['size_limit']); ${$name} = ' selected="selected"'; ?> - <select name="size_limit"> - <option value="0"<?php echo $size_0; ?>><?php echo _('Unlimited'); ?></option> - <option value="64"<?php echo $size_64; ?>>64MB</option> - <option value="128"<?php echo $size_128; ?>>128MB</option> - <option value="256"<?php echo $size_256; ?>>256MB</option> - <option value="512"<?php echo $size_512; ?>>512MB</option> - <option value="1024"<?php echo $size_1024; ?>>1024MB</option> - </select> - </td> + <td><?php echo _('Size Limit'); ?></td> + <td> + <?php $name = 'size_' . intval($_POST['size_limit']); ${$name} = ' selected="selected"'; ?> + <select name="size_limit"> + <option value="0"<?php echo $size_0; ?>><?php echo _('Unlimited'); ?></option> + <option value="64"<?php echo $size_64; ?>>64MB</option> + <option value="128"<?php echo $size_128; ?>>128MB</option> + <option value="256"<?php echo $size_256; ?>>256MB</option> + <option value="512"<?php echo $size_512; ?>>512MB</option> + <option value="1024"<?php echo $size_1024; ?>>1024MB</option> + </select> + </td> </tr> </table> + +<?php require Config::get('prefix') . '/templates/show_rules.inc.php'; ?> + <div class="formValidation"> - <input type="submit" value="<?php echo _('Enqueue'); ?>" /> + <input type="submit" value="<?php echo _('Enqueue'); ?>" /> </div> </form> <?php show_box_bottom(); ?> diff --git a/templates/show_random_rules.inc.php b/templates/show_random_rules.inc.php deleted file mode 100644 index 45be357e..00000000 --- a/templates/show_random_rules.inc.php +++ /dev/null @@ -1,59 +0,0 @@ -<?php -/* vim:set tabstop=8 softtabstop=8 shiftwidth=8 noexpandtab: */ -/** - * Show Random Rules - * - * PHP version 5 - * - * LICENSE: GNU General Public License, version 2 (GPLv2) - * Copyright (c) 2001 - 2011 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 v2 - * as published by the Free Software Foundation. - * - * 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. - * - * @category Template - * @package Template - * @author Karl Vollmer <vollmer@ampache.org> - * @copyright 2001 - 2011 Ampache.org - * @license http://opensource.org/licenses/gpl-2.0 GPLv2 - * @version PHP 5.2 - * @link http://www.ampache.org/ - * @since File available since Release 1.0 - */ - -?> -<?php show_box_top(_('Rules')); ?> -<table class="tabledata" cellpadding="0" cellspacing="0"> -<colgroup> - <col id="col_field" /> - <col id="col_operator" /> - <col id="col_value" /> - <col id="col_method" /> - <col id="col_action" /> -</colgroup> -<tr class="th-top"> - <th class="col_field"><?php echo _('Field'); ?></th> - <th class="col_operator"><?php echo _('Operator'); ?></th> - <th class="col_value"><?php echo _('Value'); ?></th> - <th class="col_method"><?php echo _('Method'); ?></th> - <th class="col_action"><?php echo _('Action'); ?></th> -</tr> -<tr> - <td></td> - <td></td> - <td></td> - <td></td> - <td></td> -</tr> -</table> -<?php show_box_bottom(); ?> diff --git a/templates/show_rules.inc.php b/templates/show_rules.inc.php new file mode 100644 index 00000000..1f98e0ae --- /dev/null +++ b/templates/show_rules.inc.php @@ -0,0 +1,67 @@ +<?php +/* vim:set tabstop=8 softtabstop=8 shiftwidth=8 noexpandtab: */ +/* + + Copyright (c) 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 v2 + as published by the Free Software Foundation. + + 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. + +*/ +?> + +<script type="text/javascript" src="<?php echo Config::get('web_path'); ?>/lib/javascript/search.js"></script> +<script type="text/javascript" src="<?php echo Config::get('web_path'); ?>/lib/javascript/search-data.php?type=<?php echo $_REQUEST['type'] ? scrub_out($_REQUEST['type']) : 'song'; ?>"></script> + +<?php show_box_top(_('Rules') . "..."); ?> +<table class="tabledata" cellpadding="3" cellspacing="0"> +<tbody id="searchtable"> + <tr> + <td><?php echo _('Match'); ?></td> + <td> + <select name="operator"> + <option value="and" <?php if($_REQUEST['operator']=="and") echo "selected=\"selected\""?>><?php echo _('all rules'); ?></option> + <option value="or" <?php if($_REQUEST['operator']=="or") echo "selected=\"selected\""?>><?php echo _('any rule'); ?></option> + </select> + </td> + </tr> + <tr> + <td> + <a id="addrowbutton" href="javascript:void(0)"> + <?php echo get_user_icon('add'); ?> + <?php echo _('Add Another Rule'); ?> + </a> + <script type="text/javascript">Event.observe('addrowbutton', 'click', SearchRow.add);</script> + </td> + </tr> +</tbody> +</table> +<?php show_box_bottom(); ?> + +<?php +if ($playlist) { + $out = $playlist->to_js(); +} +else { + $mysearch = new Search($_REQUEST['type']); + $mysearch->parse_rules(Search::clean_request($_REQUEST)); + $out = $mysearch->to_js(); +} +if ($out) { + echo $out; +} +else { + echo '<script type="text/javascript">SearchRow.add();</script>'; +} +?> diff --git a/templates/show_search.inc.php b/templates/show_search.inc.php index 47c3085f..18992b16 100644 --- a/templates/show_search.inc.php +++ b/templates/show_search.inc.php @@ -37,130 +37,39 @@ */ ?> <?php show_box_top(_('Search Ampache') . "..."); ?> -<form name="search" method="post" action="<?php echo Config::get('web_path'); ?>/search.php" enctype="multipart/form-data" style="Display:inline"> +<form id="search" name="search" method="post" action="<?php echo Config::get('web_path'); ?>/search.php?type=<?php echo $_REQUEST['type'] ? scrub_out($_REQUEST['type']) : 'song'; ?>" enctype="multipart/form-data" style="Display:inline"> <table class="tabledata" cellpadding="3" cellspacing="0"> -<tr class="<?php echo flip_class(); ?>"> - <td><?php echo _('Keywords') ?></td> + <tr> + <td><?php if ($_REQUEST['type'] != 'song') { ?><a href="<?php echo Config::get('web_path'); ?>/search.php?type=song"><?php echo _('Songs'); ?></a><?php } else { echo _('Songs'); } ?></td> + <td><?php if ($_REQUEST['type'] != 'album') { ?><a href="<?php echo Config::get('web_path'); ?>/search.php?type=album"><?php echo _('Albums'); ?></a><?php } else { echo _('Albums'); } ?></td> + <td><?php if ($_REQUEST['type'] != 'artist') { ?><a href="<?php echo Config::get('web_path'); ?>/search.php?type=artist"><?php echo _('Artists'); ?></a><?php } else { echo _('Artists'); } ?></td> + <td><?php if ($_REQUEST['type'] != 'video') { ?><a href="<?php echo Config::get('web_path'); ?>/search.php?type=video"><?php echo _('Videos'); ?></a><?php } else { echo _('Videos'); } ?></td> + </tr> + <tr><td> </td></tr> +</table> +<table class="tabledata" cellpadding="3" cellspacing="0"> + <tr> + <td><?php echo _('Maximum Results'); ?></td> <td> - <input type="text" id="s_all" name="s_all" value="<?php echo scrub_out($_REQUEST['s_all']); ?>"/> + <select name="limit"> + <option value="0"><?php echo _('Unlimited'); ?></option> + <option value="25" <?php if($_REQUEST['limit']=="25") echo "selected=\"selected\""?>>25</option> + <option value="50" <?php if($_REQUEST['limit']=="50") echo "selected=\"selected\""?>>50</option> + <option value="100" <?php if($_REQUEST['limit']=="100") echo "selected=\"selected\""?>>100</option> + <option value="500" <?php if($_REQUEST['limit']=="500") echo "selected=\"selected\""?>>500</option> + </select> </td> - <td><?php echo _('Comment'); ?></td> - <td> - <input type="text" id="s_comment" name="s_comment" value="<?php echo scrub_out($_REQUEST['s_comment']); ?>" /> - </td> -</tr> -<tr class="<?php echo flip_class(); ?>"> - <td><?php echo _('Title'); ?></td> - <td> - <input type="text" id="s_title" name="s_title" value="<?php echo scrub_out($_REQUEST['s_title']); ?>" /> - </td> - <td><?php echo _('Artist'); ?></td> - <td> - <input type="text" id="s_artist" name="s_artist" value="<?php echo scrub_out($_REQUEST['s_artist']); ?>" /> - </td> -</tr> -<tr class="<?php echo flip_class(); ?>"> - <td><?php echo _('Album'); ?></td> - <td> - <input type="text" id="s_album" name="s_album" value="<?php echo scrub_out($_REQUEST['s_album']); ?>" /> - </td> - <td><?php echo _('Tag'); ?></td> - <td> - <input type="text" id="s_tag" name="s_tag" value="<?php echo scrub_out($_REQUEST['s_tag']); ?>" /> - </td> -</tr> -<tr class="<?php echo flip_class(); ?>"> - <td><?php echo _('Year'); ?></td> - <td> - <input type="text" id="s_year" name="s_year" size="5" value="<?php echo scrub_out($_REQUEST['s_year']); ?>" /> - - - <input type="text" id="s_year2" name="s_year2" size="5" value="<?php echo scrub_out($_REQUEST['s_year2']); ?>" /> - </td> - <td><?php echo _('Filename'); ?></td> - <td> - <input type="text" id="s_filename" name="s_filename" value="<?php echo scrub_out($_REQUEST['s_filename']); ?>" /> - </td> -</tr> -<tr class="<?php echo flip_class(); ?>"> - <td><?php echo _('Time'); ?></td> - <td> - <input type="text" id="s_time" name="s_time" size="3" value="<?php echo scrub_out($_REQUEST['s_time']); ?>" /> - - - <input type="text" id="s_time2" name="s_time2" size="3" value="<?php echo scrub_out($_REQUEST['s_time2']); ?>" /> - <?php echo _('minutes'); ?> - </td> - <td><?php echo _('Codec'); ?></td> - <td> - <input type="text" id="s_codec" name="s_codec" size="5" value="<?php echo scrub_out($_REQUEST['s_codec']); ?>" /> - </td> -</tr> -<tr class="<?php echo flip_class(); ?>"> - <td><?php echo _('Played'); ?></td> - <td> - <select id="s_played" name="s_played" > - <option value=""> </option> - <option value="1" <?php if($_REQUEST['s_played']=="1") echo "selected=\"selected\""?>><?php echo _('Yes'); ?></option> - <option value="0" <?php if($_REQUEST['s_played']=="0") echo "selected=\"selected\""?>><?php echo _('No'); ?></option> - </select> - </td> - <td><?php echo _('Min Bitrate'); ?></td> - <td> - <select id="s_minbitrate" name="s_minbitrate" > - <option value=""> </option> - <?php foreach(array(32,40,48,56,64,80,96,112,128,160,192,224,256,320) as $val) { ?> - <option value="<?php echo $val?>" <?php if($_REQUEST['s_minbitrate']==$val) echo "selected=\"selected\""?>><?php echo $val?></option> - <?php } ?> - </select> - </td> -</tr> -<tr class="<?php echo flip_class(); ?>"> - <td><?php echo _('Rating'); ?></td> - <td> - <select id="s_rating_operator" name="s_rating_operator"> - <option value="0" <?php if($_REQUEST['s_rating_operator']=="0") echo "selected=\"selected\""?>><?php echo _('>='); ?></option> - <option value="1" <?php if($_REQUEST['s_rating_operator']=="1") echo "selected=\"selected\""?>><?php echo _('<='); ?></option> - <option value="2" <?php if($_REQUEST['s_rating_operator']=="2") echo "selected=\"selected\""?>><?php echo _('='); ?></option> - </select> - <select id="s_rating" name="s_rating"> - <option value=""> </option> - <option value="1" <?php if($_REQUEST['s_rating']=="1") echo "selected=\"selected\""?>><?php echo _('One Star'); ?></option> - <option value="2" <?php if($_REQUEST['s_rating']=="2") echo "selected=\"selected\""?>><?php echo _('Two Stars'); ?></option> - <option value="3" <?php if($_REQUEST['s_rating']=="3") echo "selected=\"selected\""?>><?php echo _('Three Stars'); ?></option> - <option value="4" <?php if($_REQUEST['s_rating']=="4") echo "selected=\"selected\""?>><?php echo _('Four Stars'); ?></option> - <option value="5" <?php if($_REQUEST['s_rating']=="5") echo "selected=\"selected\""?>><?php echo _('Five Stars'); ?></option> - </select> - </td> - <td><?php echo _('Operator'); ?></td> - <td> - <select name="operator"> - <option value="and" <?php if($_REQUEST['operator']=="and") echo "selected=\"selected\""?>><?php echo _('AND'); ?></option> - <option value="or" <?php if($_REQUEST['operator']=="or") echo "selected=\"selected\""?>><?php echo _('OR'); ?></option> - </select> - </td> -</tr> -<tr class="<?php echo flip_class(); ?>"> - <td><?php echo _('Method'); ?></td> - <td> - <select name="method"> - <option value="fuzzy" <?php if($_REQUEST['method']=="fuzzy") echo "selected=\"selected\""?>><?php echo _('Fuzzy'); ?></option> - <option value="exact" <?php if($_REQUEST['method']=="exact") echo "selected=\"selected\""?>><?php echo _('Exact'); ?></option> - </select> - </td> - <td><?php echo _('Maximum Results'); ?></td> - <td> - <select name="limit"> - <option value="0"><?php echo _('Unlimited'); ?></option> - <option value="25" <?php if($_REQUEST['limit']=="25") echo "selected=\"selected\""?>>25</option> - <option value="50" <?php if($_REQUEST['limit']=="50") echo "selected=\"selected\""?>>50</option> - <option value="100" <?php if($_REQUEST['limit']=="100") echo "selected=\"selected\""?>>100</option> - <option value="500" <?php if($_REQUEST['limit']=="500") echo "selected=\"selected\""?>>500</option> - </select> - </td> -</tr> + </tr> </table> + +<?php require Config::get('prefix') . '/templates/show_rules.inc.php'; ?> + <div class="formValidation"> <input class="button" type="submit" value="<?php echo _('Search'); ?>" /> - <input type="hidden" name="action" value="search" /> +<?php if ($_REQUEST['type'] == 'song' || ! $_REQUEST['type']) { ?> + <input id="savesearchbutton" class="button" type="submit" value="<?php echo _('Save as Smart Playlist'); ?>" onClick="$('hiddenaction').setValue('save_as_smartplaylist');" /> +<?php } ?> + <input type="hidden" id="hiddenaction" name="action" value="search" /> </div> </form> <?php show_box_bottom(); ?> diff --git a/templates/show_search_bar.inc.php b/templates/show_search_bar.inc.php index 486ad9fe..b5bb4f4f 100644 --- a/templates/show_search_bar.inc.php +++ b/templates/show_search_bar.inc.php @@ -33,13 +33,20 @@ ?> <div id="sb_Subsearch"> - <form name="search" method="post" action="<?php echo $web_path; ?>/search.php" enctype="multipart/form-data" style="Display:inline"> - <input type="text" name="search_string" id="searchString"/> - <input type="hidden" name="action" value="quick_search" /> - <input type="hidden" name="method" value="fuzzy" /> + <form name="search" method="post" action="<?php echo $web_path; ?>/search.php?type=song" enctype="multipart/form-data" style="Display:inline"> + <input type="text" name="rule_1_input" id="searchString"/> + <input type="hidden" name="action" value="search" /> + <input type="hidden" name="rule_1_operator" value="0" /> <input type="hidden" name="object_type" value="song" /> + <select name="rule_1"> + <option value="anywhere"><?php echo _('Anywhere')?></option> + <option value="title"><?php echo _('Title')?></option> + <option value="album"><?php echo _('Album')?></option> + <option value="artist"><?php echo _('Artist')?></option> + <option value="tag"><?php echo _('Tag')?></option> + </select> <input class="button" type="submit" value="<?php echo _('Search'); ?>" id="searchBtn" /> - <a href="<?php echo $web_path; ?>/search.php" class="button" id="advSearchBtn"><?php echo _('Advanced Search'); ?></a> + <a href="<?php echo $web_path; ?>/search.php?type=song" class="button" id="advSearchBtn"><?php echo _('Advanced Search'); ?></a> </form> </div> diff --git a/templates/show_search_options.inc.php b/templates/show_search_options.inc.php index dad9d733..1d890767 100644 --- a/templates/show_search_options.inc.php +++ b/templates/show_search_options.inc.php @@ -40,7 +40,7 @@ </li> <?php if (Access::check_function('batch_download')) { ?> <li> - <a href="<?php echo Config::get('web_path'); ?>/batch.php?action=browse&browse_id=<?php echo $browse->id; ?>"><?php echo get_user_icon('batch_download', _('Batch Download')); ?></a> + <a href="<?php echo Config::get('web_path'); ?>/batch.php?action=browse&type=<?php echo scrub_out($_REQUEST['type']); ?>&browse_id=<?php echo $browse->id; ?>"><?php echo get_user_icon('batch_download', _('Batch Download')); ?></a> <?php echo _('Batch Download'); ?> </li> <?php } ?> diff --git a/templates/show_smartplaylist.inc.php b/templates/show_smartplaylist.inc.php new file mode 100644 index 00000000..4c276ffd --- /dev/null +++ b/templates/show_smartplaylist.inc.php @@ -0,0 +1,67 @@ +<?php +/* vim:set tabstop=8 softtabstop=8 shiftwidth=8 noexpandtab: */ +/* + Copyright (c) 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 v2 + as published by the Free Software Foundation. + + 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. + +*/ +?> +<?php +ob_start(); +require Config::get('prefix') . '/templates/show_smartplaylist_title.inc.php'; +$title = ob_get_contents(); +ob_end_clean(); +show_box_top('<div id="playlist_row_' . $playlist->id . '">' . $title . + '</div>'); +?> +<div id="information_actions"> +<ul> + <?php if (Access::check_function('batch_download')) { ?> + <li> + <a href="<?php echo Config::get('web_path'); ?>/batch.php?action=search&id=<?php echo $playlist->id; ?>"><?php echo get_user_icon('batch_download', _('Batch Download')); ?></a> + <?php echo _('Batch Download'); ?> + </li> + <?php } ?> + <li> + <?php echo Ajax::button('?action=basket&type=smartplaylist&id=' . $playlist->id,'add',_('Add All'),'play_playlist'); ?> + <?php echo _('Add All'); ?> + </li> + <?php if ($playlist->has_access()) { ?> + <li> + <?php echo Ajax::button('?action=show_edit_object&type=smartplaylist_title&id=' . $playlist->id,'edit',_('Edit'),'edit_playlist_' . $playlist->id); ?> + <?php echo _('Edit'); ?> + </li> + <li> + <a href="<?php echo Config::get('web_path'); ?>/smartplaylist.php?action=delete_playlist&playlist_id=<?php echo $playlist->id; ?>"> + <?php echo get_user_icon('delete'); ?> + </a> + <?php echo _('Delete'); ?> + </li> + <?php } ?> +</ul> +</div> + +<form id="editplaylist" name="editplaylist" method="post" action="<?php echo Config::get('web_path'); ?>/smartplaylist.php?action=update_playlist&playlist_id=<?php echo $playlist->id; ?>" enctype="multipart/form-data" style="Display:inline"> + +<?php require Config::get('prefix') . '/templates/show_rules.inc.php'; ?> + +<div class="formValidation"> + <input class="button" type="submit" value="<?php echo _('Save Changes'); ?>" /> +</div> + +</form> + +<?php show_box_bottom(); ?> diff --git a/templates/show_smartplaylist_row.inc.php b/templates/show_smartplaylist_row.inc.php new file mode 100644 index 00000000..bf1f43f0 --- /dev/null +++ b/templates/show_smartplaylist_row.inc.php @@ -0,0 +1,39 @@ +<?php +/* vim:set tabstop=8 softtabstop=8 shiftwidth=8 noexpandtab: */ +/* + + Copyright (c) 2001 - 2007 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 v2 + as published by the Free Software Foundation. + + 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. + +*/ +?> +<td class="cel_add"> + <?php echo Ajax::button('?action=basket&type=smartplaylist&id=' . $playlist->id,'add',_('Add'),'add_playlist_' . $playlist->id); ?> +</td> +<td class="cel_playlist"><?php echo $playlist->f_link; ?></td> +<td class="cel_type"><?php echo $playlist->f_type; ?></td> +<td class="cel_owner"><?php echo scrub_out($playlist->f_user); ?></td> +<td class="cel_action"> + <?php if (Access::check_function('batch_download')) { ?> + <a href="<?php echo Config::get('web_path'); ?>/batch.php?action=smartplaylist&id=<?php echo $playlist->id; ?>"> + <?php echo get_user_icon('batch_download',_('Batch Download')); ?> + </a> + <?php } ?> + <?php if ($playlist->has_access()) { ?> + <?php echo Ajax::button('?action=show_edit_object&type=smartplaylist_row&id=' . $playlist->id,'edit',_('Edit'),'edit_playlist_' . $playlist->id); ?> + <?php echo Ajax::button('?page=browse&action=delete_object&type=smartplaylist&id=' . $playlist->id,'delete',_('Delete'),'delete_playlist_' . $playlist->id); ?> + <?php } ?> +</td> diff --git a/templates/show_smartplaylist_title.inc.php b/templates/show_smartplaylist_title.inc.php new file mode 100644 index 00000000..8691ac98 --- /dev/null +++ b/templates/show_smartplaylist_title.inc.php @@ -0,0 +1,24 @@ +<?php +/* vim:set tabstop=8 softtabstop=8 shiftwidth=8 noexpandtab: */ +/* + + Copyright (c) 2001 - 2007 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 v2 + as published by the Free Software Foundation. + + 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. + +*/ +?> + +<?php echo sprintf(_('%s %s (Smart Playlist)'), $playlist->f_type, $playlist->name); ?> diff --git a/templates/show_smartplaylists.inc.php b/templates/show_smartplaylists.inc.php new file mode 100644 index 00000000..2c891884 --- /dev/null +++ b/templates/show_smartplaylists.inc.php @@ -0,0 +1,63 @@ +<?php +/* vim:set tabstop=8 softtabstop=8 shiftwidth=8 noexpandtab: */ +/* + + Copyright (c) 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. + +*/ +?> +<?php require Config::get('prefix') . '/templates/list_header.inc.php' ?> +<table class="tabledata" cellpadding="0" cellspacing="0"> +<colgroup> + <col id="col_add" /> + <col id="col_playlist" /> + <col id="col_type" /> + <col id="col_songs" /> + <col id="col_owner" /> + <col id="col_action" /> +</colgroup> +<tr class="th-top"> + <th class="cel_add"><?php echo _('Add'); ?></th> + <th class="cel_playlist"><?php echo Ajax::text('?page=browse&action=set_sort&type=smartplaylist&sort=name',_('Playlist Name'),'playlist_sort_name'); ?></th> + <th class="cel_type"> </th> + <th class="cel_owner"><?php echo Ajax::text('?page=browse&action=set_sort&type=smartplaylist&sort=user',_('Owner'),'playlist_sort_owner'); ?></th> + <th class="cel_action"><?php echo _('Actions'); ?></th> +</tr> +<?php +foreach ($object_ids as $playlist_id) { + $playlist = new Search('song', $playlist_id); + $playlist->format(); +?> +<tr class="<?php echo flip_class(); ?>" id="playlist_row_<?php echo $playlist->id; ?>"> + <?php require Config::get('prefix') . '/templates/show_smartplaylist_row.inc.php'; ?> +</tr> +<?php } // end foreach ($playlists as $playlist) ?> +<?php if (!count($object_ids)) { ?> +<tr class="<?php echo flip_class(); ?>"> + <td colspan="6"><span class="fatalerror"><?php echo _('Not Enough Data'); ?></span></td> +</tr> +<?php } ?> +<tr class="th-bottom"> + <th class="cel_add"><?php echo _('Add'); ?></th> + <th class="cel_playlist"><?php echo Ajax::text('?page=browse&action=set_sort&type=playlist&sort=name',_('Playlist Name'),'playlist_sort_name_bottom'); ?></th> + <th class="cel_type"> </th> + <th class="cel_owner"><?php echo Ajax::text('?page=browse&action=set_sort&type=playlist&sort=user',_('Owner'),'playlist_sort_owner_bottom'); ?></th> + <th class="cel_action"><?php echo _('Actions'); ?></th> +</tr> +</table> +<?php require Config::get('prefix') . '/templates/list_header.inc.php' ?> diff --git a/templates/sidebar_home.inc.php b/templates/sidebar_home.inc.php index b0fb642a..4b97abd5 100644 --- a/templates/sidebar_home.inc.php +++ b/templates/sidebar_home.inc.php @@ -48,6 +48,7 @@ $ajax_info = Config::get('ajax_url'); $web_path = Config::get('web_path'); <li id="sb_browse_bb_Artist"><a href="<?php echo $web_path; ?>/browse.php?action=artist"><?php echo _('Artists'); ?></a></li> <li id="sb_browse_bb_Tags"><a href="<?php echo $web_path; ?>/browse.php?action=tag"><?php echo _('Tag Cloud'); ?></a></li> <li id="sb_browse_bb_Playlist"><a href="<?php echo $web_path; ?>/browse.php?action=playlist"><?php echo _('Playlists'); ?></a></li> + <li id="sb_browse_bb_SmartPlaylist"><a href="<?php echo $web_path; ?>/browse.php?action=smartplaylist"><?php echo _('Smart Playlists'); ?></a></li> <li id="sb_browse_bb_RadioStation"><a href="<?php echo $web_path; ?>/browse.php?action=live_stream"><?php echo _('Radio Stations'); ?></a></li> <li id="sb_browse_bb_Video"><a href="<?php echo $web_path; ?>/browse.php?action=video"><?php echo _('Videos'); ?></a></li> </ul> @@ -77,7 +78,7 @@ $ajax_info = Config::get('ajax_url'); $web_path = Config::get('web_path'); <li id="sb_home_random_album"><?php echo Ajax::text('?page=random&action=album',_('Album'),'home_random_album'); ?></li> <li id="sb_home_random_artist"><?php echo Ajax::text('?page=random&action=artist',_('Artist'),'home_random_artist'); ?></li> <li id="sb_home_random_playlist"><?php echo Ajax::text('?page=random&action=playlist',_('Playlist'),'home_random_playlist'); ?></li> - <li id="sb_home_random_advanced"><a href="<?php echo $web_path; ?>/random.php?action=advanced"><?php echo _('Advanced'); ?></a></li> + <li id="sb_home_random_advanced"><a href="<?php echo $web_path; ?>/random.php?action=advanced&type=song"><?php echo _('Advanced'); ?></a></li> </ul> </li> <li><h4><?php echo _('Information'); ?></h4> |