Gallery2 MiniSlideShow Performance Cache

MiniSlideShow is an interesting Flash plugin to display Gallery2 images on your website. It uses an XML RSS feed to access Gallery2 albums. It also uses Gallery2 to return the correct size image resolution for embedded slideshows. MiniSlideShow is being used in the sidebars on Kisekae World.

One problem with this solution is that generating an RSS feed takes time. The generation delay impacts the start of the slideshow, particularly if the slideshow is included as a sidebar block on every Gallery page or embedded application page. This can be particularly noticable if the feed contains many images. Each display of a new page results is a new invokation of the slideshow and this results in a new initialization of the RSS feed.

One way to mitigate the feed generation performance loss is to cache the generated RSS feed XML text. For example, if the album feed has been previously generated and saved then it can be referenced on a new page load without the overhead of regenerating the RSS feed. This can provide some performance relief.

Gallery2 provides disk caching services as part of its core module. I have modified the xml() function in mediaRSS.php distributed with MiniSlideShow to use the Gallery2 cache functions. The code assumes that a new ‘minislideshow’ module has been installed as a Gallery2 module as described further below. For caching, the Gallery2 itemId is used as the cache key, and each cached RSS text entity will expire after 3600 seconds (1 hour). All new lines inserted into the function are shown in a different color.

 

mediaRss.php

<?php
// +---------------------------------------------------------------------------+
// |  E2  XML Audio/Video Player/Minislideshow for Gallery2                    |
// +---------------------------------------------------------------------------+
// | mediaRss.php     [v.3.0.0]                                                |
// +---------------------------------------------------------------------------+
// | Copyright (C) 2009 Wayne Patterson [suprsidr@flashyourweb.com]            |
// +---------------------------------------------------------------------------+
// |                                                                           |
// | This program is free software; you can redistribute it 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 more details.                              |
// |                                                                           |
// | You should have received a copy of the GNU General Public License         |
// | along with this program; if not, write to the Free Software Foundation,   |
// | Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.           |
// |                                                                           |
// +---------------------------------------------------------------------------+
//

.
. [snipped code]
.

    function xml() {
	init();
	global $gallery, $userId, $count;


	// Determine cache item	
	if (isset ($_REQUEST['g2_itemId'])) {
	    $cacheId = $_REQUEST['g2_itemId'];
	} else if (isset ($_REQUEST['g2_albumId'])) {
	    $cacheId = $_REQUEST['g2_albumId'];
	} else {
		$cacheId = getRoot() ;
	}
	
	// Retrieve cache item if not expired	
	if (isset($cacheId)) {
		$expire = 3600;		   
		$cacheMsg = "n";
		$cachePathInfo = array('type' => 'module-data',
			   'module' => 'minislideshow',
			   'itemId' => $cacheId);
		list ($xmltime, $xmldata) =
			GalleryDataCache::getFromDisk($cachePathInfo);
		if (isset($xmltime) && isset($xmldata)) {
			$vm = $gallery->getPhpVm();
			$cacbeTime = date('U', $vm->time());
			$diff = (int)$cacbeTime - (int)$xmltime;
			$expiretime = (int)$xmltime + $expire;
			if ($diff < $expire) {
				$xmldata .= "nRetrieved itemId " . $cacheId . " at " . $cacbeTime . " that was cached at " . $xmltime 
					. " and will expire at " . $expiretime;
				echo $xmldata;
				return;
			} else {
				$cacheMsg .= "Cache expired, item cached at " . $xmltime . ", current time " . $cacbeTime 
					. ", item expired at " . $expiretime . "n" ;
			}
		} else {
			$cacheMsg .= "Cache not found, itemId " . $cacheId . "n";
		}
	}

	
	$title = '';
	$recursive = '';
	if (!$userId) {
	    $userId = $gallery->getActiveUserId();
	}
	if (!$userId) {
	    list($ret,$userId) = GalleryCoreApi::getAnonymousUserId();
	}
	if (isset ($_REQUEST['mode'])) {
	    $mode = $_REQUEST['mode'];
	}else{
		$mode = '';
	}
	if (isset ($_REQUEST['g2_itemId'])) {
	    $g2_itemId = $_REQUEST['g2_itemId'];
	    list ($ret, $item) = GalleryCoreApi::loadEntitiesById($g2_itemId, 'GalleryAlbumItem');
	    if ($ret) {
	        print "Error loading initial item:" . $ret->getAsHtml();
	    }
	    $title = getTitle($item);
	}else{
	    $title = "Gallery2 MediaRss";
	}
	if (isset ($_REQUEST['g2_view'])) {
	    $g2_view = $_REQUEST['g2_view'];
	}
	if (isset ($_REQUEST['mime'])) {
	    $mime = $_REQUEST['mime'];
	}
	if (isset ($_REQUEST['recursive'])) {
	    $recursive = $_REQUEST['recursive'];
	}
	if(isset ($_REQUEST['limit'])){
		global $limit;
		$limit = $_REQUEST['limit'];
	}
	$xml = '';
	$count = 0;
	$urlGenerator =& $gallery->getUrlGenerator();
	$link = $urlGenerator->generateUrl(array(), array('forceFullUrl' => true));
	$vm = $gallery->getPhpVm();
	list ($ret, $language) = GalleryTranslator::getDefaultLanguageCode( );
	if ($ret) {
	    $language = "en-us";
	}
	if (!$vm->headers_sent()) {
	    $vm->header('Content-Type: application/rss+xml; charset=UTF-8');
	}
	echo "<?xml version="1.0" encoding="UTF-8" ?>n";	
	$xml .= "<rss version="2.0" xmlns:media="http://search.yahoo.com/mrss/">n";
	$xml .= "    <channel>n";
	$xml .= "        <title>" . cdata($title) . "</title>n";
	$xml .= "        <link>" . $link . "</link>n";
	$xml .= "        <description>" . cdata($title) . "</description>n";
	$xml .= "        <language>" .$language. "</language>n";
	$xml .= "        <generator>FlashYourWeb MediaRSS Generator v3.0.0</generator>n";
	$xml .= "        <lastBuildDate>" . date('r', $vm->time()) . "</lastBuildDate>n";
	$xml .= "        <ttl>120</ttl>n";
	if(isset($g2_itemId)){
		$xml .= getAlbumList ($g2_itemId);
	}else{
		$xml .= getAlbumList (getRoot());
	}
	switch ($mode) {
	    case 'dynamic':
	        switch ($g2_view) {
	            case 'dynamicalbum.UpdatesAlbum':
	                $xml .= getDynamicChildIds($userId);
	            break;
	            case 'dynamicalbum.PopularAlbum':
	                $xml .= getDynamicChildIds($userId, 'views', 'viewCount', ORDER_DESCENDING, 'GalleryItemAttributesMap', 'itemId');
	            break;
	            case 'dynamicalbum.RandomAlbum':
	                $xml .= getDynamicChildIds($userId, 'random', 'random', ORDER_ASCENDING, null, 'id');
	            break;
	            case 'keyalbum.KeywordAlbum':
	            	$xml .= getKeywordChildIds($userId, $g2_keyword=null);
	            break;
	            case 'tags.VirtualAlbum':
	                $xml .= getTagChildIds($userId, $g2_tagName=null);
	            break;
	            default:
	            $xml .= getDynamicChildIds($userId);
	        }
	    break;
	    case 'search':
	        $xml .= getSearchItems($g2_itemId, $mime);
	    break;
	    case 'simple':
	        $xml .= itemListDisplay();
	    break;
	    default:
	        if(isset($g2_itemId) && $recursive){
	            $xml .= getItemsRecursive ($g2_itemId);
	        }else if(isset($g2_itemId)){
	            $xml .= getItems($g2_itemId);
	        }else{
	            $xml .= getItems(getRoot());
	        }
	}
	
	$xml .= "    </channel>n";
	$xml .= "</rss>";


	// Cache item for future access	
	if (isset($cacheId)) {
		$cachePath = GalleryDataCache::getCachePath($cachePathInfo);
		if (isset($cachePath)) {
			$xmltime = date('U', $vm->time());
			GalleryDataCache::putToDisk($cachePathInfo, $dataToCache = array($xmltime, $xml));
			$xml .= $cacheMsg;	
			$xml .= "Cache itemId " . $cacheId . " at " . $xmltime . " to " . $cachePath;
		}
	}


	echo $xml;
    }
xml();
?>

 

For the above solution to work there must be a ‘/g2data/cache/module/minislideshow’ directory on your web server. This is where Gallery2 stores the cached files. If this directory does not exist or disk caching is not possible then the cache modifications will fail silently. To determine if caching is functioning you need to examine the source code for the XML feed. Cache message text is inserted in the document following the RSS directives. The following three feeds below will show cache information if you use your browser to display the source text.

Example:

Cache expired, item cached at 1325184690, current time 1325189988, item expired at 1325188290
Cache itemId 3576 at 1325189988 to /home/g2data/cache/module/minislideshow/3/5/3576.dat

 

Installation

The MiniSlideShow has been packaged as a rudimentary Gallery2 module so that it can be included in the Gallery2 sidebar block. Download the MiniSlideShow Gallery2 Module and copy the ‘minislideshow’ directory to your Gallery2 modules folder.

The packaged module doesn’t install the MiniSlideShow function for you. It does include the modified ‘mediaRSS.php’ file shown above and the required ‘minislideshow.swf’ and ‘swfobject.js’ files released with MiniSlideShow. Copy these files to your Gallery2 home directory on your web server.

You need to edit the ‘MiniSlideShow.tpl’ block template file found in the ‘minislideshow/templates/blocks’ directory. See below. Change the reference URLs to refer to your Gallery2 URL of your ‘mediaRSS.php’ and the ‘minislideshow.swf’ files. You should also ensure that the ‘swfobject.js’ file is included in the <head> section of your pages with <script type=”text/javascript” src=”http://www.yoursite.com/swfobject.js”></script>

 

MiniSlideShowBlock.tpl

{*
 * $Revision: 1.5 $
 * If you want to customize this file, do not edit it directly since future upgrades
 * may overwrite it.  Instead, copy it into a new directory called "local" and edit that
 * version.  Gallery will look for that file first and use it if it exists.
 *}

<div id="slideshow" style="margin: 10px 10px 15px 0px; padding: 5px; border-style:solid; border-width:1px; background: #ffffff; text-align: center;">

{if $theme.pageType == 'album'}
	{if !empty($theme.item.title)} <span style="color: #800000; font-weight: bold;">{$theme.item.title|markup}</span><br /> {/if} Slide Show <br />
{/if}
{if $theme.pageType == 'photo'}
	{if !empty($theme.parent.title)} <span style="color: #800000; font-weight: bold;">{$theme.parent.title|markup}</span><br /> {/if} Slide Show <br />
{/if}

<div id="g2slidecontainer" style="height: 160px;">
 <div id="g2slideplayer">
    You need Flash Player and JavaScript enabled to view this item.
 </div>
</div>

<script type="text/javascript">
    var attributes = {ldelim}
      id: 'mini',
      name: 'movie'
    {rdelim};
    var params = {ldelim}
      menu: 'false',
      wmode: 'transparent',
      allowscriptaccess: 'always',
      allowfullscreen: 'true'
    {rdelim};
    var flashvars = {ldelim}
{if $theme.pageType == 'album'}
      xmlUrl: 'http://www.yoursite.com/gallery2/mediaRss.php?mode=dynamic%26g2_view=dynamicalbum.RandomAlbum%26g2_albumId={$theme.item.id}',
{/if}
{if $theme.pageType == 'photo'}
      xmlUrl: 'http://www.yoursite.com/gallery2/mediaRss.php?mode=dynamic%26g2_view=dynamicalbum.RandomAlbum%26g2_albumId={$theme.parent.id}',
{/if}
      shuffle: 'true',
      showDropShadow: 'true',
      delay: 3,
      useFull: 'true',
      showControls: 'always',
      roundedMask: 'true'
    {rdelim};
    swfobject.embedSWF("http://www.yoursite.com/gallery2/minislideshow.swf", "g2slideplayer", "160", "160", "9.0.115.0", null, flashvars, params, attributes);
</script>
</div>

 

As a Gallery2 administrator you can install the ‘minislideshow’ plugin. The installation process should create the Gallery2 module cache directory for you. If you want to include the slideshow in your Gallery2 theme add the ‘minislideshow’ as a sidebar block. If you want to view the slideshow from an external application such as WordPress, simply create a text widget with code similar to the template file above.

 

WordPress Text Widget

<div id="slideshow" style="margin: 10px 10px 15px 0px; padding: 5px; border-style:none; background: #ffffff; text-align: center;">
<span style="color: #800000; font-weight: bold;">Resin Figure Models</span><br /><span style="font-size: 0.8em; font-family: Verdana,Arial,Helvetica,sans-serif;">Slide Show </span><br />

<div id="g2slidecontainer" style="height: 160px;">
 <div id="g2slideplayer">
    You need Flash Player and JavaScript enabled to view this item.
 </div>
</div>

<script type="text/javascript">
    var attributes = {
      id: 'mini',
      name: 'movie'
    };
    var params = {
      menu: 'false',
      wmode: 'transparent',
      allowscriptaccess: 'always',
      allowfullscreen: 'true'
    };
    var flashvars = {
      xmlUrl: 'http://www.yoursite.com/gallery2/mediaRss.php?mode=dynamic%26g2_view=dynamicalbum.RandomAlbum%26g2_albumId=21930',
      shuffle: 'true',
      showDropShadow: 'true',
      delay: 3,
      useFull: 'true',
      showControls: 'always',
      roundedMask: 'true'
   };
    swfobject.embedSWF("http://www.yoursite.com/gallery2/minislideshow.swf", "g2slideplayer", "160", "160", "9.0.115.0", null, flashvars, params, attributes);
</script>
</div>