diff options
author | Paul 'flowerysong' Arthur <flowerysong00@yahoo.com> | 2010-08-17 20:59:16 +0000 |
---|---|---|
committer | Paul 'flowerysong' Arthur <flowerysong00@yahoo.com> | 2010-08-17 20:59:16 +0000 |
commit | df80bd72432011010dc0e91ab564659ca6b2c500 (patch) | |
tree | c68f957da32a382bf3a542b7e7f3e54b886483ca | |
parent | 34d1449660437c2ea24dd55989efebf4e01d485f (diff) | |
download | ampache-df80bd72432011010dc0e91ab564659ca6b2c500.tar.gz ampache-df80bd72432011010dc0e91ab564659ca6b2c500.tar.bz2 ampache-df80bd72432011010dc0e91ab564659ca6b2c500.zip |
Refactored Last.FM recommendations; drop new dependency on curl since
Snoopy works just as well for this application.
-rw-r--r-- | artists.php | 17 | ||||
-rw-r--r-- | config/ampache.cfg.php.dist | 6 | ||||
-rw-r--r-- | lib/class/artist.class.php | 38 | ||||
-rw-r--r-- | lib/class/recommendation.class.php | 201 | ||||
-rw-r--r-- | lib/debug.lib.php | 15 | ||||
-rw-r--r-- | templates/show_artist.inc.php | 3 | ||||
-rw-r--r-- | templates/show_install_check.inc.php | 11 | ||||
-rw-r--r-- | templates/show_now_playing_row.inc.php | 38 | ||||
-rw-r--r-- | templates/show_recommended_artists.inc.php | 72 |
9 files changed, 322 insertions, 79 deletions
diff --git a/artists.php b/artists.php index ea9cb414..d8fb1d91 100644 --- a/artists.php +++ b/artists.php @@ -34,6 +34,14 @@ switch($_REQUEST['action']) { $object_ids = $artist->get_albums(); $object_type = 'album'; require_once Config::get('prefix') . '/templates/show_artist.inc.php'; + if (Config::get('lastfm_api_key')) { + if ($object_ids = Recommendation::get_artists_like($artist->id)) { + // Ugly code to grab the relevant entries. + // Almost looks like Perl. + $object_ids = array_map(create_function('$i', 'return $i[\'id\'];'), $object_ids); + require_once Config::get('prefix') . '/templates/show_recommended_artists.inc.php'; + } + } break; case 'show_all_songs': $artist = new Artist($_REQUEST['artist']); @@ -42,15 +50,6 @@ switch($_REQUEST['action']) { $object_ids = $artist->get_songs(); require_once Config::get('prefix') . '/templates/show_artist.inc.php'; break; - - case 'show_like': - $artist = new Artist($_REQUEST['artist']); - $artist->format(); - $object_type = 'artist'; - $object_ids = $artist->get_like(); - require_once Config::get('prefix') . '/templates/show_artist.inc.php'; - break; - case 'update_from_tags': $type = 'artist'; diff --git a/config/ampache.cfg.php.dist b/config/ampache.cfg.php.dist index 13e31fee..a30988a4 100644 --- a/config/ampache.cfg.php.dist +++ b/config/ampache.cfg.php.dist @@ -307,9 +307,9 @@ art_order = "db,tags,folder,musicbrainz,lastfm,google" ;amazon_developer_public_key = "" ;amazon_developer_private_key = "" -; LastFM API Key -; Set this to your api key that you can register -; on last.fm +; Last.FM API Key +; Set this to your Last.FM api key to actually use Last.FM for +; recommendations. ;lastfm_api_key = "" ; Amazon base urls diff --git a/lib/class/artist.class.php b/lib/class/artist.class.php index 1009591c..f7638b94 100644 --- a/lib/class/artist.class.php +++ b/lib/class/artist.class.php @@ -145,44 +145,6 @@ class Artist extends database_object { return $results; } // get_albums - public function get_like() { - - // Are you compiling with cURL? - if (!check_php_curl()) { - return false; - } - - $result = array(); - $lastfm_api_key = Config::get('lastfm_api_key'); - - $artistsql = "SELECT name FROM artist WHERE id = \"" . $this->id . "\""; - $artist_result = Dba::query($artistsql); - $r = Dba::fetch_assoc($artist_result); - $searchArtist = preg_replace('/ /', '%20', $r['name']); - - $lastsite = "http://ws.audioscrobbler.com/2.0/?method=artist.getsimilar&artist=" . $searchArtist . "&api_key=" . $lastfm_api_key; - debug_event('Similar', 'search url : ' . $lastsite, 5); - $lastch = curl_init(); - curl_setopt($lastch, CURLOPT_URL, $lastsite); - curl_setopt($lastch, CURLOPT_RETURNTRANSFER, 1); - - $lastxml = simplexml_load_string( curl_exec($lastch) ); - $lastcontent = curl_exec($lastch); - $lastxml = simplexml_load_string( $lastcontent ); - - foreach( $lastxml->similarartists->children() as $lastchild ) { - $check_query = 'SELECT * FROM artist WHERE name = \'' . $lastchild->name . '\''; - $check_result = Dba::query($check_query); - $row = Dba::fetch_assoc($check_result); - if( !is_null($row['id']) ) { - $result[] = $row['id']; - // debug_event('Similar', 'row return: ' . $row['id'], 5); - } - } - - return $result; - - } // get_like /** * get_songs diff --git a/lib/class/recommendation.class.php b/lib/class/recommendation.class.php new file mode 100644 index 00000000..0852780d --- /dev/null +++ b/lib/class/recommendation.class.php @@ -0,0 +1,201 @@ +<?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. + +*/ + +/** + * Recommendation Class + */ +class Recommendation { + + /** + * Constructor + * Not on my watch, boyo. + */ + private function __construct() { + return false; + } //constructor + + /** + * get_lastfm_results + * Runs a last.fm query and returns the parsed results + */ + private static function get_lastfm_results($method, $query) { + $api_key = Config::get('lastfm_api_key'); + $api_base = "http://ws.audioscrobbler.com/2.0/?method="; + $url = $api_base . $method . '&api_key=' . $api_key . '&' . $query; + debug_event('Recommendation', 'search url : ' . $url, 5); + + $snoopy = new Snoopy(); + if(Config::get('proxy_host') AND Config::get('proxy_port')) { + $snoopy->proxy_user = Config::get('proxy_host'); + $snoopy->proxy_port = Config::get('proxy_port'); + $snoopy->proxy_user = Config::get('proxy_user'); + $snoopy->proxy_pass = Config::get('proxy_pass'); + } + $snoopy->fetch($url); + $content = $snoopy->results; + + return simplexml_load_string($content); + } // get_lastfm_results + + /** + * get_songs_like + * Returns a list of similar songs + */ + public static function get_songs_like($song_id, $limit = 5, $local_only = true) { + $song = new Song($song_id); + + if (isset($song->mbid)) { + $query = 'mbid=' . rawurlencode($song->mbid); + } + else { + $query = 'track=' . rawurlencode($song->title); + } + + if ($limit && !$local_only) { + $query .= "&limit=$limit"; + } + + $xml = self::get_lastfm_results('track.getsimilar', $query); + + foreach ($xml->similartracks->children() as $child) { + $name = $child->name; + $local_id = null; + + $artist_name = $child->artist->name; + $s_artist_name = Catalog::trim_prefix($artist_name); + $s_artist_name = Dba::escape($s_artist_name['string']); + + $sql = "SELECT `song`.`id` FROM `song` " . + "LEFT JOIN `artist` ON " . + "`song`.`artist`=`artist`.`id` WHERE " . + "`song`.`title`='" . Dba::escape($name) . + "' AND `artist`.`name`='$s_artist_name'"; + + $db_result = Dba::read($sql); + + if ($result = Dba::fetch_assoc($db_result)) { + $local_id = $result['id']; + } + + if (is_null($local_id)) { + debug_event('Recommendation', "$name did not match any local song", 5); + if (! $local_only) { + $results[] = array( + 'id' => null, + 'title' => $name, + 'artist' => $artist_name + ); + } + } + else { + debug_event('Recommendation', "$name matched local song $local_id", 5); + $results[] = array( + 'id' => $local_id, + 'title' => $name + ); + } + + if ($limit && count($results) >= $limit) { + break; + } + } + + if (isset($results)) { + return $results; + } + + return false; + } + + /** + * get_artists_like + * Returns a list of similar artists + */ + public static function get_artists_like($artist_id, $limit = 5, $local_only = true) { + $artist = new Artist($artist_id); + + $query = 'artist=' . rawurlencode($artist->name); + if ($limit && !$local_only) { + $query .= "&limit=$limit"; + } + + $xml = self::get_lastfm_results('artist.getsimilar', $query); + + foreach ($xml->similarartists->children() as $child) { + $name = $child->name; + $local_id = null; + + // First we check by MBID + if ((string)$child->mbid) { + $mbid = Dba::escape($child->mbid); + $sql = "SELECT `id` FROM `artist` WHERE `mbid`='$mbid'"; + $db_result = Dba::read($sql); + if ($result = Dba::fetch_assoc($db_result)) { + $local_id = $result['id']; + } + } + + // Then we fall back to the less likely to work exact + // name match + if (is_null($local_id)) { + $searchname = Catalog::trim_prefix($name); + $searchname = Dba::escape($searchname['string']); + $sql = "SELECT `id` FROM `artist` WHERE `name`='$searchname'"; + $db_result = Dba::read($sql); + if ($result = Dba::fetch_assoc($db_result)) { + $local_id = $result['id']; + } + } + + // Then we give up + if (is_null($local_id)) { + debug_event('Recommendation', "$name did not match any local artist", 5); + if (! $local_only) { + $results[] = array( + 'id' => null, + 'name' => $name + ); + } + } + else { + debug_event('Recommendation', "$name matched local artist " . $local_id, 5); + $results[] = array( + 'id' => $local_id, + 'name' => $name + ); + } + + // Don't do more work than we have to + if ($limit && count($results) >= $limit) { + break; + } + } + + if (isset($results)) { + return $results; + } + + return false; + } // get_artists_like + +} // end of recommendation class +?> diff --git a/lib/debug.lib.php b/lib/debug.lib.php index e49cb065..4464447e 100644 --- a/lib/debug.lib.php +++ b/lib/debug.lib.php @@ -157,21 +157,6 @@ function check_php_pcre() { } // check_php_pcre /** - * check_php_curl - * This makes sure they have cURL (curl_???) support - * compiled into PHP this is optional - */ -function check_php_curl() { - - if (!extension_loaded('curl')) { - return false; - } - - return true; - -} // check_php_curl - -/** * check_config_values * checks to make sure that they have at least set the needed variables */ diff --git a/templates/show_artist.inc.php b/templates/show_artist.inc.php index d14bc665..408e6b5e 100644 --- a/templates/show_artist.inc.php +++ b/templates/show_artist.inc.php @@ -54,9 +54,6 @@ if (Config::get('ratings')) { <?php echo Ajax::button('?action=basket&type=artist_random&id=' . $artist->id,'random',_('Random'),'random_' . $artist->id); ?> <?php echo Ajax::text('?action=basket&type=artist_random&id=' . $artist->id, sprintf(_('Add Random Songs By %s'), $artist->f_name),'random_text_' . $artist->id); ?> </li> -<li> - <a href="<?php echo $web_path; ?>/artists.php?action=show_like&artist=<?php echo $artist->id; ?>"><?php echo get_user_icon('view'); ?></a> <a href="<?php echo $web_path; ?>/artists.php?action=show_like&artist=<?php echo $artist->id; ?>"><?php printf(_("Show Similar to %s"), $artist->f_name); ?></a> -</li> <?php if (Access::check('interface','50')) { ?> <li> <a href="<?php echo $web_path; ?>/artists.php?action=update_from_tags&artist=<?php echo $artist->id; ?>"><?php echo get_user_icon('cog', _('Update from tags')); ?></a> diff --git a/templates/show_install_check.inc.php b/templates/show_install_check.inc.php index 97bdb64b..08952496 100644 --- a/templates/show_install_check.inc.php +++ b/templates/show_install_check.inc.php @@ -174,16 +174,5 @@ } ?> </td> -</tr><tr> -<td><?php echo _('PHP cURL extension Support'); ?>:</td> -<td> -<?php - if (!check_php_curl()) { - echo debug_result(_('Some functions might not run correctly.'), false); - } - else { - echo debug_result(_(''), true); - } -?> </tr> </table> diff --git a/templates/show_now_playing_row.inc.php b/templates/show_now_playing_row.inc.php index ad33429f..c6f4988f 100644 --- a/templates/show_now_playing_row.inc.php +++ b/templates/show_now_playing_row.inc.php @@ -82,3 +82,41 @@ $artist = scrub_out(truncate_with_ellipsis($media->f_artist_full)); </div> </div> <?php } // end play album art ?> + +<?php if (Config::get('show_similar')) { ?> +<div class="np_group"> +<?php if ($artists = Recommendation::get_artists_like($media->artist, 3, false)) { ?> + <div class="np_cel cel_similar"> + <label><?php echo _('Similar Artists'); ?></label> + <?php foreach ($artists as $a) { ?> + <div class="np_cel cel_similar_artist"> + <?php + if (is_null($a['id'])) { + echo scrub_out(truncate_with_ellipsis($a['name']), Config::get('ellipse_threshold_artist')); + } + else { + $artist = new Artist($a['id']); + $artist->format(); + echo $artist->f_name_link; + } + ?> + </div> + <?php } // end foreach ?> + </div> +<?php } // end show similar artists ?> +<?php if ($songs = Recommendation::get_songs_like($media->id, 3)) { ?> + <div class="np_cel cel_similar"> + <label><?php echo _('Similar Songs'); ?></label> + <?php foreach ($songs as $s) { ?> + <div class="np_cel cel_similar_song"> + <?php + $song = new Song($s['id']); + $song->format(); + echo $song->f_link; + ?> + </div> + <?php } // end foreach ?> + </div> +<?php } // end show similar songs ?> +</div> +<?php } // end show similar things ?> diff --git a/templates/show_recommended_artists.inc.php b/templates/show_recommended_artists.inc.php new file mode 100644 index 00000000..459e2d63 --- /dev/null +++ b/templates/show_recommended_artists.inc.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. +*/ + +?> +<?php show_box_top(_('Similar Artists'), 'info-box'); ?> +<table class="tabledata" cellpadding="0" cellspacing="0"> +<colgroup> + <col id="col_add" /> + <col id="col_artist" /> + <col id="col_songs" /> + <col id="col_albums" /> + <col id="col_tags" /> + <col id="col_rating" /> + <col id="col_action" /> +</colgroup> +<tr class="th-top"> + <th class="cel_add"><?php echo _('Add'); ?></th> + <th class="cel_artist"><?php echo _('Artist'); ?></th> + <th class="cel_songs"><?php echo _('Songs'); ?></th> + <th class="cel_albums"><?php echo _('Albums'); ?></th> + <th class="cel_time"><?php echo _('Time'); ?></th> + <th class="cel_tags"><?php echo _('Tags'); ?></th> + <th class="cel_rating"> <?php echo _('Rating'); ?> </th> + <th class="cel_action"> <?php echo _('Action'); ?> </th> +</tr> +<?php +// Cache the ratings we are going to use +if (Config::get('ratings')) { Rating::build_cache('artist',$object_ids); } + +/* Foreach through every artist that has been passed to us */ +foreach ($object_ids as $artist_id) { + $artist = new Artist($artist_id); + $artist->format(); +?> +<tr id="artist_<?php echo $artist->id; ?>" class="<?php echo flip_class(); ?>"> + <?php require Config::get('prefix') . '/templates/show_artist_row.inc.php'; ?> +</tr> +<?php } //end foreach ($artists as $artist) ?> +<?php if (!count($object_ids)) { ?> +<tr class="<?php echo flip_class(); ?>"> + <td colspan="5"><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_artist"><?php echo _('Artist'); ?></th> + <th class="cel_songs"> <?php echo _('Songs'); ?> </th> + <th class="cel_albums"> <?php echo _('Albums'); ?> </th> + <th class="cel_time"> <?php echo _('Time'); ?> </th> + <th class="cel_tags"><?php echo _('Tags'); ?></th> + <th class="cel_rating"> <?php echo _('Rating'); ?> </th> + <th class="cel_action"> <?php echo _('Action'); ?> </th> +</tr> +</table> |