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>

Sturgeon King (Serpent 2)

Well, it is now mid-December, and as promised I have finished the serpent on the Sturgeon King model. I sprayed some green to blue Alclad II prismatic paint along the belly of the serpent to add some additional shading and texture. The Alclad II prismatic paints have an interesting effect whereby they change color a bit depending on the angle at which you are looking at the model. You should be able to see the slight green tint reflecting off the scales in some of the pictures.

 

The following pictures are some close-ups of the serpent’s face. The creature has little beady eyes that I presume just had to be red, and a number of tiny little teeth just waiting to bite something. I washed some black enamel into the nose lines to draw this feature out, and also into the spirals in the things in the head that I had famously tried to paint in a copper color. I also added a little more purple pearlescent color to the scales on the top of the head as I thought this color should continue on from the back. There is a little gold enamel trim in the ear wings, and the two antenna on the head were done in the Alclad gold oversprayed with white pearl as I did with the wings.

 

There you go. The serpent is done.

My next posting should be in a week or two. We’re into the holiday season now and I have some time off work, so I should be able to find more time to continue working on this model. My plan is to start work on the mushroom seat (if that is what we call it).

Sturgeon King (Serpent 1)

Now it is early December and I have started work on the serpent. I am not finished, but I thought I would post some progress pictures.

I had mostly intended to follow PKking’s original color scheme as it made sense. The serpent is rising from the water and the base of the creature should be of a blue color, which means that the whole serpent should perhaps be of a blue or gray tint. And, I wanted metallic colors that would shine. The picture below shows the paints that I used. There was a metallic blue from Vallejo Model Air and another blue from Tamiya X13, and a few pearlescent ink paints from Daler-Rowney.

The base of the serpent was colored with standard blue to roughly match the shade of the water. The back of the serpent was sprayed with the darker Vallejo blue.

The head and the inside of the serpent was painted with the Tamiya metallic blue. The fins, or pointy things all along the back of the serpent were painted with the purple pearlescent paint. Now, these Daler-Rowney ink paints are hard to spray as they tend to plug up the airbrush. So, when they come they come in a big rush, and then they stop, and so on. There is not a lot of fine spray control. But, the overspray does leave a wonderful glisten to the metallic paint. Once the purple is on it is shaded and toned with a white pearl overspray.

Now, being creatively silly, I thought that a nice metallic gold Alclad II color on the wings would look good. Boy, was I wrong! But, with every mistake there is always gold in the silver linings. I oversprayed the gold with my wonderful white pearl and came out with a very fine slightly gold tint to the wings which makes them look just like metal.

And then, stupid me, I thought to repeat my mistake by looking for a copper color as highlights on the serpent’s head. Well, this didn’t work any better than the gold. So, I highlighted the top of the head with the blue pearlescent paint. And I covered this copper mess up and highlighted the blue with the white pearl. This is much more satisfactory.

What follows now are a few shots of the serpent on the clear base. There is a lot of brush work still required on the serpent to paint the eyes and teeth and bring out all the detail in the creature. I’ll post some more pictures in a week or two when this is done.