--- a/functions.php Fri Aug 15 23:31:37 2008 -0400
+++ b/functions.php Fri Aug 15 23:49:00 2008 -0400
@@ -24,23 +24,39 @@
function burnout($msg)
{
+ global $use_colors;
$h = @fopen('php://stderr', 'w');
- fwrite($h, "\x1B[31;1m[Greyhound] fatal: \x1B[37;1m");
- fwrite($h, "$msg\x1B[0m\n");
+ if ( $use_colors )
+ {
+ fwrite($h, "\x1B[31;1m[Greyhound] fatal: \x1B[37;1m");
+ fwrite($h, "$msg\x1B[0m\n");
+ }
+ else
+ {
+ fwrite($h, "[Greyhound] fatal: $msg\n");
+ }
fclose($h);
exit(1);
}
/**
- * Print a stylized status message, compatible with Linux consoles
+ * Print a stylized status message, compatible with Linux consoles. Falls back to no control characters if on unsupported terminal.
* @param string Status message
*/
function status($msg)
{
+ global $use_colors;
$h = @fopen('php://stderr', 'w');
$label = ( defined('HTTPD_WS_CHILD') ) ? 'Child ' . substr(strval(getmypid()), -3) : 'Greyhound';
- fwrite($h, "\x1B[32;1m[$label] \x1B[32;0m$msg\x1B[0m\n");
+ if ( $use_colors )
+ {
+ fwrite($h, "\x1B[32;1m[$label] \x1B[32;0m$msg\x1B[0m\n");
+ }
+ else
+ {
+ fwrite($h, "[$label] $msg\n");
+ }
fclose($h);
}
@@ -51,8 +67,16 @@
function warning($msg)
{
+ global $use_colors;
$h = @fopen('php://stderr', 'w');
- fwrite($h, "\x1B[33;1m[Greyhound] \x1B[0m\x1B[33mWarning:\x1B[0m $msg\n");
+ if ( $use_colors )
+ {
+ fwrite($h, "\x1B[33;1m[Greyhound] \x1B[0m\x1B[33mWarning:\x1B[0m $msg\n");
+ }
+ else
+ {
+ fwrite($h, "[Greyhound] Warning: $msg\n");
+ }
fclose($h);
}
--- a/greyhound.php Fri Aug 15 23:31:37 2008 -0400
+++ b/greyhound.php Fri Aug 15 23:49:00 2008 -0400
@@ -37,7 +37,7 @@
// set this to false, it will only display the playlist.
$allowcontrol = true;
// The default theme. This should be a name of a directory in ./themes.
-$theme = 'funkymonkey';
+$theme = 'grey';
// Allow forking when an HTTP request is received. This has advantages
// and disadvantages. If this experimental option is enabled, it will
// result in faster responses and load times but more memory usage.
@@ -64,6 +64,9 @@
// create directories
@mkdir('./compiled');
+// what kind of terminal do we have?
+$use_colors = ( @in_array(@$_SERVER['TERM'], array('linux', 'xterm', 'vt100')) ) ? true : false;
+
// start up...
status('Starting Greyhound Web Control v0.1a3');
@@ -85,6 +88,18 @@
exit(0);
}
+status('doing PHP capabilities check');
+if ( !function_exists('pcntl_signal') )
+{
+ warning('System does not support POSIX functions. Termination signals will result in unclean shutdown.');
+}
+
+if ( !function_exists('simplexml_load_file') )
+{
+ warning('Can\'t find support for SimpleXML, which is needed to parse the Amarok playlist file.');
+ burnout('SimpleXML required to continue. You may have an outdated version of PHP; most versions of PHP 5 have SimpleXML built-in. Check your distribution\'s documentation to find out how to enable PHP\'s SimpleXML support.');
+}
+
status('initializing playlist');
// init playlist object
@@ -99,11 +114,6 @@
try
{
status('starting PhpHttpd');
- status('doing PHP capabilities check');
- if ( !function_exists('pcntl_signal') )
- {
- warning('System does not support POSIX functions. Termination signals will result in unclean shutdown.');
- }
$httpd = new WebServer($ip, $port);
// setup handlers
@@ -143,6 +153,10 @@
}
catch( Exception $e )
{
+ if ( strstr(strval($e), "Could not bind") )
+ {
+ burnout("Could not bind to the port $ip:$port. Is Greyhound already running? Sometimes browsers don't close off their connections until Greyhound has been dead for about a minute, so try starting Greyhound again in roughly 60 seconds. If that doesn't work, type \"killall -9 php\" at a terminal and try starting Greyhound again in 60 seconds.");
+ }
burnout("Exception caught while running webserver:\n$e");
}
Binary file themes/grey/images/ajax.gif has changed
Binary file themes/grey/images/amarok.gif has changed
Binary file themes/grey/images/next.png has changed
Binary file themes/grey/images/pause.png has changed
Binary file themes/grey/images/play.png has changed
Binary file themes/grey/images/playbar-shadow.gif has changed
Binary file themes/grey/images/playbar.gif has changed
Binary file themes/grey/images/playhead.png has changed
Binary file themes/grey/images/position-empty.png has changed
Binary file themes/grey/images/position-full.png has changed
Binary file themes/grey/images/prev.png has changed
Binary file themes/grey/images/src/playbar-shadow.xcf has changed
Binary file themes/grey/images/src/playbar.xcf has changed
Binary file themes/grey/images/src/playhead.xcf has changed
Binary file themes/grey/images/src/position-empty.xcf has changed
Binary file themes/grey/images/src/position-full.xcf has changed
Binary file themes/grey/images/stop.png has changed
Binary file themes/grey/images/volume.png has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/themes/grey/playlist.tpl Fri Aug 15 23:49:00 2008 -0400
@@ -0,0 +1,92 @@
+{**
+ * Template file for default Funky Monkey theme
+ * Web control interface script for Amarok
+ * Written by Dan Fuhry - 2008
+ *
+ * This script is in the public domain. Use it for good, not evil.
+ *}
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html>
+ <head>
+ <title>AmaroK playlist</title>
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
+ <link rel="stylesheet" type="text/css" href="/themes/{$theme|escape}/style.css" />
+ <link rel="favorite icon" type="image/ico" href="/favicon.ico" />
+ <script type="text/javascript">
+ var img_play = '/themes/{$theme|escape}/images/play.png';
+ var img_pause = '/themes/{$theme|escape}/images/pause.png';
+ var img_ajax = '/themes/{$theme|escape}/images/ajax.gif';
+ var class_current = 'current';
+ var allow_control = {if $allow_control}true{else}false{/if};
+ </script>
+ {foreach from=$scripts item=script}
+ <script type="text/javascript" src="/scripts/{$script}"></script>
+ {/foreach}
+ </head>
+ <body>
+ <div id="playbar">
+ <div class="playbar-inner">
+ <div id="playhead"><div id="playhead-filler"> </div></div>
+ <div id="playhead-button"> </div>
+ <img alt=" " id="ajax_status" style="display: none; float: right; margin: 3px 0;" src="about:blank" />
+ <img alt="AmaroK web control" src="/themes/{$theme|escape}/images/amarok.gif" style="margin-right: 20px;" />
+ {if $allow_control}
+ <a href="#action:prev" onclick="player_action('prev'); return false;"><img alt="« PrevTrk" src="/themes/{$theme|escape}/images/prev.png" /></a>
+ <a href="#action:play" onclick="player_action('play'); return false;" id="btn_playpause"><img alt="Play" src="/themes/{$theme|escape}/images/play.png" /></a>
+ <a href="#action:stop" onclick="player_action('stop'); return false;"><img alt="Stop" src="/themes/{$theme|escape}/images/stop.png" /></a>
+ <a href="#action:next" onclick="player_action('next'); return false;"><img alt="NextTrk »" src="/themes/{$theme|escape}/images/next.png" /></a>
+ {/if}
+ <span style="margin-right: 50px;"> </span>
+ <span id="playmeter">--:--/--:--</span>
+ {if $allow_control}
+ <span style="margin-right: 50px;"> </span>
+ <img hspace="4" alt="Volume: " src="/themes/{$theme|escape}/images/volume.png" />
+ <span id="volume_wrap"><a
+ class="volume_button" href="#volume:0" onmouseover="volume_over(0);" onmouseout="volume_out();" id="volbtn_0" onclick="set_volume(0); return false;"> </a><a
+ class="volume_button" href="#volume:10" onmouseover="volume_over(10);" onmouseout="volume_out();" id="volbtn_10" onclick="set_volume(10); return false;"> </a><a
+ class="volume_button" href="#volume:20" onmouseover="volume_over(20);" onmouseout="volume_out();" id="volbtn_20" onclick="set_volume(20); return false;"> </a><a
+ class="volume_button" href="#volume:30" onmouseover="volume_over(30);" onmouseout="volume_out();" id="volbtn_30" onclick="set_volume(30); return false;"> </a><a
+ class="volume_button" href="#volume:40" onmouseover="volume_over(40);" onmouseout="volume_out();" id="volbtn_40" onclick="set_volume(40); return false;"> </a><a
+ class="volume_button" href="#volume:50" onmouseover="volume_over(50);" onmouseout="volume_out();" id="volbtn_50" onclick="set_volume(50); return false;"> </a><a
+ class="volume_button" href="#volume:60" onmouseover="volume_over(60);" onmouseout="volume_out();" id="volbtn_60" onclick="set_volume(60); return false;"> </a><a
+ class="volume_button" href="#volume:70" onmouseover="volume_over(70);" onmouseout="volume_out();" id="volbtn_70" onclick="set_volume(70); return false;"> </a><a
+ class="volume_button" href="#volume:80" onmouseover="volume_over(80);" onmouseout="volume_out();" id="volbtn_80" onclick="set_volume(80); return false;"> </a><a
+ class="volume_button" href="#volume:90" onmouseover="volume_over(90);" onmouseout="volume_out();" id="volbtn_90" onclick="set_volume(90); return false;"> </a><a
+ class="volume_button" href="#volume:100" onmouseover="volume_over(100);" onmouseout="volume_out();" id="volbtn_100" onclick="set_volume(100); return false;"> </a>
+ </span>
+ {/if}
+ </div>
+ </div>
+ <div class="tblholder" id="playlist">
+ <table border="0" cellspacing="1" cellpadding="4" style="width: 100%;">
+ <tr>
+ <th>TrackNo</th>
+ <th>Track</th>
+ <th>Artist</th>
+ <th>Album</th>
+ <th>Length</th>
+ </tr>
+ {foreach key=tid item=track from=$playlist}
+ {strip}
+ <tr class="{cycle values="row1,row2"}{if $active == $tid} current{/if}" id="track_{$tid}" amarok:length_sec="{$track.length_int}">
+ <td style="text-align: center;">{$tid+1}</td>
+ <td>
+ <a class="tracklink" href="#action:jump;tid:{$tid}" onclick="jump_to_song({$tid}); return false;">
+ {$track.title|escape}
+ </a>
+ </td>
+ <td>{$track.artist|escape}</td>
+ <td>{$track.album|escape}</td>
+ <td style="text-align: center;">{$track.length|escape}</td>
+ </tr>
+ {/strip}
+ {/foreach}
+ </table>
+ </div>
+ <div class="poweredby">
+ Powered by <a onclick="window.open(this.href); return false;" href="http://greyhound.enanocms.org/">Greyhound</a>
+ </div>
+ </body>
+</html>
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/themes/grey/style.css Fri Aug 15 23:49:00 2008 -0400
@@ -0,0 +1,146 @@
+/**
+ * Based upon the AmaroK WebControl interface by:
+ * Jonas Christian Drewsen ( kde at xspect dot dk )
+ * André Kelpe ( fs111 at web dot de )
+ * Peter C. Ndikuwera ( pndiku at gmail dot com )
+ */
+
+body {
+ font-family: sans-serif;
+ background-color: #262626;
+ color: #ffffff;
+ padding: 0 8px;
+ background-image: url(images/playbar-shadow.gif);
+ background-repeat: repeat-x;
+}
+
+div.tblholder {
+ padding: 1px;
+ background-color: #b0b0b0;
+ border: 1px solid #000000;
+}
+
+div.tblholder table {
+ background-color: #606060;
+}
+
+tr th {
+ background-color: #505050;
+}
+
+tr.row1 td {
+ background-color: #383838;
+}
+
+tr.row2 td {
+ background-color: #424242;
+}
+
+tr.current td {
+ background-color: #303030;
+ color: #ffff00;
+}
+
+div#playbar {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 32px;
+ padding: 0;
+ margin: 0;
+ background-image: url(images/playbar.gif);
+ background-repeat: repeat-x;
+ background-color: #383f61;
+ border-bottom: 1px solid #000000;
+}
+
+div.playbar-inner {
+ padding: 5px;
+ line-height: 22px;
+}
+
+a img {
+ border-width: 0;
+}
+
+div#playlist {
+ margin-top: 48px;
+}
+
+a.tracklink {
+ text-decoration: none;
+ color: white;
+}
+
+div#playlist tr.current a.tracklink {
+ color: #ffff00;
+}
+
+span#playmeter, span#volume_wrap {
+ position: relative;
+ top: -7px;
+}
+
+a.volume_button {
+ padding-right: 10px;
+ margin-right: 1px;
+ background-color: #262626;
+ border: 1px solid #909090;
+ text-decoration: none;
+}
+
+a.volume_button_active {
+ background-color: #404040;
+ border-color: #d0d0d0;
+}
+
+/* Position slider (playhead) */
+
+div#playhead {
+ background-image: url(images/position-empty.png);
+ width: 250px;
+ background-repeat: no-repeat;
+ background-position: center center;
+ float: right;
+ margin-left: 10px;
+}
+
+div#playhead-filler {
+ background-image: url(images/position-full.png);
+ width: 150px;
+ background-repeat: no-repeat;
+ background-position: left center;
+}
+
+div#playhead-button {
+ background-image: url(images/playhead.png);
+ width: 16px;
+ height: 16px;
+ font-size: 1px;
+ position: absolute;
+ background-repeat: no-repeat;
+ background-position: center center;
+}
+
+/* The list of colors that will be cycled through as playback takes place */
+tr.pulsar0 td { background-color: #303030; }
+tr.pulsar1 td { background-color: #333333; }
+tr.pulsar2 td { background-color: #363636; }
+tr.pulsar3 td { background-color: #393939; }
+tr.pulsar4 td { background-color: #3c3c3c; }
+tr.pulsar5 td { background-color: #3f3f3f; }
+tr.pulsar6 td { background-color: #424242; }
+tr.pulsar7 td { background-color: #454545; }
+tr.pulsar8 td { background-color: #484848; }
+tr.pulsar9 td { background-color: #4b4b4b; }
+
+div.poweredby {
+ font-size: smaller;
+ text-align: center;
+ margin: 10px 0;
+}
+
+div.poweredby a {
+ color: #57608a;
+}
--- a/webserver.php Fri Aug 15 23:31:37 2008 -0400
+++ b/webserver.php Fri Aug 15 23:49:00 2008 -0400
@@ -18,7 +18,7 @@
* @const string
*/
-define('HTTPD_VERSION', '0.1b1');
+define('HTTPD_VERSION', '0.1b4');
/**
* Length of keep-alive connections
@@ -33,7 +33,7 @@
define('HTTPD_ICON_SCRIPT', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAGSSURBVCjPVVFNSwJhEF78Ad79Cf6PvXQRsotUlzKICosuRYmR2RJR0KE6lBFFZVEbpFBSqKu2rum6llFS9HHI4iUhT153n6ZtIWMOM+/MM88z7wwH7s9Ub16SJcnbmrNcxVm2q7Z8/QPvEOtntpj92NkCqITLepEpjix7xQtiLOoQ2b6+E7YAN/5nfOEJ2WbKqOIOJ4bYVMEQx4LfBBQDsvFMhUcCVU1/CxVXmDBGA5ZETrhDCQVcYAPbyEJBhvrnBVPiSpNr6cYDNCQwo4zzU/ySckkgDYuNuVpI42T9k4gLKGMPs/xPzzovQiY2hQYe0jlJfyNNhTqiWDYBq/wBMcSRpnyPzu1oS7WtxjVBSthU1vgVksiQ3Dn6Gp5ah2YOKQo5GiuHPA6xT1EKpxQNCNYejgIR457KKio0S56YckjSa9jo//3mrj+BV0QQagqGTOo+Y7gZIf1puP3WHoLhEb2PjTlCTCWGXtbp8DCX3hZuOdaIc9A+aQvWk4ihq95p67a7nP+u+Ws+r0dql9z/zv0NCYhdCPKZ7oYAAAAASUVORK5CYII=');
define('HTTPD_ICON_FOLDER', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAGrSURBVDjLxZO7ihRBFIa/6u0ZW7GHBUV0UQQTZzd3QdhMQxOfwMRXEANBMNQX0MzAzFAwEzHwARbNFDdwEd31Mj3X7a6uOr9BtzNjYjKBJ6nicP7v3KqcJFaxhBVtZUAK8OHlld2st7Xl3DJPVONP+zEUV4HqL5UDYHr5xvuQAjgl/Qs7TzvOOVAjxjlC+ePSwe6DfbVegLVuT4r14eTr6zvA8xSAoBLzx6pvj4l+DZIezuVkG9fY2H7YRQIMZIBwycmzH1/s3F8AapfIPNF3kQk7+kw9PWBy+IZOdg5Ug3mkAATy/t0usovzGeCUWTjCz0B+Sj0ekfdvkZ3abBv+U4GaCtJ1iEm6ANQJ6fEzrG/engcKw/wXQvEKxSEKQxRGKE7Izt+DSiwBJMUSm71rguMYhQKrBygOIRStf4TiFFRBvbRGKiQLWP29yRSHKBTtfdBmHs0BUpgvtgF4yRFR+NUKi0XZcYjCeCG2smkzLAHkbRBmP0/Uk26O5YnUActBp1GsAI+S5nRJJJal5K1aAMrq0d6Tm9uI6zjyf75dAe6tx/SsWeD//o2/Ab6IH3/h25pOAAAAAElFTkSuQmCC');
-define('HTTPD_ICON_FILE', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAINSURBVBgZBcG/r55zGAfg6/4+z3va01NHlYgzEfE7MdCIGISFgS4Gk8ViYyM2Mdlsko4GSf8Do0FLRCIkghhYJA3aVBtEz3nP89wf11VJvPDepdd390+8Nso5nESBQoq0pfvXm9fzWf19453LF85vASqJlz748vInb517dIw6EyYBIIG49u+xi9/c9MdvR//99MPPZ7+4cP4IZhhTPbwzT2d+vGoaVRRp1rRliVvHq+cfvM3TD82+7mun0o/ceO7NT+/4/KOXjwZU1ekk0840bAZzMQ2mooqh0A72d5x/6sB9D5zYnff3PoYBoWBgFKPKqDKqjCpjKr//dcu9p489dra88cydps30KswACfNEKanSaxhlntjJ8Mv12Paie+vZ+0+oeSwwQ0Iw1xAR1CiFNJkGO4wu3ZMY1AAzBI0qSgmCNJsJUEOtJSMaCTBDLyQ0CknAGOgyTyFFiLI2awMzdEcSQgSAAKVUmAeNkxvWJWCGtVlDmgYQ0GFtgg4pNtOwbBcwQy/Rife/2yrRRVI0qYCEBly8Z+P4qMEMy7JaVw72N568e+iwhrXoECQkfH91kY7jwwXMsBx1L93ZruqrK6uuiAIdSnTIKKPLPFcvay8ww/Hh+ufeznTXu49v95IMoQG3784gYXdTqvRmqn/Wpa/ADFX58MW3L71SVU9ETgEIQQQIOOzub+fhIvwPRDgeVjWDahIAAAAASUVORK5CYII=');
+define('HTTPD_ICON_FILE', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAINSURBVBgZBcG/r55zGAfg6/4+z3va01NHlYgzEfE7MdCIGISFgS4Gk8ViYyM2Mdlsko4GSf8Do0FLRCIkghhYJA3aVBtEz3nP89wf11VJvPDepdd390+8Nso5nESBQoq0pfvXm9fzWf19453LF85vASqJlz748vInb517dIw6EyYBIIG49u+xi9/c9MdvR//99MPPZ7+4cP4IZhhTPbwzT2d+vGoaVRRp1rRliVvHq+cfvM3TD82+7mun0o/ceO7NT+/4/KOXjwZU1ekk0840bAZzMQ2mooqh0A72d5x/6sB9D5zYnff3PoYBoWBgFKPKqDKqjCpjKr//dcu9p489dra88cydps30KswACfNEKanSaxhlntjJ8Mv12Paie+vZ+0+oeSwwQ0Iw1xAR1CiFNJkGO4wu3ZMY1AAzBI0qSgmCNJsJUEOtJSMaCTBDLyQ0CknAGOgyTyFFiLI2awMzdEcSQgSAAKVUmAeNkxvWJWCGtVlDmgYQ0GFtgg4pNtOwbBcwQy/Rife/2yrRRVI0qYCEBly8Z+P4qMEMy7JaVw72N568e+iwhrXoECQkfH91kY7jwwXMsBx1L93ZruqrK6uuiAIdSnTIKKPLPFcvay8ww/Hh+ufeznTXu49v95IMoQG3784gYXdTqvRmqn/Wpa/ADFX58MW3L71SVU9ETgEIQQQIOOzub+fhIvwPRDgeVjWDahIAAAAASUVORK5CYII=');
/**
* Simple but full-featured embedded web server written in PHP.
@@ -404,6 +404,13 @@
// parse request
$client_headers = trim($client_headers);
+
+ if ( isset($last_finish_time) && empty($client_headers) && defined('HTTPD_WS_CHILD') && $last_finish_time + HTTPD_KEEP_ALIVE_TIMEOUT < microtime(true) )
+ {
+ status('[debug] keep-alive connection timed out (checkpoint 2)');
+ continue; // will jump back to the start of the loop and kill the child process
+ }
+
$client_headers = explode("\n", $client_headers);
// first line
@@ -697,7 +704,7 @@
// if ( defined('HTTPD_WS_CHILD') )
// status('Continuing connection');
// @socket_write($remote, "\r\n\r\n");
- $last_finish_time = time();
+ $last_finish_time = microtime(true);
}
else
{