# HG changeset patch # User Dan # Date 1244829013 14400 # Node ID 08f8a72b1f7b32bdb7e79d2a5332ace75e5a054e # Parent e5f1f45ea7e20a3c7fd46d6d192b141516be0d1e Added Offline Mode - automatically turned on and off based on connectivity to server. Version bumped to 0.1a5. diff -r e5f1f45ea7e2 -r 08f8a72b1f7b greyhound.php --- 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(); -} - diff -r e5f1f45ea7e2 -r 08f8a72b1f7b offlinemode.png Binary file offlinemode.png has changed diff -r e5f1f45ea7e2 -r 08f8a72b1f7b offlinemodelarge.png Binary file offlinemodelarge.png has changed diff -r e5f1f45ea7e2 -r 08f8a72b1f7b scripts/ajax.js --- 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; diff -r e5f1f45ea7e2 -r 08f8a72b1f7b scripts/position.js --- 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(); diff -r e5f1f45ea7e2 -r 08f8a72b1f7b scripts/volume.js --- 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() diff -r e5f1f45ea7e2 -r 08f8a72b1f7b themes/grey/config.tpl --- 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 @@ - + « Return to playlist @@ -45,6 +45,14 @@ {/if} + {if $message} + + +

{$message|nl2br}

+ + + {/if} + {if $needpass} @@ -139,6 +147,33 @@ + + + + + Diagnostics + + + + + + + Clear artwork cache + + + Use this to rebuild Greyhound's sprites it generates of your album artwork. + + + + + + Refresh playlist + + + If you changed your playlist but the changes did not show up in Greyhound, use this to force Greyhound to re-read the playlist. + + + diff -r e5f1f45ea7e2 -r 08f8a72b1f7b themes/grey/login.css --- 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; } diff -r e5f1f45ea7e2 -r 08f8a72b1f7b themes/grey/playlist.tpl --- 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 @@
 
 
+
AmaroK web control {if $allow_control} diff -r e5f1f45ea7e2 -r 08f8a72b1f7b themes/grey/style.css --- 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; } + diff -r e5f1f45ea7e2 -r 08f8a72b1f7b uiconfig.php --- 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']);