These past few days I was working on the Cool Cavemen’s photo gallery to move it to a shiny new one, powered by Zenphoto. In this post I will roughly describe how I’ve done it, code and commands included.

The old gallery was based on autogallery, a e107 plugin. We assume here that both e107 and Zenphoto are well configured and installed at the root of you web hosting space (/www in this case).

The first step is to copy the autogallery album structure, with all its content, to Zenphoto:

1 $ cd /www
2 $ cp -ax ./e107_plugins/autogallery/Gallery/* ./zenphoto/albums/

Then we delete all previews, thumbnails and XML metadatas, to keep in Zenphoto original assets only:

1 $ find ./zenphoto/albums/ -iname "*.xml" | xargs rm -f
2 $ find ./zenphoto/albums/ -iname "pv_*" | xargs rm -f
3 $ find ./zenphoto/albums/ -iname "th_*" | xargs rm -f

By now, you should be able to play with your medias using Zenphoto’s admin interface.

But if you’re unlucky as I was, you will find a strange bug which break down drag’n’drop album sorting. The fix I found was to remove, in photo filenames, the numerical prefix (and the following dot) set by autogallery to define the sort order. This operation should be performed, before the copy from autogallery to Zenphoto (= the first command in this post). By the way, if you know a one-liner to do this, please, please… share! :)

To migrate comments, I have no automatic solution. I choose to do this manually, editing the database by hand. In my case it was the quickest way as I only had a dozen of comments to migrate.

And last but not least, if you care about measuring the popularity of your photos, you should consider migrating the view counter associated with each of your media. Don’t worry, this time I wrote a script to take care of it automagically. It will generate a bunch of SQL statements you’ll have to execute on your Zenphoto MySQL database. Here is my “e107 autogallery to Zenphoto hit counter migration script” (nice name isn’t it? ;) ) that do the job:

  1 #!/usr/bin/python
  2 
  3 ##############################################################################
  4 #
  5 # Copyright (C) 2008 Kevin Deldycke <[email protected]>
  6 #
  7 # This program is Free Software; you can redistribute it and/or
  8 # modify it under the terms of the GNU General Public License
  9 # as published by the Free Software Foundation; either version 2
 10 # of the License, or (at your option) any later version.
 11 #
 12 # This program is distributed in the hope that it will be useful,
 13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 15 # GNU General Public License for more details.
 16 #
 17 # You should have received a copy of the GNU General Public License
 18 # along with this program; if not, write to the Free Software
 19 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 20 #
 21 ##############################################################################
 22 
 23 """
 24   Last update: 2008 aug 21
 25 """
 26 
 27 ########### User config ###########
 28 
 29 AUTOGALLERY_ALBUM_PATH = "/www/e107_plugins/autogallery/Gallery"
 30 ZENPHOTO_ALBUM_PATH    = "/www/zenphoto/albums"
 31 ZENPHOTO_TABLE_PREFIX  = "zenphoto_"
 32 
 33 ######## End of user config #######
 34 
 35 import os, hashlib
 36 import xml.etree.ElementTree as ET
 37 
 38 # Calculate hash of a given file
 39 def getHash(path):
 40   # Calculate the hash from file raw data
 41   if not os.path.isfile(path):
 42     return None
 43   try:
 44     file_object = open(path, 'r')
 45     data = file_object.read()
 46   except:
 47     return None
 48   if not len(data):
 49     return None
 50   return hashlib.sha224(data).hexdigest()
 51 
 52 # Associate each autogallery photo having a hitcounter greater than 0 with its MD5 hash
 53 def populateHashTable(arg, dirname, names):
 54   global hash_table
 55   for name in names:
 56     file_path = os.path.join(dirname, name)
 57     # print "Get hit count for %s" % file_path
 58     # Check that the file as a positive hit counter associated with
 59     xml_file_path = "%s.xml" % file_path
 60     if not os.path.isfile(xml_file_path):
 61       continue
 62     try:
 63       tree = ET.parse(xml_file_path)
 64     except:
 65       continue
 66     node = tree.find("viewhits")
 67     if node is None:
 68       continue
 69     try:
 70       hits = int(node.text)
 71     except:
 72       continue
 73     if not hits > 0:
 74       continue
 75     # Update hash table with data we care about
 76     file_hash = getHash(file_path)
 77     if file_hash is None:
 78       continue
 79     hash_table[file_hash] = hits + hash_table.get(file_hash, 0)
 80 
 81 # Generate hitcount SQL request for each matching file
 82 def generateSQL(arg, dirname, names):
 83   global sql
 84   for name in names:
 85     file_path = os.path.join(dirname, name)
 86     # print "Search hitcounter matching file %s" % file_path
 87     file_hash = getHash(file_path)
 88     if file_hash is None:
 89       continue
 90     if file_hash in hash_table:
 91       sql += "UPDATE `%simages` SET `hitcounter`=`hitcounter`+%d WHERE `filename`=%r;\n" % (ZENPHOTO_TABLE_PREFIX, hash_table[file_hash], name)
 92 
 93 # Core of the script
 94 hash_table = {}
 95 sql        = ""
 96 # Normalize path
 97 source_path = os.path.abspath(AUTOGALLERY_ALBUM_PATH)
 98 dest_path   = os.path.abspath(ZENPHOTO_ALBUM_PATH)
 99 
100 os.path.walk(source_path, populateHashTable, None)
101 # print repr(hash_table)
102 os.path.walk(dest_path, generateSQL, None)
103 print sql

I think code and comments are self-explanatory. And do not forget to update constants at the top of the script to match your installation paths and database’s tables prefix.

And finally, for your information, I tested all of this on following versions:

  • e107 0.7.11

  • autogallery 2.61

  • Zenphoto 1.2

  • Python 2.5.2

  • Linux server