iPhoto import from folders AppleScript

Preface: Having upgraded my phone (Nokia N8) firmware to “Belle” — whatever version that is, the Nokia Multimedia Transfer application no longer imports photos to iPhoto.* Tragic because the camera is the sole reason I bought this phone. Ordinarily this would not be a problem since the phone uses a “DCIM” folder at the drive root and can store images with 8 character names (5 of which you set yourself). But not every photo app does store them there or with a “proper” name. Even though there exists an “Images” folder in the drive root that I know gets used, Mass Storage.app does not access it. Could be another naming convention similar to DCF

This is an AppleScript to get around this limitation, and to allow (in my case at least) the importing of camera files named by date. In short you choose which folders you want this script to tell iPhoto to import from and can be used with any folder(s), no specific device required.

Notable: Uses ‘defaults’ to store and load folder paths in a property list (.plist) file.

A little more use shows this to have some bugs. This cannot be run as a stand alone script; it must be saved as an application.

I cannot assume responsibility should you lose data while using the “Delete” option, although it does not delete a file from the device until after the file has been moved (copied) to your Temporary Items Folder where it should still be. This script is put up as an example for anyone to use, modify, or learn from, not to solve any issues other than my own. If any errors are reported while running this you should click “Cancel”.

To open the Temporary Items folder:
tell application "Finder" to reveal (path to temporary items folder)

(*
http://strawhousepig.net/

Can be run from the script menuextra if saved as an application,
or by a Folder Action via AppleScript or Automator (probably easiest).

THERE MAY BE ISSUES WITH REPLACING FILES. Script *should* die in that event (untested).
Trying to keep read_array() and write_array() as generic as possible for use else where. *hint-hint*
Doing a lot of re-reading of the plist array to be able to repeat functions after adding to or deleting from it
Property list array delimiter is "%%"

Structure
----------------
Start
Count items to import.
If nothing to count: Add folder
If > 0: ask to import, manage folders, or cancel.
  Else: Manage folders.
If mange folders: Ask to add, or remove folders, prompt for another, Start.
If import: Ask to delete from device
  If delete: Move items to temp dir, tell iPhoto to import temp dir
    (iPhoto is slower than the script and does not return true or false on completion of import.
    Make iPhoto work away from the folders so the script doesn't run ahead deleting items.
    Unfortunately telling Finder to "move" a file from one disk to another leaves the original 
    so we are 'rm 'ing the files one by one as they are moved.
    Also there are no auto increments in the case of multiple files with the same name.)
  Else: Tell iPhoto to import folders.
If cancel:

*)

property the_dom : "iphoto.import.this"
property the_key : "folders"
start()

on start()
  set import_folders to read_array(the_dom, the_key)
  if import_folders is not false then
    set image_count to count_folder(import_folders)
    if image_count is greater than 0 then
      set start_button to button returned of (display dialog (image_count as text) & " items in import folders." buttons {"Cancel", "Manage Folders...", "Import..."} default button 3)
      if start_button is "Import..." then
        import_files(import_folders)
      else
        manage_folders("You rang?")
      end if
    else
      manage_folders("No items to import.")
    end if
  else
    add_folder()
  end if
end start

on import_files(import_folders)
  set import_button to button returned of (display dialog "Delete imported items from device?" buttons {"Cancel", "Keep", "Delete"} default button 3)
  if import_button is not false then
    try
      set the_date to (month of (current date) as string) & " " & day of (current date) & " " & year of (current date) & " " & hours of (current date) & "h" & minutes of (current date) & "m" & seconds of (current date) & "s"
      tell application "Finder"
        set temp_folder to (make new folder at (path to temporary items folder) with properties {name:the_date}) as alias
        repeat with i in import_folders
          set these_items to every item of folder (i as POSIX file)
          repeat with ii in these_items
            move ii to temp_folder
            if import_button is "Delete" then
              do shell script "rm " & quoted form of (POSIX path of (ii as alias))
            end if
          end repeat
        end repeat
        set import_folders to {POSIX path of temp_folder}
      end tell
    on error theMsg
      display dialog theMsg
    end try
    tell application "iPhoto"
      activate
      try
        repeat with i in import_folders
          import from i
        end repeat
      end try
    end tell
  end if
end import_files

on manage_folders(the_dialog)
  set import_folders to read_array(the_dom, the_key)
  set manage_button to button returned of (display dialog the_dialog buttons {"Cancel", "Delete Folders...", "Add Folder..."} default button 1)
  if manage_button is "Add Folder..." then
    add_folder()
  else
    if manage_button is "Delete Folders..." then
      delete_folders()
    end if
  end if
end manage_folders

on count_folder(import_folders)
  set item_count to 0
  repeat with i in import_folders
    try
      set item_count to item_count + (do shell script "ls '" & i & "' | wc -l")
    on error errMsg
      display dialog errMsg
    end try
  end repeat
  return item_count
end count_folder

on add_folder()
  set import_folders to read_array(the_dom, the_key)
  try
    set this_folder to POSIX path of (choose folder)
  on error
    start()
  end try
  if this_folder is not false then
    -- write_array will return true on success or an error if a duplicate entry is found.
    set is_written to write_array(the_dom, the_key, this_folder, import_folders)
    if is_written is true then
      set add_button to button returned of (display dialog ((this_folder) as text) & " added to import list." buttons {"Back", "Another"})
      if add_button is "Back" then
        start()
      else
        add_folder()
      end if
    else
      display dialog "Oops!: " & is_written
      manage_folders("You rang?")
    end if
  end if
  start()
end add_folder

on delete_folders()
  set import_folders to read_array(the_dom, the_key)
  set new_folders to ""
  set the_goner to choose from list import_folders with prompt "Choose folders to remove from the import list." OK button name "Delete" with multiple selections allowed
  if the_goner is not false then
    repeat with i in import_folders
      if i is not in the_goner then
        set new_folders to new_folders & ""%%" & i & "%%","
      end if
    end repeat
    set new_folders to characters 1 through ((count of characters of new_folders) - 1) of new_folders as string
    do shell script "defaults write " & the_dom & " '{ " & the_key & " = (" & new_folders & "); }'"
  end if
  start()
end delete_folders

on read_array(the_dom, the_key)
  try
    set {tid, text item delimiters} to {text item delimiters, "%%"}
    set read_plist to text items of (do shell script "defaults read " & the_dom & " " & the_key)
    set str2array to {}
    repeat with i from 2 to (count read_plist) by 2
      set this_item to item i of read_plist
      set end of str2array to this_item
    end repeat
    set text item delimiters to tid
    return str2array
  on error
    return false
  end try
end read_array

on write_array(the_dom, the_key, the_value, old_values)
  -- old_values is what is already in the array. Used for duplicate checking.
  try
    if old_values is not false then
      if the_value is not in old_values then
        do shell script "defaults write " & the_dom & " " & the_key & " -array-add '%%" & the_value & "%%'"
      else
        error "Item is already added."
      end if
    else
      do shell script "defaults write " & the_dom & " " & the_key & " -array-add '%%" & the_value & "%%'"
    end if
    return true
  on error theMsg
    return theMsg
  end try
end write_array

*UPDATE: Turns out the camera was set to name photos using the date, rather than incremental numbers. The DCIM 8 character naming spec apparently applies to folders and the files they contain. Why? Oh well. Always good to flex the brain to solve a problem manually.

Leave a Reply

Your email address will not be published. Required fields are marked *