Report abuse

--
-- Sets the date a photo was taken in iPhoto using the date stored in
-- Flickr for that photo as the source (via each photo's XML file as
-- generated by the Python script).
--

-- the folder where the XML files are for each Flickr photo, as
-- downloaded with the Python script
set the_xml_folder to ((path to home folder as text) & "Documents:scripts:flickr:photoinfo")

-- replace the tell section with the following line if you
-- want to run the script on *all* photos in your iPhoto library
-- as opposed to just those you have selected.
--set all_the_photos to get_all_photos()
tell application "iPhoto"
    set all_the_photos to selection
end tell

-- loop over the photos (either all or the selection as chosen above)
set photo_count to count of all_the_photos
repeat with i from 1 to photo_count
    -- get information about this photo
    set the_photo to (item i of all_the_photos)
    set the_filename to get_photo_filename(the_photo)
    set the_id to (item 1 of (string_to_list(the_filename, "_")))
    
    -- load and parse this photo's XML file (as downloaded by that Python script)
    set the_data to load_xml(the_xml_folder & ":" & the_id & ".xml")
    set the_xml to parse_it(the_data)
    
    -- extract the photo's date taken from the XML document
    set the_photo_tag to getAnElement(the_xml, "photo")
    set the_dates to getElementFromPath(the_xml, {"photo", "dates"})
    set the_date_taken to convert_date(taken of XML attributes of the_dates)
    
    -- set the photo's date taken in iPhoto to what we got from its XML file
    tell application "iPhoto"
        select the_photo
        set date of the_photo to the_date_taken
    end tell
    
end repeat

return 0

on convert_date(the_flickr_date)
    -- convert a Flickr date, as extract from the XML file, to an AppleScript Date object
    set d_n_t to string_to_list(the_flickr_date, " ")
    set the_date to (item 1 of d_n_t)
    set the_exif_time to (item 2 of d_n_t)
    set y_m_d to string_to_list(the_date, "-")
    set the_year to (item 1 of y_m_d)
    set the_month to (item 2 of y_m_d)
    set the_day to (item 3 of y_m_d)
    set the_exif_year to the_year & " " & the_month & " " & the_day
    set the_exif_date to the_exif_year & " " & the_exif_time
    return EXIFDateDecode(the_exif_date)
end convert_date

on EXIFDateDecode(iPhotoDate) -- converts EXIF dates into AppleScript Date objects
    -- original subroutine by Joe Maller <http://www.joemaller.com>
    -- authored March 2005
    -- licensed under Creative Commons Attribution Non Commercial ShareAlike 2.0
    -- http://creativecommons.org/licenses/by-nc-sa/2.0/
    
    -- 1.1 Added a month key to workaround an ambiguity problem with some international date formats
    -- 1.2 (May 2005) removed any English language dependencies from date rebuilding
    -- 1.3 (May 2005) rebuilt date extraction for compatibility with older versions of Applescript
    -- 1.5 (January 2006) Adapted for iPhoto 6, now checks to see if iPhotoDate is a date
    
    --iPhoto 6 returns a date object instead of an exif-formatted string:
    if class of iPhotoDate is date then return iPhotoDate
    
    -- EXIF dates are always #### ## ## ##:##:## [-####], extract characters to desired places, translate months to words
    if length of iPhotoDate < 19 then
        return false -- fail on too short a supplied date
    else
        set monthList to {January, February, March, April, May, June, July, August, September, October, November, December} -- month constants, seems work internationally
        set theDate to "1/1/1 2:2:2" -- save a call to "current date" 
        set theDate to date theDate
        set month of theDate to item (text 6 thru 7 of iPhotoDate) of monthList
        set day of theDate to text 9 thru 10 of iPhotoDate
        set year of theDate to text 1 thru 4 of iPhotoDate
        set time of theDate to ((text 12 thru 13 of iPhotoDate) * hours + (text 15 thru 16 of iPhotoDate) * minutes + (text 18 thru 19 of iPhotoDate))
        return theDate
    end if
end EXIFDateDecode

on get_all_photos()
    -- return all the photos in iPhoto's library
    tell application "iPhoto"
        set all_the_photos to the photos of photo library album
        return all_the_photos
    end tell
end get_all_photos

on get_photo_filename(the_photo)
    -- get the name of a photo from iPhoto
    tell application "iPhoto"
        tell the_photo
            return the image filename
        end tell
    end tell
end get_photo_filename

on getElementFromPath(theXML, theElementPath)
    -- extract an element from an arbitrary path into the document
    if theElementPath is {} then
        return theXML
    else
        local foundElement
        
        set foundElement to getAnElement(theXML, item 1 of theElementPath)
        if foundElement is not missing value and ¬
            class of foundElement is XML element then
            return getElementFromPath(foundElement, rest of theElementPath)
        else
            return missing value
        end if
    end if
end getElementFromPath

on getAnElement(theXML, theElementName)
    -- find and return a particular element (this presumes there is only one instance of the element)
    repeat with anElement in XML contents of theXML
        if class of anElement is XML element and ¬
            XML tag of anElement is theElementName then
            return contents of anElement
        end if
    end repeat
    
    return missing value
end getAnElement

on getNamedElement(theXML, theElementName, theName)
    -- find and return the first element with a particular name attribute
    if class of theXML is XML element or class of theXML is XML document then
        repeat with anElement in XML contents of theXML
            try
                if class of anElement is XML element and ¬
                    XML tag of anElement is theElementName and ¬
                    |name| of XML attributes of anElement is theName then
                    return contents of anElement
                end if
            on error number -1728
                -- ignore this error
            end try
        end repeat
    else if class of theXML is list then
        repeat with anElement in theXML
            try
                if class of anElement is XML element and ¬
                    XML tag of anElement is theElementName and ¬
                    |name| of XML attributes of anElement is theName then
                    return contents of anElement
                end if
            on error number -1728
                -- ignore this error
            end try
        end repeat
    end if
    
    return missing value
end getNamedElement

on load_xml(the_file)
    -- read in a file
    set fRef to open for access file the_file without write permission
    set the_contents to (read fRef)
    close access fRef
    return the_contents
end load_xml

on parse_it(the_xml_data)
    -- parse XML data
    set the_xml to parse XML the_xml_data
    return the_xml
end parse_it

on string_to_list(the_string, the_delim)
    -- a sort of strtok, where we break a string into elements at delimiters
    my atid(the_delim)
    set the_list to (every text item of the_string) as list
    my atid("")
    return the_list
end string_to_list

on atid(the_delim)
    -- tell AppleScript what delimiter to use
    set AppleScript's text item delimiters to the_delim
end atid