%PDF- %PDF-
| Direktori : /data/www_bck/varak.net_bck/gnufm.varak.net/api/ |
| Current File : //data/www_bck/varak.net_bck/gnufm.varak.net/api/TrackXML.php |
<?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;
}
}