Submit Hint Search The Forums LinksStatsPollsHeadlinesRSS
14,000 hints and counting!

Click here to return to the 'Export iPhoto events into appropriate directory structure' hint
The following comments are owned by whoever posted them. This site is not responsible for what they say.
Export iPhoto events into appropriate directory structure
Authored by: ricelid on Aug 26, '09 08:44:28AM

This ALMOST did exactly what I want, but now my photos have non-meaningful file names. Is there a way to process the files and rename them to have the title from the iphoto metadata


[ Reply to This | # ]
Export iPhoto events into appropriate directory structure
Authored by: dchilders on Dec 29, '09 11:12:00AM
This has really bugged me for a while and I really don't like the solution where all my files get renamed. I've written a python script that so far is doing what I want it. I'm parsing the AlbumData.xml file and walking through the list of all of the events/rolls. The roll lists all the imageId's that belong to it. From there I can get the original and modified image path. Then I look for a corresponding file in my target directory and compare the timestamps to see if I need to recopy the file (incase I've made changes to it in iPhoto). Anyway, I've just started using it and it appears to be working ok.

I'm running:

  • Snow Leopard 10.6.2
  • python 2.6.1
  • iPhoto 8.1.1
You'll want to update the following lines to be correct on your system:
albumDataXml="/Users/YOURUSERNAME/Pictures/iPhoto Library/AlbumData.xml"

Here's the script:

from xml.dom.minidom import parse, parseString, Node
import os, time, stat, shutil, sys

def findChildElementsByName(parent, name):
    result = []
    for child in parent.childNodes:
        if child.nodeName == name:
    return result

def getElementText(element):
    if element is None: return None
    if len(element.childNodes) == 0: return None
    else: return element.childNodes[0].nodeValue

def getValueElementForKey(parent, keyName):
    for key in findChildElementsByName(parent, "key"):
        if getElementText(key) == keyName:
            sib = key.nextSibling
            while(sib is not None and sib.nodeType != Node.ELEMENT_NODE):
                sib = sib.nextSibling
            return sib

albumDataXml="/Users/YOURUSERNAME/Pictures/iPhoto Library/AlbumData.xml"
copyImg=True #set to false to run with out copying files or creating directories

print "Parsing AlbumData.xml"
albumDataDom = parse(albumDataXml)
topElement = albumDataDom.documentElement
topMostDict = topElement.getElementsByTagName('dict')[0]
listOfRollsArray = getValueElementForKey(topMostDict, "List of Rolls")
masterImageListDict = getValueElementForKey(topMostDict, "Master Image List")

#walk through all the rolls (events)
for rollDict in findChildElementsByName(listOfRollsArray, 'dict'):
    rollName = getElementText(getValueElementForKey(rollDict, "RollName"))
    print "\n\nProcessing Roll: %s" % (rollName)

    #walk through all the images in this roll/event
    imageIdArray = getValueElementForKey(rollDict, "KeyList")
    for imageIdElement in findChildElementsByName(imageIdArray, 'string'):
        imageId = getElementText(imageIdElement)
        imageDict = getValueElementForKey(masterImageListDict, imageId)
        modifiedFilePath = getElementText(getValueElementForKey(imageDict, "ImagePath"))
        originalFilePath = getElementText(getValueElementForKey(imageDict, "OriginalPath"))

        sourceImageFilePath = modifiedFilePath

        modifiedStat = os.stat(sourceImageFilePath)
        basename = os.path.basename(sourceImageFilePath)
        year = str(time.gmtime(modifiedStat[stat.ST_CTIME])[0])
        targetFileDir = targetDir + "/" + year + "/" + rollName

        if not os.path.exists(targetFileDir):
            print "Directory did not exist - Creating: %s" % targetFileDir
            if copyImg:

        targetFilePath = targetFileDir + "/" + basename
        iPhotoFileIsNewer = False

        if os.path.exists(targetFilePath):
            targetStat = os.stat(targetFilePath)

            #print "modified: %d %d" % (modifiedStat[stat.ST_MTIME], modifiedStat[stat.ST_SIZE])
            #print "target  : %d %d" % (targetStat[stat.ST_MTIME], targetStat[stat.ST_SIZE])

            #why oh why is modified time not getting copied over exactly the same?
            if abs(targetStat[stat.ST_MTIME] - modifiedStat[stat.ST_MTIME]) > 10 or targetStat[stat.ST_SIZE] != modifiedStat[stat.ST_SIZE]:
                iPhotoFileIsNewer = True
            iPhotoFileIsNewer = True

        if iPhotoFileIsNewer:
            msg = "copy from:%s to:%s" % (sourceImageFilePath, targetFilePath)
            if copyImg:
                print msg
                shutil.copy2(sourceImageFilePath, targetFilePath)
                print "test - %s" % (msg)


[ Reply to This | # ]