git.gnu.io has moved to IP address 209.51.188.249 -- please double check where you are logging in.

Commit 00fc869e authored by Jonas Haraldsson's avatar Jonas Haraldsson

Use 2.0 scrobble-utils.php for 1.2

Changed 1.2 nowplaying to use 2.0 functions
Changed 1.2 scrobble to use 2.0 functions
Move useridFromSID function to temp-utils.php for now
Delete 1.x/scrobble-utils.php
parent 75a45b26
......@@ -20,7 +20,7 @@
require_once($_SERVER['DOCUMENT_ROOT'] . '/config.php');
require_once($install_path . 'database.php');
require_once($install_path . '1.x/scrobble-utils.php');
require_once($install_path . 'scrobble-utils.php');
require_once($install_path . '1.x/auth-utils.php');
header('Content-Type: text/plain');
......@@ -29,74 +29,57 @@ if (!isset($_POST['s']) || !isset($_POST['a']) || !isset($_POST['t'])) {
die("FAILED Required POST parameters are not set\n");
}
//trim parameters
$session_id = trim($_POST['s']);
$artist = trim($_POST['a']);
$artist = noSpamTracks($artist);
$track = trim($_POST['t']);
$track = noSpamTracks($track);
if (empty($session_id) || empty($artist) || empty($track)) {
die("FAILED Required POST parameters are empty\n");
$sessionid = trim($_POST['s']);
if (!check_session($adodb->qstr($sessionid))) {
die("BADSESSION\n");
}
if (isset($_POST['b'])) {
$album = trim($_POST['b']);
$album = noSpamTracks($album);
}
if (empty($album)) {
$album = 'NULL';
}
$t = array(
'artist' => $_POST['a'],
'track' => $_POST['t'],
'album' => $_POST['b'],
'tracknumber' => $_POST['n'],
'mbid' => $_POST['m'],
'duration' => $_POST['l'],
'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) {}
if (isset($_POST['l']) && is_numeric($_POST['l'])) {
$length = (int) $_POST['l'];
if ($length > 5400) {
$expires = time() + 600;
} else {
$expires = time() + (int) $_POST['l'];
}
// 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() + 250; //Expire in 5 minutes if we don't know the track length
}
$mbid = validateMBID($_POST['m']);
if (!$mbid) {
$mbid = 'NULL';
$expires = time() + $t['duration'];
}
//quote strings
$session_id = $adodb->qstr($session_id);
$artist = $adodb->qstr($artist);
$track = $adodb->qstr($track);
if($album != 'NULL') {
$album = $adodb->qstr($album);
}
if ($mbid != 'NULL') {
$mbid = $adodb->qstr($mbid);
}
//Delete this user's last playing song (if any)
$adodb->Execute('DELETE FROM Now_Playing WHERE sessionid = ' . ($session_id));
if (!check_session($session_id)) {
die("BADSESSION\n");
}
try {
$adodb->Execute('INSERT INTO Now_Playing (sessionid, artist, album, track, expires, mbid) VALUES ('
. $session_id . ', '
. $artist . ', '
. $album . ', '
. $track . ', '
. $expires . ', '
. $mbid . ')');
} catch (Exception $e) {
die('FAILED ' . $e->getMessage() . "\n");
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());
die('FAILED');
}
$adodb->CompleteTrans();
}
getTrackCreateIfNew($artist, $album, $track, $mbid);
//Expire old tracks
$adodb->Execute('DELETE FROM Now_Playing WHERE expires < ' . time());
die("OK\n");
<?php
/* GNUkebox -- a free software server for recording your 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($_SERVER['DOCUMENT_ROOT'] . '/config.php');
require_once($install_path . 'database.php');
require_once($install_path . 'temp-utils.php');
function useridFromSID($session_id) {
//derive the username from a session ID
global $adodb; // include the Database connector
// Delete any expired session ids
$adodb->Execute('DELETE FROM Scrobble_Sessions WHERE expires < ' . time());
try {
$res = $adodb->GetOne('SELECT userid FROM Scrobble_Sessions WHERE sessionid = ' . $adodb->qstr($session_id)); // get the username from the table
} catch (Exception $e) {
die('FAILED ufs ' . $e->getMessage() . '\n');
// die is there is an error, printing the error
}
if (!$res) {
die("BADSESSION\n");
// the user has no session
}
return $res;
// return the first user
}
function createArtistIfNew($artist) {
global $adodb;
$id = $adodb->GetOne('SELECT id FROM Artist WHERE lower(name) = lower(' . $artist . ')');
if (!$id) {
// Artist doesn't exist, so we create them
$res = $adodb->Execute('INSERT INTO Artist (name) VALUES (' . $artist . ')');
}
}
function createAlbumIfNew($artist, $album) {
global $adodb;
$id = $adodb->GetOne('SELECT id FROM Album WHERE lower(name) = lower(' . $album . ') AND lower(artist_name) = lower(' . $artist . ')');
if (!$id) {
// Album doesn't exist, so create it
// First check if artist exist, if not create it
createArtistIfNew($artist);
// Disable to fix scrobble breakage
//$art = $adodb->qstr(getAlbumArt($artist, $album));
$art = '';
if ($art != '') {
$license = $adodb->qstr('amazon');
$sql = 'INSERT INTO Album (name, artist_name, image, artwork_license) VALUES (' . $album . ', ' . $artist . ', ' . $art . ', ' . $license .')';
} else {
$sql = 'INSERT INTO Album (name, artist_name) VALUES (' . $album . ', ' . $artist . ')';
}
$adodb->Execute($sql);
}
}
function getTrackCreateIfNew($artist, $album, $track, $mbid) {
global $adodb;
if ($album != 'NULL') {
$res = $adodb->GetOne('SELECT id FROM Track WHERE lower(name) = lower(' . $track . ') AND lower(artist_name) = lower(' . $artist . ') AND lower(album_name) = lower(' . $album . ')');
} else {
$res = $adodb->GetOne('SELECT id FROM Track WHERE lower(name) = lower(' . $track . ') AND lower(artist_name) = lower(' . $artist . ') AND album_name IS NULL');
}
if (!$res) {
// First check if artist and album exists, if not create them
if ($album != 'NULL') {
createAlbumIfNew($artist, $album);
} else {
createArtistIfNew($artist);
}
// Create new track
$res = $adodb->Execute('INSERT INTO Track (name, artist_name, album_name, mbid) VALUES ('
. $track . ', '
. $artist . ', '
. $album . ', '
. $mbid . ')');
return getTrackCreateIfNew($artist, $album, $track, $mbid);
} else {
return $res;
}
}
function getScrobbleTrackCreateIfNew($artist, $album, $track, $mbid) {
global $adodb;
$res = $adodb->GetOne('SELECT id FROM Scrobble_Track WHERE name = lower('
. $track . ') AND artist = lower(' . $artist . ') AND album '
. (($album == 'NULL') ? 'IS NULL' : ('= lower(' . $album . ')')) . ' AND mbid '
. (($mbid == 'NULL') ? 'IS NULL' : ('= lower(' . $mbid . ')')));
if (!$res) {
// First check if track exists, if not create it
$tid = getTrackCreateIfNew($artist, $album, $track, $mbid);
$sql = 'INSERT INTO Scrobble_Track (name, artist, album, mbid, track) VALUES ('
. 'lower(' . $track . '), '
. 'lower(' . $artist . '), '
. (($album == 'NULL') ? 'NULL' : 'lower(' . $album . ')') . ', '
. (($mbid == 'NULL') ? 'NULL' : 'lower(' . $mbid . ')') . ', '
. $tid . ')';
$res = $adodb->Execute($sql);
return getScrobbleTrackCreateIfNew($artist, $album, $track, $mbid);
} else {
return $res;
}
}
function scrobbleExists($userid, $artist, $track, $time) {
global $adodb;
$res = $adodb->GetOne('SELECT time FROM Scrobbles WHERE userid = ' . $userid . ' AND artist = ' . $artist . ' AND track = ' . $track . ' AND time = ' . $time);
if (!$res) {
return false;
} else {
return true;
}
}
function noSpamTracks($track) {
// This function exists to remove things like '(PREVIEW: buy it at www.magnatune.com)' from track names.
$track = str_replace(' (PREVIEW: buy it at www.magnatune.com)', '', $track);
return $track;
}
function getAlbumArt($artist, $album) {
$Access_Key_ID = '1EST86JB355JBS3DFE82'; // this is mattl's personal key :)
$SearchIndex = 'Music';
$Keywords = rawurlencode($artist . ' ' . $album);
$Operation = 'ItemSearch';
$Version = '2007-07-16';
$ResponseGroup = 'ItemAttributes,Images';
$request = 'http://ecs.amazonaws.com/onca/xml'
. '?Service=AWSECommerceService'
. '&AssociateTag=' . $Associate_tag
. '&AWSAccessKeyId=' . $Access_Key_ID
. '&Operation=' . $Operation
. '&Version=' . $Version
. '&SearchIndex=' . $SearchIndex
. '&Keywords=' . $Keywords
. '&ResponseGroup=' . $ResponseGroup;
$aws_xml = simplexml_load_file($request) or die('xml response not loading\n');
$image = $aws_xml->Items->Item->MediumImage->URL;
$URI = $aws_xml->Items->Item->DetailPageURL;
return $image;
}
function validateMBID($input) {
if (isset($input)) {
$input = strtolower(rtrim($input));
if (preg_match('/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/', $input)) {
return $input;
} else {
return null;
}
} else {
return null;
}
}
/**
* Sends a scrobble on to any other services the user has connected to their account
*/
function forwardScrobble($userid, $artist, $album, $track, $time, $mbid, $source, $rating, $length) {
global $adodb, $lastfm_key, $lastfm_secret;
$artist = rawurlencode($artist);
$track = rawurlencode($track);
$album = rawurlencode($album);
$mbid = rawurlencode($mbid);
$source = rawurlencode($source);
$rating = rawurlencode($rating);
$length = rawurlencode($length);
$res = $adodb->CacheGetAll(600, 'SELECT * FROM Service_Connections WHERE userid = ' . $userid . ' AND forward = 1');
foreach ($res as &$row) {
$remote_key = $row['remote_key'];
$ws_url = $row['webservice_url'];
$curl_session = curl_init($ws_url);
$post_vars = '';
if ($album) {
$post_vars .= 'album[0]=' . $album . '&';
}
$post_vars .= 'api_key=' . $lastfm_key . '&artist[0]=' . $artist;
if ($length) {
$post_vars .= '&length[0]=' . $length;
}
if ($mbid) {
$post_vars .= '&mbid[0]=' . $mbid;
}
$post_vars .= '&method=track.scrobble';
if ($rating) {
$post_vars .= '&rating[0]=' . $rating;
}
$post_vars .= '&sk=' . $remote_key;
if ($source) {
$post_vars .= '&source[0]='. $source;
}
$post_vars .= '&timestamp[0]=' . $time . '&track[0]=' . $track;
$sig = urldecode(str_replace('&', '', $post_vars));
$sig = str_replace('=', '', $sig);
$sig = md5($sig . $lastfm_secret);
$post_vars .= '&api_sig=' . $sig;
curl_setopt($curl_session, CURLOPT_POST, true);
curl_setopt($curl_session, CURLOPT_POSTFIELDS, $post_vars);
curl_setopt($curl_session, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl_session, CURLOPT_CONNECTTIMEOUT, 1);
curl_setopt($curl_session, CURLOPT_TIMEOUT, 1);
$response = curl_exec($curl_session);
curl_close($curl_session);
}
}
......@@ -16,10 +16,12 @@
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($_SERVER['DOCUMENT_ROOT'] . '/config.php');
require_once($install_path . 'database.php');
require_once($install_path . '1.x/scrobble-utils.php');
require_once($install_path . 'scrobble-utils.php');
require_once($install_path . 'temp-utils.php');
if (!isset($_POST['s']) || !isset($_POST['a']) || !isset($_POST['t']) || !isset($_POST['i'])) {
die("FAILED Required POST parameters are not set\n");
......@@ -35,197 +37,130 @@ if (!is_array($_POST['a']) || !is_array($_POST['t']) || !is_array($_POST['i']))
$session_id = $_POST['s'];
$userid = useridFromSID($session_id);
$rowvalues = array();
$forwardvalues = array();
$actualcount = 0;
$timeisstupid = 0;
for ($i = 0; $i < count($_POST['a']); $i++) {
if (!isset($_POST['t'][$i]) || !isset($_POST['a'][$i]) || !isset($_POST['i'][$i])) {
$f = isset($_POST['t'][$i]) ? "T({$_POST['t'][$i]})" : 't';
$f .= isset($_POST['a'][$i]) ? "A({$_POST['a'][$i]})" : 'a';
$f .= isset($_POST['i'][$i]) ? "I({$_POST['i'][$i]})" : 'i';
//Add error message to db and skip to next scrobble
reportError("FAILED Track $i was submitted with empty mandatory field(s)",
"artist:{$_POST['a'][$i]}, album:{$_POST['b'][$i]}, track:{$_POST['t'][$i]}, time:{$_POST['i'][$i]}");
continue;
}
$artist = trim($_POST['a'][$i]);
$artist = noSpamTracks($artist);
if (empty($artist)) {
//Add error message to db and skip to next scrobble
reportError("FAILED Track $i was submitted with empty artist field",
"artist:{$_POST['a'][$i]}, album:{$_POST['b'][$i]}, track:{$_POST['t'][$i]}, time:{$_POST['i'][$i]}");
continue;
} else {
switch (mb_detect_encoding($artist)) {
case 'ASCII':
case 'UTF-8':
$artist = $adodb->qstr(trim(mb_strcut($artist, 0, 255, 'UTF-8')));
break;
default:
die("FAILED Bad encoding in artist submission $i\n");
}
}
$track = trim($_POST['t'][$i]);
$track = noSpamTracks($track);
if (empty($track)) {
//Add error message to db and skip to next scrobble
reportError("FAILED Track $i was submitted with empty track field",
"artist:{$_POST['a'][$i]}, album:{$_POST['b'][$i]}, track:{$_POST['t'][$i]}, time:{$_POST['i'][$i]}");
continue;
} else {
switch (mb_detect_encoding($track)) {
case 'ASCII':
case 'UTF-8':
$track = $adodb->qstr(trim(mb_strcut($track, 0, 255, 'UTF-8')));
break;
default:
die("FAILED Bad encoding in title submission $i\n");
}
}
if (is_numeric($_POST['i'][$i])) {
$time = (int) $_POST['i'][$i];
$artist = $_POST['a'];
$track = $_POST['t'];
$timestamp = $_POST['i'];
//$source = $_POST['o'];
//$rating = $_POST['r'];
$duration = $_POST['l'];
$album = $_POST['b'];
$tracknumber = $_POST['n'];
$mbid = $_POST['m'];
// Convert timestamps to unix time if needed
for ($i = 0; $i < count($timestamp); $i++) {
if (is_numeric($timestamp[$i])) {
$timestamp[$i] = (int) $timestamp[$i];
} else {
// 1.1 time format
date_default_timezone_set('UTC');
$time = strtotime($_POST['i'][$i]);
}
$album = trim($_POST['b'][$i]);
$album = noSpamTracks($album);
if (!empty($album)) {
switch (mb_detect_encoding($album)) {
case 'ASCII':
case 'UTF-8':
$album = $adodb->qstr(trim(mb_strcut($album, 0, 255, 'UTF-8')));
break;
default:
die("FAILED Bad encoding in album submission $i\n");
}
} else {
$album = 'NULL';
}
$mb = validateMBID($_POST['m'][$i]);
if ($mb) {
$mbid = $adodb->qstr($mb);
} else {
$mbid = 'NULL';
$timestamp[$i] = strtotime($timestamp[$i]);
}
}
if (isset($_POST['o'][$i])) {
$source = $adodb->qstr($_POST['o'][$i]);
} else {
$source = 'NULL';
}
if (!empty($_POST['r'][$i])) {
$rating = $adodb->qstr($_POST['r'][$i]);
} else {
$rating = $adodb->qstr('0'); // use the fake rating code 0 for now
}
if (isset($_POST['l'][$i])) {
$length = (int)($_POST['l'][$i]);
} else {
$length = 'NULL';
$tracks_array = 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,
);
}
if (($time - time()) > 300) {
die("FAILED Submitted track has timestamp in the future\n"); // let's try a 5-minute tolerance
}
if ($time <= 1009000000) {
$timeisstupid = 1;
}
// 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');
}
$failed = false;
try {
$exists = scrobbleExists($userid, $artist, $track, $time);
if (!$exists) {
$stid = getScrobbleTrackCreateIfNew($artist, $album, $track, $mbid);
$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());
die('FAILED');
}
} catch (Exception $ex) {
$failed = true;
reportError($ex->getMessage(), '');
}
if (!$exists && $rating != 'S' && !$failed) {
$rowvalues[$actualcount] = '('
. $userid . ', '
. $artist . ', '
. $album . ', '
. $track . ', '
. $time . ', '
. $mbid . ', '
. $source . ','
. $rating . ','
. $length . ','
. $stid . ')';
// Create array with tracks to be forwarded
if (isset($lastfm_key)) {
$forwardvalues[$actualcount] = array(
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,
$_POST['a'][$i],
$_POST['b'][$i],
$_POST['t'][$i],
$time,
$_POST['m'][$i],
$_POST['o'][$i],
$_POST['r'][$i],
$_POST['l'][$i]
$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());
die('FAILED');
}
$actualcount++;
}
if (($i + 1) == count($_POST['a'])) {
if ($actualcount > 0) {
$adodb->StartTrans();
for ($j = 0; $j < $actualcount; $j++) {
// Scrobble!
$sql = 'INSERT INTO Scrobbles (userid, artist, album, track, time, mbid, source, rating, length, stid) VALUES ' . $rowvalues[$j];
try {
$res =& $adodb->Execute($sql);
if (isset($lastfm_key)) {
call_user_func_array("forwardScrobble", $forwardvalues[$j]);
}
} catch (Exception $e) {
$msg = $e->getMessage();
$adodb->FailTrans();
$adodb->CompleteTrans();
reportError($msg, $sql);
}
}
try {
$adodb->CompleteTrans();
} catch (Exception $e) {
die('FAILED ' . $e->getMessage() . "\n");
}
} else {
if ($timeisstupid == 1) {
die("FAILED Too many submitted tracks with invalid timestamps\n");
}
$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'],
null,
null,
$t['duration_old']);
}
}
}
die("OK\n");
......@@ -48,3 +48,26 @@ function uniqueid_to_username($uniqueid) {
return $username;
}
function useridFromSID($session_id) {
//derive the username from a session ID
global $adodb; // include the Database connector
// Delete any expired session ids
$adodb->Execute('DELETE FROM Scrobble_Sessions WHERE expires < ' . time());
try {
$res = $adodb->GetOne('SELECT userid FROM Scrobble_Sessions WHERE sessionid = ' . $adodb->qstr($session_id)); // get the username from the table
} catch (Exception $e) {
die('FAILED ufs ' . $e->getMessage() . '\n');
// die is there is an error, printing the error