123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468 |
- <?php
- /* GNU FM -- a free network service for sharing your music listening habits
- Copyright (C) 2009 Free Software Foundation, Inc
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, either version 3 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 Affero General Public License for more details.
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- require_once($install_path . '/database.php');
- require_once($install_path . '/data/Track.php');
- require_once($install_path . '/scrobble-utils.php');
- require_once('xml.php');
- /**
- * Class with functions that returns XML-formatted data for tracks.
- *
- * These functions are mainly used by web service methods.
- *
- * @package API
- */
- class TrackXML {
- public static function addTags($userid, $artist, $album, $trackName, $tags) {
- try {
- $track = new Track($trackName, $artist);
- $res = $track->addTags($tags, $userid);
- } catch (Exception $e) {
- return(XML::error('failed', '7', 'Invalid resource specified'));
- }
- if(!$res) {
- $xml = XML::error('failed', '7', 'Invalid resource specified');
- } else {
- $xml = new SimpleXMLElement('<lfm status="ok"></lfm>');
- }
- return $xml;
- }
- public static function removeTag($userid, $artist, $trackName, $tag) {
- try {
- $track = new Track($trackName, $artist);
- $res = $track->removeTag($tag, $userid);
- } catch (Exception $e) {
- return(XML::error('failed', '7', 'Invalid resource specified'));
- }
- if(!$res) {
- $xml = XML::error('failed', '7', 'Invalid resource specified');
- } else {
- $xml = new SimpleXMLElement('<lfm status="ok"></lfm>');
- }
- return $xml;
- }
- public static function getInfo($artist, $name, $username) {
- global $adodb;
- try {
- $track = new Track($name, $artist);
- } catch (Exception $e) {
- return(XML::error('failed', '7', 'Invalid resource specified'));
- }
- $xml = new SimpleXMLElement('<lfm status="ok"></lfm>');
- $root = $xml->addChild('track', null);
- $root->addChild('name', $track->name);
- $root->addChild('mbid', $track->mbid);
- $root->addChild('url', $track->getURL());
- $root->addChild('duration', $track->duration * 1000);
- $streamable = $root->addChild('streamable', $track->streamable);
- $streamable->addAttribute('fulltrack', $track->streamable);
- $root->addChild('listeners', $track->getListenerCount());
- $root->addChild('playcount', $track->getPlayCount());
- if($username) {
- $userid = $adodb->GetOne('SELECT uniqueid FROM Users WHERE '
- . 'username = ' . $adodb->qstr($username));
- $root->addChild('userloved', $track->isLoved($userid) ? 1 : 0);
- }
- return $xml;
- }
- public static function getTopTags($artist, $name, $limit, $cache) {
- try {
- $track = new Track($name, $artist);
- $res = $track->getTopTags($limit, 0, $cache);
- } catch (Exception $e) {
- return(XML::error('failed', '7', 'Invalid resource specified'));
- }
- if(!$res) {
- return(XML::error('failed', '6', 'No tags for this track'));
- }
-
- $xml = new SimpleXMLElement('<lfm status="ok"></lfm>');
- $root = $xml->addChild('toptags', null);
- $root->addAttribute('artist', $artist);
- $root->addAttribute('track', $name);
- foreach ($res as &$row) {
- $tag_node = $root->addChild('tag', null);
- $tag_node->addChild('name', repamp($row['tag']));
- $tag_node->addChild('count', $row['freq']);
- $tag_node->addChild('url', Server::getTagURL($row['tag']));
- }
- return $xml;
- }
- public static function getTopFans($name, $artistname, $limit, $cache) {
- global $adodb;
- try {
- $track = new Track($name, $artistname);
- $res = $track->getTopListeners($limit, 0, False, null, null, $cache);
- } catch (Exception $e) {
- return XML::error('error', '7', 'Invalid resource specified');
- }
- $xml = new SimpleXMLElement('<lfm status="ok"></lfm>');
- $root = $xml->addChild('topfans', null);
- $root->addAttribute('artist', $track->artist_name);
- $root->addAttribute('track', $track->name);
- foreach($res as &$row) {
- try {
- $user = new User($row['username']);
- $user_node = $root->addChild('user', null);
- $user_node->addChild('name', $user->name);
- $user_node->addChild('realname', $user->fullname);
- $user_node->addChild('url', repamp($user->getURL()));
- $image_small = $user_node->addChild('image', null);
- $image_small->addAttribute('size', 'small');
- $image_medium = $user_node->addChild('image', null);
- $image_medium->addAttribute('size', 'medium');
- $image_large = $user_node->addChild('image', null);
- $image_large->addAttribute('size', 'large');
- $user_node->addChild('weight', $row['freq']);
- } catch (Exception $e) {}
- }
- return $xml;
- }
- public static function getTags($artist, $name, $userid, $limit, $cache) {
-
- try {
- $track = new Track($name, $artist);
- $res = $track->getTags($userid, $limit, 0, $cache);
- } catch (Exception $e) {
- return(XML::error('failed', '7', 'Invalid resource specified'));
- }
- if(!$res) {
- return(XML::error('failed', '6', 'No tags for this track'));
- }
- $xml = new SimpleXMLElement('<lfm status="ok"></lfm>');
- $root = $xml->addChild('tags', null);
- $root->addAttribute('artist', $artist);
- $root->addAttribute('track', $name);
- foreach ($res as &$row) {
- $tag_node = $root->addChild('tag', null);
- $tag_node->addChild('name', repamp($row['tag']));
- $tag_node->addChild('url', Server::getTagURL($row['tag']));
- }
- return $xml;
- }
- public static function ban($artist, $name, $userid) {
- try {
- $track = new Track($name, $artist);
- $res = $track->ban($userid);
- } catch (Exception $e) {
- return XML::error('failed', '7', 'Invalid resource specified');
- }
- if(!$res) {
- $xml = XML::error('failed', '7', 'Invalid resource specified');
- } else {
- $xml = new SimpleXMLElement('<lfm status="ok"></lfm>');
- }
- return $xml;
- }
- public static function love($artist, $name, $userid) {
- try {
- $track = new Track($name, $artist);
- $res = $track->love($userid);
- } catch (Exception $e) {
- return XML::error('failed', '7', 'Invalid resource specified');
- }
- if(!$res) {
- $xml = XML::error('failed', '7', 'Invalid resource specified');
- } else {
- $xml = new SimpleXMLElement('<lfm status="ok"></lfm>');
- }
- return $xml;
- }
- public static function unban($artist, $name, $userid) {
- try {
- $track = new Track($name, $artist);
- $res = $track->unban($userid);
- } catch (Exception $e) {
- return XML::error('failed', '7', 'Invalid resource specified');
- }
- if(!$res) {
- $xml = XML::error('failed', '7', 'Invalid resource specified');
- } else {
- $xml = new SimpleXMLElement('<lfm status="ok"></lfm>');
- }
- return $xml;
- }
- public static function unlove($artist, $name, $userid) {
- try {
- $track = new Track($name, $artist);
- $res = $track->unlove($userid);
- } catch (Exception $e) {
- return XML::error('failed', '7', 'Invalid resource specified');
- }
- if(!$res) {
- $xml = XML::error('failed', '7', 'Invalid resource specified');
- } else {
- $xml = new SimpleXMLElement('<lfm status="ok"></lfm>');
- }
- return $xml;
- }
- public static function updateNowPlaying($userid, $artist, $track, $album, $tracknumber, $context, $mbid, $duration, $albumartist, $api_key) {
- global $adodb;
- $sessionid = Server::getScrobbleSession($userid, $api_key);
- $t = array(
- 'artist' => $artist,
- 'track' => $track,
- 'album' => $album,
- 'tracknumber' => $tracknumber,
- 'mbid' => $mbid,
- 'duration' => $duration,
- 'albumartist' => $albumartist
- );
- $t = prepareTrack($userid, $t, 'nowplaying');
- // Delete last played track
- $query = 'DELETE FROM Now_Playing WHERE sessionid = ?';
- $params = array($sessionid);
- try {
- $adodb->Execute($query, $params);
- } catch (Exception $e) {}
- // Calculate expiry time
- if (!$t['duration'] || ($t['duration'] > 5400)) {
- // Default expiry time of 300 seconds if duration is false or above 5400 seconds
- $expires = time() + 300;
- } else {
- $expires = time() + $t['duration'];
- }
- if ($t['ignored_code'] === 0) {
- // Clean up expired tracks in now_playing table
- $params = array(time());
- $query = 'DELETE FROM Now_Playing WHERE expires < ?';
- $adodb->Execute($query, $params);
- $adodb->StartTrans();
- try {
- // getTrackID will create the track in Track table if it doesnt exist
- getTrackID($t['artist'], $t['album'], $t['track'], $t['mbid'], $t['duration']);
- $params = array($sessionid, $t['track'], $t['artist'], $t['album'], $t['mbid'], $expires);
- $query = 'INSERT INTO Now_Playing(sessionid, track, artist, album, mbid, expires) VALUES (?,?,?,?,?,?)';
- $adodb->Execute($query, $params);
- } catch (Exception $e) {
- $adodb->FailTrans();
- $adodb->CompleteTrans();
- reportError($e->getMessage(), $e->getTraceAsString());
- return XML::error('failed', '16', 'The service is temporarily unavailable, please try again.');
- }
- $adodb->CompleteTrans();
- }
- $xml = new SimpleXMLElement('<lfm status="ok"></lfm>');
- $root = $xml->addChild('nowplaying', null);
- $track_node = $root->addChild('track', repamp($t['track']));
- $track_node->addAttribute('corrected', $t['track_corrected']);
- $artist_node = $root->addChild('artist', repamp($t['artist']));
- $artist_node->addAttribute('corrected', $t['artist_corrected']);
- $album_node = $root->addChild('album', repamp($t['album']));
- $album_node->addAttribute('corrected', $t['album_corrected']);
- $albumartist_node = $root->addChild('albumArtist', repamp($t['albumartist']));
- $albumartist_node->addAttribute('corrected', $t['albumartist_corrected']);
- $ignoredmessage_node = $root->addChild('ignoredMessage', $t['ignored_message']);
- $ignoredmessage_node->addAttribute('code', $t['ignored_code']);
- return $xml;
- }
- public static function scrobble($userid, $artist, $track, $timestamp, $album, $context, $streamid, $chosenbyuser, $tracknumber, $mbid, $albumartist, $duration, $api_key) {
- global $adodb;
- $sessionid = Server::getScrobbleSession($userid, $api_key);
- $accepted_count = 0;
- $ignored_count = 0;
- $tracks_array = array();
- // Convert input to track arrays and add them to tracks_array
- if (is_array($artist)) {
- for ($i = 0; $i < count($artist); $i++) {
- $tracks_array[$i] = array(
- 'artist' => $artist[$i],
- 'track' => $track[$i],
- 'timestamp' => $timestamp[$i],
- 'album' => $album[$i],
- 'tracknumber' => $tracknumber[$i],
- 'mbid' => $mbid[$i],
- 'albumartist' => $albumartist[$i],
- 'duration' => $duration[$i],
- );
- }
- } else {
- $tracks_array[0] = array(
- 'artist' => $artist,
- 'track' => $track,
- 'timestamp' => $timestamp,
- 'album' => $album,
- 'tracknumber' => $tracknumber,
- 'mbid' => $mbid,
- 'albumartist' => $albumartist,
- 'duration' => $duration,
- );
- }
- // Correct and inspect scrobbles to see if some should be ignored
- for ($i = 0; $i < count($tracks_array); $i++) {
- $tracks_array[$i] = prepareTrack($userid, $tracks_array[$i], 'scrobble');
- }
- $adodb->StartTrans();
- for ($i = 0; $i < count($tracks_array); $i++) {
- $t = $tracks_array[$i];
- if ($t['ignored_code'] === 0) {
- try {
- // Create artist, album and track if not already in db
- $t['track_id'] = getTrackID($t['artist'], $t['album'], $t['track'], $t['mbid'], $t['duration']);
- $t['scrobbletrack_id'] = getScrobbleTrackID($t['artist'], $t['album'], $t['track'], $t['mbid'], $t['duration'], $t['track_id']);
- } catch (Exception $e) {
- // Roll back database entries, log error and respond with error message
- $adodb->FailTrans();
- $adodb->CompleteTrans();
- reportError($e->getMessage(), $e->getTraceAsString());
- return XML::error('failed', '16', 'The service is temporarily unavailable, please try again.');
- }
- try {
- // Scrobble
- // TODO last.fm spec says we shouldnt scrobble corrected values,
- // so maybe we should only use corrected values for validation and in xml
- $query = 'INSERT INTO Scrobbles (userid, artist, album, track, time, mbid, source, rating, length, stid) VALUES (?,?,?,?,?,?,?,?,?,?)';
- $params = array(
- $userid,
- $t['artist'],
- $t['album'],
- $t['track'],
- $t['timestamp'],
- $t['mbid'],
- null,
- null,
- $t['duration'],
- $t['scrobbletrack_id']
- );
- $adodb->Execute($query, $params);
- } catch (Exception $e) {
- // Roll back database entries, log error and respond with error message
- $adodb->FailTrans();
- $adodb->CompleteTrans();
- reportError($e->getMessage(), $e->getTraceAsString());
- return XML::error('failed', '16', 'The service is temporarily unavailable, please try again.');
- }
- }
- $tracks_array[$i] = $t;
- }
- $adodb->CompleteTrans();
- // Check if forwarding is enabled before looping through array
- $params = array($userid);
- $query = 'SELECT userid FROM Service_Connections WHERE userid = ? AND forward = 1';
- $forward_enabled = $adodb->CacheGetOne(600, $query, $params);
- if ($forward_enabled) {
- for ($i = 0; $i < count($tracks_array); $i++) {
- $t = $tracks_array[$i];
- if ($t['ignored_code'] === 0) {
- /* Forward scrobbles, we are forwarding unmodified input submitted by user,
- * but only the scrobbles that passed our ignore filters, see prepareTrack(). */
- forwardScrobble($userid,
- $t['artist_old'],
- $t['album_old'],
- $t['track_old'],
- $t['timestamp_old'],
- $t['mbid_old'],
- '',
- '',
- $t['duration_old']);
- }
- }
- }
- // Build xml
- $xml = new SimpleXMLElement('<lfm status="ok"></lfm>');
- $root = $xml->addChild('scrobbles', null);
- for ($i = 0; $i < count($tracks_array); $i++) {
- $t = $tracks_array[$i];
- $scrobble = $root->addChild('scrobble', null);
- $track_node = $scrobble->addChild('track', repamp($t['track']));
- $track_node->addAttribute('corrected', $t['track_corrected']);
- $artist_node = $scrobble->addChild('artist', repamp($t['artist']));
- $artist_node->addAttribute('corrected', $t['artist_corrected']);
- $album_node = $scrobble->addChild('album', repamp($t['album']));
- $album_node->addAttribute('corrected', $t['album_corrected']);
- $albumartist_node = $scrobble->addChild('albumArtist', repamp($t['albumartist']));
- $albumartist_node->addAttribute('corrected', $t['albumartist_corrected']);
- $scrobble->addChild('timestamp', $t['timestamp']);
- $ignoredmessage_node = $scrobble->addChild('ignoredMessage', $t['ignored_message']);
- $ignoredmessage_node->addAttribute('code', $t['ignored_code']);
- if ($t['ignored_code'] === 0) {
- $accepted_count += 1;
- } else {
- $ignored_count += 1;
- }
- }
- $root->addAttribute('accepted', $accepted_count);
- $root->addAttribute('ignored', $ignored_count);
- return $xml;
- }
- }
|