I'm using Apple's iPhoto to organize my private photographs and Drupal is what comes to my mind first when there's need for a web-based solution. Having lots of pictures from a recent trip I want to show people I started thinking about some kind of web gallery. Being a developer I need to come up with something fancier than just some stock gallery product like Gallery2 (actually I don't really know that product so bear with me). I did some research and found some article about different approaches to build photo galleries in Drupal and also a nice video tutorial. I've used image module and gallery module before but the flexibility that CCK extended by imagefield and imagecache and views seem to offer is just too tempting. But how would I get my hundreds of pictures imported into my yet-to-be-built gallery site? There are plenty of exporter plug-ins for iPhoto sending pictures to galleries like said Gallery2, Flickr and so on. I did not find much information on how to write a plug-in for iPhoto but I found some AppleScript code that did just an export to Drupal. This one seemed to be very outdated but it was a good start. I started a thread on the Drupal developer mailing list which gave me interesting options but I stayed with the concept of using cURL because it's the most flexible and probably the fasted way for my one-time requirement and there are no dependencies. The missing piece was this handbook page on d.o.
Note: The following is a kind of tutorial but the result is just a custom script that needs to be adjusted to your scenario.
AppleScript is probably not the most powerful language but it allows us to call shell scripts. The idea is to get all the image information from iPhoto and then use shell commands to upload to a Drupal site. The first step is to extract the cURL commands from the PHP code from the handbook page so I don't need a separate script. Here are the shell commands to create content on a Drupal site:
First we log in which means getting a cookie with session data.
-s \
-c /tmp/curl-cookies.txt \
-b /tmp/curl-cookies.txt \
-F 'name=user' \
-F 'pass=pass' \
-F 'form_id=user_login' \
-F 'op=Log in' \
--output ~/response_login.html
This calls the user page with your username and password. Check response_login.html
to see if this has been successful.
Next we need to get the security token of the content creation form.
-s \
-c /tmp/curl-cookies.txt \
-b /tmp/curl-cookies.txt \
--output ~/response_create_form.html
I'm using a custom content type called "image" – substitute that with whatever your content type is. response_create_form.html
contains the HTML form to add an image including the security token which we can extract using a perl regular expression:
Finally we actually upload our content.
-s \
-c /tmp/curl-cookies.txt \
-b /tmp/curl-cookies.txt \
-F 'title=My Title' \
-F 'field_image[0][fid]=0' \
-F 'field_image[0][list]=1' \
-F 'files[field_image_0]=@/Users/me/myimage.jpg' \
-F 'body=My content.' \
-F 'name=Myself' \
-F 'status=1' \
-F 'revision=1' \
-F 'op=Save' \
-F 'form_id=image_node_form' \
-F 'form_token=63fe773e820d2a4565720ab3bd0fc991' \
Check your Drupal site – there should be new content. My content type contains an imagefield that takes the above values. The "@" makes cURL upload the actual file.
Now to upload all selected images in iPhoto to the Drupal site I merge the snippets above with the AppleScript from iPhotoToDrupal:
Update: I had an issue with special characters as I entered "'" in iPhoto's description field. I found out about quoted form of variablename
which is used to escape strings in AppleScript to use them in shell scripts. This funtion puts the string in single quotes automatically so I couldn't use it like " -F 'body=" & quoted form of this_comment & "'"
. Fortunately it's also possible to quote the value only like -F body='xxx'
so " -F body=" & quoted form of this_comment
works. Just being at it I replaced it for other variables also. Finally, I added a "Done" dialog.
set DrupalPassword to "pass"
set DrupalSite to "http://localhost/drupal/"
set DrupalContentType to "image"
set DrupalAddPage to "?q=node/add/" & DrupalContentType
set CookieFile to "/tmp/curl-cookies.txt"
set curlLogin to "curl"
set curlLogin to curlLogin & " " & DrupalSite & "?q=user"
set curlLogin to curlLogin & " -s"
set curlLogin to curlLogin & " -c " & CookieFile
set curlLogin to curlLogin & " -b " & CookieFile
set curlLogin to curlLogin & " -F 'name=" & DrupalUsername & "'"
set curlLogin to curlLogin & " -F 'pass=" & DrupalPassword & "'"
set curlLogin to curlLogin & " -F 'op=Log in'"
set curlLogin to curlLogin & " -F 'form_id=user_login'"
do shell script curlLogin
set curlAddForm to "curl"
set curlAddForm to curlAddForm & " " & DrupalSite & DrupalAddPage
set curlAddForm to curlAddForm & " -s"
set curlAddForm to curlAddForm & " -c " & CookieFile
set curlAddForm to curlAddForm & " -b " & CookieFile
set tokenSrc to do shell script curlAddForm
set token to do shell script "echo '" & tokenSrc & "' | perl -pe 's/.*edit-" & DrupalContentType & "-node-form-form-token\" *value=\"([^\"]*)\".*/$1/s';"
tell application "iPhoto"
activate
try
copy (my selected_images()) to these_images
-- Make sure we have one or more image selected, and if we do, then grab the details of each and upload
if these_images is false or (the count of these_images) is 0 then
error "Please select one or more images."
end if
repeat with this_image in these_images
set this_imagefile to ((image path of this_image) as POSIX file)
set this_uploadfile to (POSIX path of this_imagefile)
set this_comment to (the comment of this_image) as string
set this_name to the title of this_image
set curlCreate to "curl"
set curlCreate to curlCreate & " " & DrupalSite & DrupalAddPage
set curlCreate to curlCreate & " -s"
set curlCreate to curlCreate & " -c " & CookieFile
set curlCreate to curlCreate & " -b " & CookieFile
set curlCreate to curlCreate & " -F title=" & quoted form of this_name
set curlCreate to curlCreate & " -F field_image[0][fid]=0"
set curlCreate to curlCreate & " -F field_image[0][list]=1"
set curlCreate to curlCreate & " -F files[field_image_0]=@" & quoted form of this_uploadfile
set curlCreate to curlCreate & " -F body=" & quoted form of this_comment
set curlCreate to curlCreate & " -F name=" & quoted form of DrupalUsername
set curlCreate to curlCreate & " -F status=1"
set curlCreate to curlCreate & " -F revision=1"
set curlCreate to curlCreate & " -F op="
set curlCreate to curlCreate & " -F form_id=" & DrupalContentType & "_node_form"
set curlCreate to curlCreate & " -F form_token=" & token
do shell script curlCreate
end repeat
on error error_message number error_number
if the error_number is not -128 then
display dialog error_message buttons {"Cancel"} default button 1
end if
end try
end tell
display dialog "Done." buttons {"Ok"} default button 1
-- Taken right out the "Show Image File" AppleScript on the Apple site:
-- http://www.apple.com/applescript/iphoto/
on selected_images()
tell application "iPhoto"
try
-- get selection
set these_items to the selection
-- check for single album selected
if the class of item 1 of these_items is album then error
-- return the list of selected photos
return these_items
on error
return false
end try
end tell
end selected_images
Just go to iPhoto, select some images and start the script. The images including title and description will be uploaded as new nodes to your Drupal site.
Comments
Der Inhalt dieses Feldes wird nicht öffentlich zugänglich angeze
Hi-
Nice job. I've been trying to use your applescript but am getting an error, "the command exited with a non-zero status". My Drupal install has clean URLs on. Do I need to modify the strings in your script to fit, or will the "non-clean" URLs still work?
Here's the details on my parts: Drupal 6.17 iPhoto 7.1.5 (aka iPhoto '08)
Thanks!
I needed to change reg regex....
In my Drupal 7.12 i needed to alter your regex line :
to:
Somehow the name attribute was "form_token" and not "edit-image-node-form-form-token" as your code suggested.
Now it works great. Thanks for sharing!
I also added on the fly image resizing. All credits here go to https://discussions.apple.com/thread/2174350?start=0&tstart=0 from where I borrowed the resize code.
set DrupalUsername to "admin"
set DrupalPassword to "XXXXXX"
set DrupalSite to "http://localhost/~arminhelbach/drupal7/"
set DrupalContentType to "image"
set DrupalAddPage to "?q=node/add/" & DrupalContentType
set CookieFile to "/tmp/curl-cookies.txt"
set tmp_path to "/tmp"
set curlLogin to "curl"
set curlLogin to curlLogin & " " & DrupalSite & "?q=user"
set curlLogin to curlLogin & " -s"
set curlLogin to curlLogin & " -c " & CookieFile
set curlLogin to curlLogin & " -b " & CookieFile
set curlLogin to curlLogin & " -F 'name=" & DrupalUsername & "'"
set curlLogin to curlLogin & " -F 'pass=" & DrupalPassword & "'"
set curlLogin to curlLogin & " -F 'op=Log in'"
set curlLogin to curlLogin & " -F 'form_id=user_login'"
do shell script curlLogin
set curlAddForm to "curl"
set curlAddForm to curlAddForm & " " & DrupalSite & DrupalAddPage
set curlAddForm to curlAddForm & " -s"
set curlAddForm to curlAddForm & " -c " & CookieFile
set curlAddForm to curlAddForm & " -b " & CookieFile
set tokenSrc to do shell script curlAddForm
set token to do shell script "echo '" & tokenSrc & "' | grep form_token | perl -pe 's/.*name=\"form_token\" *value=\"([^\"]*)\".*/$1/s';"
tell application "iPhoto"
activate
try
copy (my selected_images()) to these_images
-- Make sure we have one or more image selected, and if we do, then grab the details of each and upload
if these_images is false or (the count of these_images) is 0 then
error "Please select one or more images."
end if
repeat with this_image in these_images
set this_imagefile to ((image path of this_image) as POSIX file)
set this_comment to (the comment of this_image) as string
set this_name to the title of this_image
tell application "Image Events" to set t to PNG
copy (my convert_image(this_imagefile as alias, tmp_path, longest_side)) to tmpimagefile
set this_uploadfile to (POSIX path of tmpimagefile)
set curlCreate to "curl"
set curlCreate to curlCreate & " " & DrupalSite & DrupalAddPage
set curlCreate to curlCreate & " -s"
set curlCreate to curlCreate & " -c " & CookieFile
set curlCreate to curlCreate & " -b " & CookieFile
set curlCreate to curlCreate & " -F title=" & quoted form of this_name
set curlCreate to curlCreate & " -F field_image[und][0][fid]=0"
set curlCreate to curlCreate & " -F field_image[und][0][list]=1"
set curlCreate to curlCreate & " -F files[field_image_und_0]=@" & quoted form of this_uploadfile
set curlCreate to curlCreate & " -F body=" & quoted form of this_comment
set curlCreate to curlCreate & " -F name=" & quoted form of DrupalUsername
set curlCreate to curlCreate & " -F status=1"
set curlCreate to curlCreate & " -F revision=1"
set curlCreate to curlCreate & " -F op="
set curlCreate to curlCreate & " -F form_id=" & DrupalContentType & "_node_form"
set curlCreate to curlCreate & " -F form_token=" & token
do shell script curlCreate
do shell script "rm '" & this_uploadfile & "'"
end repeat
on error error_message number error_number
if the error_number is not -128 then
display dialog error_message buttons {"Cancel"} default button 1
end if
end try
end tell
display dialog "Done." buttons {"Ok"} default button 1
-- Taken right out the "Show Image File" AppleScript on the Apple site:
-- http://www.apple.com/applescript/iphoto/
on selected_images()
tell application "iPhoto"
try
-- get selection
set these_items to the selection
-- check for single album selected
if the class of item 1 of these_items is album then error
-- return the list of selected photos
return these_items
on error
return false
end try
end tell
end selected_images
on convert_image(this_item, target_path, longest_side)
tell application "Image Events"
try
launch
-- open the image file
set this_image to open this_item
tell application "Finder"
set new_item to ((target_path) as string) & (name of this_item) & ".jpg"
end tell
copy dimensions of this_image to {current_width, current_height}
if current_width is greater than current_height then
set new_height to (longest_side * current_height) / current_width
if (new_height * longest_side) < (current_width * current_height) then
scale this_image to size longest_side
end if
else
if (new_height * longest_side) < (current_width * current_height) then
set new_height to (longest_side * current_width) / current_height
scale this_image to size new_height
end if
end if
save this_image in new_item as JPEG
return new_item
on error msg
return msg
end try
end tell
end convert_image