A few miscellaneous fixes including modifying WebServer to write data in chunks (improved performance and reliability on a slow connection)
<?php
/**
* Action servlet (play, pause, etc.)
*
* Greyhound - real web management for Amarok
* Copyright (C) 2008 Dan Fuhry
*
* This program is Free Software; you can redistribute 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 details.
*/
status('initializing Services_JSON');
$json = new Services_JSON(SERVICES_JSON_LOOSE_TYPE);
// keep track of playlist refresh
$playlist_last_refresh = time();
/**
* Terminate a request with an error string formatted as JSON.
* @param string Error message
*/
function json_die($msg)
{
global $json;
echo $json->encode(array(
'mode' => 'error',
'error' => $msg
));
return true;
}
function ajax_request_handler($httpd, $socket)
{
global $playlist, $mime_types, $json, $allowcontrol;
global $use_auth, $auth_data;
if ( !session_check() )
return true;
// Set content type
$httpd->header("Content-type: {$mime_types['js']}");
// get PATH_INFO
$pathinfo = @substr(@substr($_SERVER['REQUEST_URI'], 1), @strpos(@substr($_SERVER['REQUEST_URI'], 1), '/')+1);
if ( empty($pathinfo) )
{
return json_die('No action specified on URI');
}
$params = explode('/', $pathinfo);
$action =& $params[0];
switch ( $action )
{
case 'stop':
case 'next':
case 'prev':
if ( !$allowcontrol )
return false;
echo dcop_action('player', $action);
break;
case 'play':
if ( !$allowcontrol )
return false;
echo dcop_action('player', 'playPause');
break;
case 'jump':
if ( !$allowcontrol )
return false;
$tid =& $params[1];
if ( !preg_match('/^[0-9]+$/', $tid) )
{
return json_die('Invalid track ID');
}
$tid = intval($tid);
dcop_action('playlist', "playByIndex $tid");
$return = array(
'current_track_length' => $playlist[$tid]['length_int'],
'current_track_pos' => 0,
'current_track_title' => $playlist[$tid]['title'],
'current_track_album' => $playlist[$tid]['album'],
'current_track_artist' => $playlist[$tid]['artist']
);
echo $json->encode($return);
break;
case 'volume':
if ( !$allowcontrol )
return false;
$volume =& $params[1];
if ( !preg_match('/^[0-9]+$/', $volume) )
{
return json_die('Invalid track ID');
}
$volume = intval($volume);
dcop_action('player', "setVolume $volume");
$return = array(
'volume' => $volume
);
echo $json->encode($return);
break;
case 'seek':
if ( !$allowcontrol )
return false;
$pos =& $params[1];
if ( !preg_match('/^[0-9]+$/', $pos) )
{
return json_die('Invalid track ID');
}
$pos = intval($pos);
dcop_action('player', "seek $pos");
break;
case 'refresh':
global $playlist_last_refresh, $playlist, $playlist_last_md5;
if ( $playlist_last_refresh + 60 < time() )
{
rebuild_playlist();
}
$current_track = dcop_action('playlist', 'getActiveIndex');
$current_time = dcop_action('player', 'trackCurrentTime');
$is_playing = dcop_action('player', 'isPlaying');
$return = array(
'is_playing' => $is_playing,
'is_paused' => $current_time > 0 && !$is_playing,
'current_track' => $current_track,
'volume' => dcop_action('player', 'getVolume'),
// include the MD5 of the playlist so that if it changes, the
// client can refresh (otherwise things get madly corrupted)
'playlist_hash' => $playlist_last_md5,
'current_track_title' => false,
'current_track_album' => false,
'current_track_artist' => false
);
if ( isset($playlist[$current_track]) )
{
$return['current_track_length'] = $playlist[$current_track]['length_int'];
$return['current_track_pos'] = $current_time;
$return['current_track_title'] = $playlist[$current_track]['title'];
$return['current_track_artist'] = $playlist[$current_track]['artist'];
$return['current_track_album'] = $playlist[$current_track]['album'];
}
echo $json->encode($return);
break;
default:
return json_die("Undefined action: $action");
}
}
function api_request_handler($httpd, $socket)
{
global $json;
$httpd->header('Content-type: text/javascript');
if ( !isset($_POST['request']) )
{
return json_die("No request specified on POST.");
}
$req = $json->decode($_POST['request']);
if ( !isset($req['action']) )
{
return json_die("No action specified.");
}
switch($req['action'])
{
case 'check_login':
global $use_auth, $auth_data;
if ( $use_auth )
{
$return = array(
'need_login' => true
);
if ( isset($req['username']) && isset($req['password']) )
{
$return['auth_valid'] = ( isset($auth_data[$req['username']]) && $auth_data[$req['username']] === $req['password'] );
}
}
else
{
$return = array(
'need_login' => false,
'auth_valid' => true
);
}
break;
case 'login':
global $use_auth, $auth_data;
if ( $use_auth )
{
if ( !isset($req['username']) || !isset($req['password']) )
{
return json_die("Username or password not provided");
}
if ( $session = login($req['username'], $req['password']) )
{
$return = array(
'need_login' => true,
'login_cookie' => $session
);
}
else
{
$return = array(
'need_login' => true,
'login_cookie' => false
);
}
}
else
{
$return = array(
'need_login' => false,
'login_cookie' => false
);
}
break;
default:
return json_die("Undefined action '{$req['action']}'.");
break;
}
echo $json->encode($return);
}