iPhoto2

Just released a library for parsing iphoto databases:


gem install plist
gem install iphoto2

iphoto = IPhoto2.new # path to AlbumData.xml is optional
iphoto.albums.each do |album|
album.each do |image|
puts image.path
end
end


There's more, but I'm tired now.

Update: oylenshpeegul pointed out a bug in the comments, I've put out another gem (iphoto2-1.0.1) to the problem with the Album#each. And he is correct, there is an Album#images accessor.


plist.xml parser for Ruby

To help with my AlbumData.xml parsing, I've thrown together a plist parser for Mac OS X plist.xml files. Api documentation: Plist::parse_xml( plist_xml_filename )


iPhoto 2 database format

~/Pictures/iPhoto Library/

2006/01/07/fallow_keep.png.450x450.2005-12-04.jpg
original image

2006/01/07/Thumbs/7.jpg
a thumbnail

AlbumData.xml
plist file with all the goodies

Dir.data
binary

iPhoto.db
binary

iPhoto.ipspot
text, perhaps for spotlight indexing?

iPhotoLock.data
blank at the moment

Library.iPhoto
binary

Thumb32.data
binary

Thumb64.data
binary

ThumbJPG.data
binary



I kept the library pretty simple, to show the structure:


{
"Application Version" = "5.0.4 (263)";
"Archive Path" = "/Users/username/Pictures/iPhoto Library";
"List of Albums" = (
{
AlbumId = 999000;
AlbumName = Library;
KeyList = (7);
Master = 1;
PhotoCount = 1;
PlayMusic = YES;
RepeatSlideShow = YES;
SecondsPerSlide = 3;
SlideShowUseTitles = 0;
SongPath = "";
TransitionDirection = 0;
TransitionName = Dissolve;
TransitionSpeed = 1;
},
{
"Album Type" = "Special Roll";
AlbumId = 999001;
AlbumName = "Last Roll";
"Filter Mode" = All;
Filters = ({Count = 1; Operation = "In Last"; Type = Roll; });
KeyList = (7);
PhotoCount = 1;
PlayMusic = YES;
RepeatSlideShow = YES;
SecondsPerSlide = 3;
SlideShowUseTitles = 0;
SongPath = "";
TransitionDirection = 0;
TransitionName = Dissolve;
TransitionSpeed = 1;
},
{
"Album Type" = "Special Month";
AlbumId = 999002;
AlbumName = "Last 12 Months";
"Filter Mode" = All;
Filters = ();
KeyList = (7);
PhotoCount = 1;
PlayMusic = YES;
RepeatSlideShow = YES;
SecondsPerSlide = 3;
SlideShowUseTitles = 0;
SongPath = "";
TransitionDirection = 0;
TransitionName = Dissolve;
TransitionSpeed = 1;
},
{
"Album Type" = Regular;
AlbumId = 9;
AlbumName = "An Album";
KeyList = (7);
PhotoCount = 1;
PlayMusic = YES;
RepeatSlideShow = YES;
SecondsPerSlide = 3;
SlideShowUseTitles = 0;
SongPath = "";
TransitionDirection = 0;
TransitionName = Dissolve;
TransitionSpeed = 1;
}
);
"List of Keywords" = {};
"List of Rolls" = (
{
"Album Type" = Regular;
AlbumId = 6;
AlbumName = "Roll 1";
KeyList = (7);
Parent = 999000;
PhotoCount = 1;
}
);
"Major Version" = 2;
"Master Image List" = {
7 = {
"Aspect Ratio" = 1;
Caption = "fallow_keep.png.450x450.2005-12-04";
Comment = "";
DateAsTimerInterval = 158341389;
ImagePath = "/Users/username/Pictures/iPhoto Library/2006/01/07/fallow_keep.png.450x450.2005-12-04.jpg";
MediaType = Image;
MetaModDateAsTimerInterval = 158341439.728129;
ModDateAsTimerInterval = 158341389;
Rating = 0;
Roll = 6;
ThumbPath = "/Users/username/Pictures/iPhoto Library/2006/01/07/Thumbs/7.jpg";
};
};
"Minor Version" = 0;
}



~ Patrick May