Added Offline Mode - automatically turned on and off based on connectivity to server. Version bumped to 0.1a5.
--- a/greyhound.php Fri Jun 12 13:49:22 2009 -0400
+++ b/greyhound.php Fri Jun 12 13:50:13 2009 -0400
@@ -12,7 +12,7 @@
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
*/
-define('GREY_VERSION', '0.1a4');
+define('GREY_VERSION', '0.1a5');
// Try to trap termination signals to cleanly close the socket when needed
// AmaroK sends a SIGTERM when it is shut down or the user requests to stop
@@ -25,7 +25,6 @@
// trap SIGTERM
pcntl_signal(SIGTERM, 'sigterm');
pcntl_signal(SIGINT, 'sigterm');
- pcntl_signal(SIGHUP, 'handle_refresh_signal');
}
@ini_set('display_errors', 'on');
@@ -175,7 +174,10 @@
$httpd->add_handler('apple-touch-icon.png', 'file', GREY_ROOT . '/apple-touch-icon.png');
$httpd->add_handler('spacer.gif', 'file', GREY_ROOT . '/spacer.gif');
$httpd->add_handler('trans80.png', 'file', GREY_ROOT . '/trans80.png');
+ $httpd->add_handler('offlinemode.png', 'file', GREY_ROOT . '/offlinemode.png');
+ $httpd->add_handler('offlinemodelarge.png', 'file', GREY_ROOT . '/offlinemodelarge.png');
$httpd->threader->ipc_register('reloadconfig', 'grey_reload_config');
+ $httpd->threader->ipc_register('reloadplaylist', 'rebuild_playlist_ipc');
// load all themes if forking is enabled
// Themes are loaded when the playlist is requested. This is fine for
// single-threaded operation, but if the playlist handler is only loaded
@@ -212,14 +214,3 @@
burnout("Exception caught while running webserver:\n$e");
}
-function handle_refresh_signal()
-{
- global $httpd;
- if ( !is_object($httpd) )
- // we're not serving yet.
- return false;
-
- // we've got an httpd instance; rebuild the playlist
- rebuild_playlist();
-}
-
Binary file offlinemode.png has changed
Binary file offlinemodelarge.png has changed
--- a/scripts/ajax.js Fri Jun 12 13:49:22 2009 -0400
+++ b/scripts/ajax.js Fri Jun 12 13:50:13 2009 -0400
@@ -12,7 +12,7 @@
*/
var ajax;
-var is_playing = false, current_track = -1, current_track_length, current_track_pos, ct_advance_timeout = false, ct_counter = false, playlist_md5 = false, first_load = true;
+var is_playing = false, current_track = -1, current_track_length, current_track_pos, ct_advance_timeout = false, ct_counter = false, playlist_md5 = false, first_load = true, offline_mode = false;
var onload_hooks = new Array();
@@ -47,11 +47,74 @@
}
}
+// preload "offline mode" large icon
+var preload = ['/offlinemodelarge.png', 'trans80.png']
+for ( var i = 0; i < preload.length; i++ )
+{
+ var img = new Image();
+ img.src = preload[i];
+}
+
+function offline_mode_on()
+{
+ unsetAjaxLoading();
+ document.getElementById('offlinemode').style.display = 'block';
+ offline_mode = true;
+}
+
+function offline_mode_off()
+{
+ document.getElementById('offlinemode').style.display = 'none';
+ offline_mode = false;
+}
+
+function verify_online()
+{
+ if ( !offline_mode )
+ return true;
+
+ flash_offline();
+ return false;
+}
+
+function flash_offline()
+{
+ if ( document.getElementById('offlinebox') )
+ return false;
+
+ var box = document.createElement('div');
+ $(box)
+ .css('position', 'absolute')
+ .css('padding', '50px 80px')
+ .css('background-image', 'url(/trans80.png)')
+ .css('color', 'black')
+ .css('text-align', 'center')
+ .attr('id', 'offlinebox')
+ .opacity(0);
+
+ var image = document.createElement('img');
+ image.src = '/offlinemodelarge.png';
+ box.appendChild(image);
+
+ document.body.appendChild(box);
+
+ $(box)
+ .css('top', (( getHeight() / 2 ) - ( $(box).Height() / 2 ) + getScrollOffset()) + 'px')
+ .css('left', (( $(document.body).Width() / 2 ) - ( $(box).Width() / 2 )) + 'px');
+
+ $(box).fadeIn(250);
+ window.setTimeout(function()
+ {
+ $(box).fadeOut(250);
+ window.setTimeout(function()
+ {
+ document.body.removeChild(box);
+ }, 250);
+ }, 1000);
+}
+
function ajaxGet(uri, f)
{
- if ( ajax_panicked )
- return false;
-
if (window.XMLHttpRequest)
{
ajax = new XMLHttpRequest();
@@ -75,9 +138,6 @@
function ajaxPost(uri, parms, f)
{
- if ( ajax_panicked )
- return false;
-
if (window.XMLHttpRequest)
{
ajax = new XMLHttpRequest();
@@ -127,8 +187,9 @@
setAjaxLoading();
ajaxGet('/action.json/refresh', function()
{
- if ( ajax.readyState == 4 && ajax.status == 200 )
+ if ( ajax.readyState == 4 && ajax.status == 200 && ( (window.location.hash != '#offlinemode' && !first_load ) || first_load ) )
{
+ offline_mode_off();
unsetAjaxLoading();
var response = (' ' + ajax.responseText).substr(1);
// quickie JSON parser :)
@@ -144,123 +205,111 @@
}
}
playlist_md5 = response.playlist_hash;
- // update track number
- if ( response.current_track != current_track )
- {
- var ot_id = 'track_' + current_track;
- var nt_id = 'track_' + response.current_track;
- current_track = response.current_track;
- if ( $(ot_id).hasClass('current') )
- {
- $(ot_id).rmClass('current');
- }
- if ( ! $(nt_id).hasClass('current') )
- {
- $(nt_id).addClass('current');
- }
- pulsar_reset();
- }
- // update playing status
- is_playing = response.is_playing;
- if ( allow_control )
- {
- var img = $('btn_playpause').object.getElementsByTagName('img')[0];
- if ( is_playing )
- {
- img.src = img_pause;
- }
- else
- {
- img.src = img_play;
- }
- }
- // update volume
- if ( response.volume != current_volume )
- {
- set_volume_fill(response.volume);
- current_volume = response.volume;
- }
- // auto-refresh on track advance
- if ( ct_advance_timeout )
- {
- clearTimeout(ct_advance_timeout);
- }
- // countdown/up timer
- var time_remaining = response.current_track_length - response.current_track_pos;
- current_track_length = response.current_track_length;
- current_track_pos = response.current_track_pos;
- if ( ct_counter )
- clearInterval(ct_counter);
- update_clock();
- // set page title
- updateTitle(response.current_track_artist, response.current_track_album, response.current_track_title);
-
- // if not playing, set the position slider to zero
- if ( !is_playing && !response.is_paused )
- {
- posslide_set_position(0);
- }
-
- // set advance timer
- if ( is_playing && time_remaining > 0 )
- {
- ct_advance_timeout = setTimeout(refresh_playlist, ( 1000 * time_remaining ));
- ct_counter = setInterval(update_clock, 1000);
- }
- if ( first_load )
- {
- first_load = false;
- jump_current_track();
- }
+ update_timers(response);
}
- else if ( ajax.readyState == 4 && ajax.status != 200 )
+ else if ( ajax.readyState == 4 && ( ajax.status != 200 || window.location.hash == '#offlinemode' ) )
{
- ajax_panic();
- console.debug(ajax);
+ if ( !offline_mode )
+ ajax_panic();
+ else
+ unsetAjaxLoading();
}
});
}
-var ajax_panicked = false;
+function update_timers(response)
+{
+ // update track number
+ if ( response.current_track != current_track )
+ {
+ var ot_id = 'track_' + current_track;
+ var nt_id = 'track_' + response.current_track;
+ current_track = response.current_track;
+ if ( $(ot_id).hasClass('current') )
+ {
+ $(ot_id).rmClass('current');
+ }
+ if ( ! $(nt_id).hasClass('current') )
+ {
+ $(nt_id).addClass('current');
+ }
+ pulsar_reset();
+ }
+ // update playing status
+ is_playing = response.is_playing;
+ if ( allow_control )
+ {
+ var img = $('btn_playpause').object.getElementsByTagName('img')[0];
+ if ( is_playing )
+ {
+ img.src = img_pause;
+ }
+ else
+ {
+ img.src = img_play;
+ }
+ }
+ // update volume
+ if ( response.volume != current_volume )
+ {
+ set_volume_fill(response.volume);
+ current_volume = response.volume;
+ }
+ // auto-refresh on track advance
+ if ( ct_advance_timeout )
+ {
+ clearTimeout(ct_advance_timeout);
+ }
+ // countdown/up timer
+ var time_remaining = response.current_track_length - response.current_track_pos;
+ current_track_length = response.current_track_length;
+ current_track_pos = response.current_track_pos;
+ if ( ct_counter )
+ clearInterval(ct_counter);
+ update_clock();
+
+ // set page title
+ updateTitle(response.current_track_artist, response.current_track_album, response.current_track_title);
+
+ // if not playing, set the position slider to zero
+ if ( !is_playing && !response.is_paused )
+ {
+ posslide_set_position(0);
+ }
+
+ // set advance timer
+ if ( is_playing && time_remaining > 0 )
+ {
+ ct_advance_timeout = setTimeout(refresh_playlist, ( 1000 * time_remaining ));
+ ct_counter = setInterval(update_clock, 1000);
+ }
+ if ( first_load )
+ {
+ first_load = false;
+ if ( window.iPhone )
+ {
+ setTimeout('jump_current_track();', 1000);
+ }
+ else
+ {
+ jump_current_track();
+ }
+ }
+}
function ajax_panic()
{
- // set error flag
- ajax_panicked = true;
-
- // scroll to the top
- window.scroll(0, 0);
-
- // stop events
- pulsar_reset();
- window.clearInterval(pl_refresh_id);
- if ( ct_counter )
- window.clearInterval(ct_counter);
- if ( pulsar_interval_id )
- window.clearInterval(pulsar_interval_id);
-
- // show error message
- var floater = document.createElement('div');
- floater.style.backgroundColor = '#ffffff';
- floater.style.opacity = 0.7;
- floater.style.filter = 'alpha(opacity=70)';
- floater.style.textAlign = 'center';
- floater.style.paddingTop = '120px';
- floater.style.position = 'fixed';
- floater.style.zIndex = '999';
- floater.style.width = '100%';
- floater.style.height = '100%';
- floater.style.top = '0px';
- floater.style.left = '0px';
- floater.style.color = '#000000';
- floater.innerHTML = 'There was a problem with a refresh request to the server. Please reload the page.';
- var body = document.getElementsByTagName('body')[0];
- body.appendChild(floater);
+ offline_mode_on();
}
function player_action(action)
{
+ if ( !verify_online() )
+ {
+ return false;
+ }
+
var act2 = action;
setAjaxLoading();
ajaxGet('/action.json/' + action, function()
@@ -275,6 +324,11 @@
function jump_to_song(tid)
{
+ if ( !verify_online() )
+ {
+ return false;
+ }
+
setAjaxLoading();
if ( tid == current_track )
return false;
@@ -345,8 +399,32 @@
});
}
+function offline_advance_track()
+{
+ var new_track = current_track + 1;
+ if ( !document.getElementById('track_' + new_track) )
+ new_track = 0;
+
+ update_timers({
+ is_playing: is_playing,
+ is_paused: false,
+ volume: current_volume,
+ current_track: new_track,
+ current_track_length: document.getElementById('track_' + new_track).getAttribute('amarok:length_sec'),
+ current_track_pos: 0,
+ current_track_artist: 'FIXME artist',
+ current_track_album: 'FIXME album',
+ current_track_title: 'FIXME title'
+ })
+}
+
function update_clock()
{
+ if ( offline_mode && current_track_pos > current_track_length )
+ {
+ offline_advance_track();
+ }
+
posslide_set_position((100 * (current_track_pos / current_track_length)));
var str = secs_to_string(current_track_pos) + '/' + secs_to_string(current_track_length);
$('playmeter').object.innerHTML = str;
--- a/scripts/position.js Fri Jun 12 13:49:22 2009 -0400
+++ b/scripts/position.js Fri Jun 12 13:50:13 2009 -0400
@@ -41,6 +41,12 @@
var posslide_handle_dragend = function(x, y)
{
pos_in_drag = false;
+ if ( !verify_online() )
+ {
+ posslide_set_position(current_track_pos);
+ return false;
+ }
+
var inner = document.getElementById('playhead-filler');
var base = document.getElementById('playhead');
var multiplier = $(base).Width() - 13;
@@ -51,6 +57,9 @@
var posslide_handle_click = function(e)
{
+ if ( !verify_online() )
+ return false;
+
e = Drag.fixE(e);
var base = document.getElementById('playhead');
var val = e.clientX - $(base).Left();
--- a/scripts/volume.js Fri Jun 12 13:49:22 2009 -0400
+++ b/scripts/volume.js Fri Jun 12 13:50:13 2009 -0400
@@ -46,6 +46,11 @@
function set_volume(level)
{
+ if ( !verify_online() )
+ {
+ return false;
+ }
+
setAjaxLoading();
if ( level == current_volume )
return false;
@@ -125,6 +130,32 @@
}
}
}
+ if ( window.iPhone )
+ {
+ // iPhone Safari can't do keyup events
+ field.onblur = function()
+ {
+ if ( this.value == '' )
+ {
+ $(this.parentNode).fadeOut(250, function(o)
+ {
+ o.parentNode.removeChild(o);
+ });
+ }
+ else if ( !this.value.match(/^[0-9]+$/) )
+ {
+ $(this.parentNode).insertBR().insertText('please enter a number');
+ }
+ else
+ {
+ set_volume(parseInt(this.value));
+ $(this.parentNode).fadeOut(250, function(o)
+ {
+ o.parentNode.removeChild(o);
+ });
+ }
+ }
+ }
}
addOnloadHook(function()
--- a/themes/grey/config.tpl Fri Jun 12 13:49:22 2009 -0400
+++ b/themes/grey/config.tpl Fri Jun 12 13:50:13 2009 -0400
@@ -19,7 +19,7 @@
<link rel="favorite icon" type="image/ico" href="/favicon.ico" />
<script type="text/javascript" src="/scripts/config.js"></script>
</head>
- <body>
+ <body style="width: 80%; margin: 0 auto; min-width: 900px;">
<div class="greylogo"></div>
<a class="backlink" href="/index">« Return to playlist</a>
@@ -45,6 +45,14 @@
</tr>
{/if}
+ {if $message}
+ <tr>
+ <td class="row3" colspan="2">
+ <p class="success">{$message|nl2br}</p>
+ </td>
+ </tr>
+ {/if}
+
<!-- field - current config pass -->
{if $needpass}
<tr>
@@ -139,6 +147,33 @@
</td>
</tr>
+ <!-- section - diagnostics -->
+
+ <tr>
+ <th colspan="2">
+ Diagnostics
+ </th>
+ </tr>
+
+ <!-- clear artwork -->
+ <tr>
+ <td class="row2" style="text-align: center;">
+ <a href="/config/rebuild/artwork" class="backlink inline">Clear artwork cache</a>
+ </td>
+ <td class="row1">
+ Use this to rebuild Greyhound's sprites it generates of your album artwork.
+ </td>
+ </tr>
+
+ <tr>
+ <td class="row2" style="text-align: center;">
+ <a href="/config/rebuild/playlist" class="backlink inline">Refresh playlist</a>
+ </td>
+ <td class="row1">
+ If you changed your playlist but the changes did not show up in Greyhound, use this to force Greyhound to re-read the playlist.
+ </td>
+ </tr>
+
<!-- section - auth config -->
<tr>
<th colspan="2">
--- a/themes/grey/login.css Fri Jun 12 13:49:22 2009 -0400
+++ b/themes/grey/login.css Fri Jun 12 13:50:13 2009 -0400
@@ -13,7 +13,7 @@
body {
font-family: sans-serif;
- background-color: #363636;
+ background-color: #262626;
color: #ffffff;
padding: 0;
}
--- a/themes/grey/playlist.tpl Fri Jun 12 13:49:22 2009 -0400
+++ b/themes/grey/playlist.tpl Fri Jun 12 13:50:13 2009 -0400
@@ -33,6 +33,7 @@
<div class="playbar-inner">
<div id="playhead"><div id="playhead-filler"> </div></div>
<div id="playhead-button"> </div>
+ <div id="offlinemode"><img title="No network connection; running in offline mode" src="/offlinemode.png" width="22" height="22" /></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/themes/grey/style.css Fri Jun 12 13:49:22 2009 -0400
+++ b/themes/grey/style.css Fri Jun 12 13:50:13 2009 -0400
@@ -104,6 +104,12 @@
border-color: #d0d0d0;
}
+div#offlinemode {
+ float: right;
+ margin-left: 4px;
+ display: none;
+}
+
/* Position slider (playhead) */
div#playhead {
@@ -186,6 +192,21 @@
background-color: #505050;
}
+a.backlink.inline {
+ max-width: none;
+ background-color: #282828;
+ margin: 5px 10px;
+}
+
+a.backlink.inline:hover {
+ background-color: #303030;
+}
+
+span.clearer {
+ display: block;
+ clear: both;
+}
+
div.greylogo {
width: 120px;
height: 33px;
@@ -198,3 +219,4 @@
div.clearer {
clear: both;
}
+
--- a/uiconfig.php Fri Jun 12 13:49:22 2009 -0400
+++ b/uiconfig.php Fri Jun 12 13:50:13 2009 -0400
@@ -90,6 +90,7 @@
{
$auth_data = array();
$auth_changed = true;
+ $use_auth = false;
}
}
if ( isset($_POST['users_add']) )
@@ -188,6 +189,36 @@
}
}
+ $message = false;
+
+ // Rebuild options
+ $pathinfo = @substr(@substr($_SERVER['REQUEST_URI'], 1), @strpos(@substr($_SERVER['REQUEST_URI'], 1), '/')+1);
+ switch($pathinfo)
+ {
+ case 'rebuild/artwork':
+ global $amarok_home;
+ $artwork_dir = "$amarok_home/albumcovers";
+
+ if ( $dp = opendir($artwork_dir) )
+ {
+ while ( $dh = @readdir($dp) )
+ {
+ if ( preg_match('/^collage_[0-9]+\.(?:map|png)$/', $dh) )
+ {
+ unlink("$artwork_dir/$dh");
+ }
+ }
+ closedir($dp);
+ }
+
+ $message = 'Successfully cleared album art cache';
+ break;
+ case 'rebuild/playlist':
+ rebuild_playlist(true);
+ $message = 'Successfully rebuilt playlist cache';
+ break;
+ }
+
global $theme;
$iphone = ( ( strpos($_SERVER['HTTP_USER_AGENT'], 'iPhone') ||
strpos($_SERVER['HTTP_USER_AGENT'], 'iPod') ||
@@ -196,12 +227,13 @@
&& !isset($_GET['f'])
);
$theme_id = ( $iphone ) ? 'iphone' : $theme;
+
$smarty = load_theme($theme_id);
-
$smarty->assign('theme', $theme_id);
$smarty->assign('greyhound_version', GREY_VERSION);
$smarty->assign('tried', $tried);
$smarty->assign('success', $success);
+ $smarty->assign('message', $message);
$smarty->assign('needpass', $needpass);
$smarty->assign('use_auth', $use_auth);
$smarty->assign('public', $GLOBALS['public']);