|
hipSync.scpt (AppleScript) |
Sunday, May 25, 2003 |
| Prototype sync script between Palm Desktop and iPod. | |
|
(* hipSync 1.0d2 / Nicholas Riley <hipsync@sabi.net> / 25 May 2003 This script is in the public domain. *) property this_iPod : "" property events_file : "Palm Desktop Events" property todos_file : "Palm Desktop To Dos" property addresses_file : "Palm Desktop Addresses" property section_length : 3950 property crlf : return & " " property ical_header : "BEGIN:VCALENDAR" & crlf & ¬ "CALSCALE:GREGORIAN" & crlf & ¬ "METHOD:PUBLISH" & crlf & ¬ "VERSION:2.0" & crlf & ¬ "PRODID:hipSync" & crlf on run try if this_iPod is "" then select_iPod() sync_memos() sync_todos() sync_events() sync_addresses() sync_music() on error error_message number the error_number if the error_number is not -128 then display dialog error_message buttons {"OK"} default button 1 end if end try end run -- •••••••••••••••••••••••••••••••• Sync Music •••••••••••••••••••••••••••••••• on sync_music() local playlists_folder, playlist_name, iPod_name local iPod_source, iPod_playlist, iPod_library, iPod_track local library_source, local_library, local_playlist, local_track, local_tracks, db_id tell application "Finder" set iPod_name to this_iPod's name set playlists_folder to my get_folder(my get_folder(home, "Music"), ¬ "Playlists for iPod “" & iPod_name & "”") end tell tell application "iTunes" set library_source to source 1 whose kind is library set local_library to library playlist 1 of library_source set local_playlist to my get_playlist(the library_source, "hipSync To Upload") set iPod_source to source 1 whose name is iPod_name and kind is iPod set iPod_library to library playlist 1 of iPod_source repeat with playlist_name in list folder playlists_folder without invisibles set playlist_name to playlist_name as string set iPod_playlist to my get_playlist(iPod_source, playlist_name) repeat with local_track in tracks of local_playlist delete (tracks of local_library whose database ID = (local_track's database ID)) end repeat add alias ((playlists_folder as string) & playlist_name) to local_playlist repeat with iPod_track in iPod_playlist's tracks set local_tracks to ((local_playlist's tracks) whose name = (iPod_track's name as string) ¬ and size = (iPod_track's size as real)) if length of local_tracks is 0 then set db_id to iPod_track's database ID delete (tracks of iPod_library whose database ID = db_id) else set db_id to database ID of item 1 of local_tracks delete (tracks of local_library whose database ID = db_id) end if end repeat if size of local_playlist > free space of iPod_source then error "Playlist “" & playlist_name & "” will not fit on your iPod. To upload this playlist, delete " & ¬ (round ((size of local_playlist) - (free space of iPod_source)) / 1024 / 1024 * 100 rounding up / 100 & ¬ " MB of music and/or files from your iPod.") end if duplicate local_playlist's tracks to iPod_playlist end repeat delete local_playlist end tell end sync_music on get_playlist(the_source, playlist_name) local the_playlist tell application "iTunes" set the_playlist to (playlists of the_source whose name is playlist_name) if the_playlist's length is 1 then set the_playlist to item 1 of the_playlist else set the_playlist to (make user playlist at the_source with properties {name:playlist_name}) end if end tell end get_playlist -- •••••••••••••••••••••••••••••••• Sync Addresses •••••••••••••••••••••••••••••••• on sync_addresses() local contacts_folder set contacts_folder to get_iPod_folder("Contacts") try tell application "Finder" to delete file addresses_file of contacts_folder end try do_export() tell application "System Events" to tell window "Export: Palm Desktop" of process "Palm Desktop" keystroke "a" with command down keystroke POSIX path of contacts_folder & (ASCII character 13) & addresses_file tell pop up button 3 click tell menu 1 to click menu item "Addresses" end tell tell pop up button 1 click tell menu 1 to click menu item "vCard" end tell keystroke (ASCII character 13) end tell end sync_addresses -- •••••••••••••••••••••••••••••••• Sync Events •••••••••••••••••••••••••••••••• on sync_events() local calendars_folder set calendars_folder to get_iPod_folder("Calendars") try tell application "Finder" to delete file events_file of calendars_folder end try do_export() tell application "System Events" to tell window "Export: Palm Desktop" of process "Palm Desktop" keystroke "a" with command down keystroke POSIX path of calendars_folder & (ASCII character 13) & events_file if value of pop up button 3 is not "Date Book" then error "“Date Book” not selected" tell pop up button 1 click tell menu 1 to click menu item "vCal" end tell keystroke (ASCII character 13) end tell end sync_events on do_export() tell application "Palm Desktop" activate end tell tell application "System Events" with timeout of 10 seconds tell menu bar 1 of process "Palm Desktop" to click menu item "Export…" of menu "File" end timeout end tell end do_export -- •••••••••••••••••••••••••••••••• Sync To Dos •••••••••••••••••••••••••••••••• on sync_todos() local target_file, open_target_file, write_result, the_todo, todo_properties, ical_data set target_file to get_iPod_folder("Calendars") & todos_file try set the target_file to the target_file as text set the open_target_file to ¬ open for access file target_file with write permission -- XXX want no creator instead... tell application "Finder" to set properties of file target_file to {file type:"iCal", creator type:"iCal"} set eof of the open_target_file to 0 write ical_header to the open_target_file starting at eof tell application "Palm Desktop" repeat with the_todo in to dos set todo_properties to the_todo's properties set todo_category to my get_category(todo_properties's primary category) -- SHOULD fold at 75 characters, but I'm lazy (RFC 2445 §4.1) set ical_data to "BEGIN:VTODO" & crlf & "SUMMARY:" & todo_properties's title & crlf set ical_data to ical_data & ¬ my get_iCal_categories(todo_properties's primary category, todo_properties's secondary category) if todo_properties's completed then set ical_data to ical_data & "STATUS:COMPLETED" & crlf set ical_data to ical_data & my get_iCal_datetime("COMPLETED", todo_properties's completion date) end if if todo_properties's private then set ical_data to ical_data & "CLASS:PRIVATE" & crlf set ical_data to ical_data & my get_iCal_priority(todo_properties's priority) set ical_data to ical_data & my get_iCal_datetime("DUE", todo_properties's due date) -- reminder value is in days if todo_properties's reminder is not missing value then ¬ set ical_data to ical_data & "BEGIN:VALARM" & crlf & ¬ "TRIGGER:-P" & todo_properties's reminder & "D" & crlf & ¬ "ACTION:DISPLAY" & crlf & ¬ "DESCRIPTION:" & todo_properties's title & crlf & ¬ "END:VALARM" & crlf -- XXX handle repeating to-dos set ical_data to ical_data & "END:VTODO" & crlf my write_data_to_file(ical_data, open_target_file) end repeat end tell write "END:VCALENDAR" & crlf to the open_target_file starting at eof close access the open_target_file on error error_message number error_number try close access file target_file end try error "There was a problem writing to dos to a file on the iPod: " & error_message & " (" & error_number & ")" end try end sync_todos on write_data_to_file(the_data, open_file) write the_data to open_file starting at eof end write_data_to_file -- •••••••••••••••••••••••••••••••• Sync Memos •••••••••••••••••••••••••••••••• on sync_memos() global notes_folder local the_memo, memo_properties, memo_category set notes_folder to get_iPod_folder("Notes") tell application "Palm Desktop" repeat with the_memo in memos set memo_properties to the_memo's properties set memo_category to my get_category(memo_properties's primary category) my add_note(my fix_title(memo_properties's title), memo_properties's contents, memo_category) end repeat end tell end sync_memos on fix_title(the_title) return my replace_chars(the_title, "Handheld Note: ", "") end fix_title on add_note(this_name, this_data, this_category) global notes_folder set the data_length to the length of this_data set this_name to make_filename(this_name) if the data_length is less than 4000 then set the target_file to get_folder(notes_folder, make_filename(this_category)) & this_name set the write_result to my write_to_file(this_data, target_file, false) if the write_result is false then error "There was a problem writing the note “" & this_name & "” to the iPod." end if else set the file_count to round (data_length / section_length) rounding up repeat with i from 1 to the file_count set the file_number to my add_leading_zeros(i, 1) set the next_number to my add_leading_zeros((i + 1), 1) set the filename to this_name & "." & file_number set the nextname to this_name & "." & next_number if i is 1 then -- first list item set the section_text to text from character 1 to section_length of this_data & "..." & return & return & tab & "[[<a href=\"" & nextname & "\">NEXT PAGE</a>]]" set the target_file to (notes_folder as string) & this_name else if i is the file_count then -- last list item set the section_text to "[[PAGE " & (i as string) & " of " & (file_count as string) & "]]" & return & return & "..." & (text from character (section_length * (i - 1)) to -1 of this_data) set the target_file to (notes_folder as string) & filename else -- other list items set the section_text to "[[PAGE " & (i as string) & " of " & (file_count as string) & "]]" & return & return & "..." & (text from character (section_length * (i - 1)) to (section_length * i) of this_data) & "..." & return & return & tab & "[[<a href=\"" & nextname & "\">NEXT PAGE</a>]]" set the target_file to (notes_folder as string) & filename end if --set the target_file to (notes_folder as string) & filename set the write_result to my write_to_file(section_text, target_file, false) if the write_result is false then error "There was a problem writing note file “" & filename & "” to the iPod." end repeat end if end add_note -- •••••••••••••••••••••••••••••••• Find iPod •••••••••••••••••••••••••••••••• on select_iPod() -- check for iPods set the mounted_iPods to my locate_iPods() -- check for iPod count if the mounted_iPods is {} then error "No iPod is connected to this computer." else if the (count of the mounted_iPods) is greater than 1 then -- choose iPod set the ipod_names to {} repeat with i from 1 to the count of the mounted_iPods set this_iPod to item i of the mounted_iPods tell application "Finder" set the end of the ipod_names to the name of this_iPod end tell end repeat set this_name to (choose from list ipod_names with prompt "Pick the iPod to use:") as string if this_name is "false" then error number -128 repeat with i from 1 to the count of the ipod_names if item i of the ipod_names is this_name then set this_iPod to item i of the mounted_iPods exit repeat end if end repeat else set this_iPod to item 1 of the mounted_iPods end if return this_iPod end select_iPod on locate_iPods() set mounted_iPods to {} repeat with this_disk in list disks set these_items to list folder (this_disk as alias) if "iPod_Control" is in these_items then set the end of the mounted_iPods to (this_disk as alias) end if end repeat return mounted_iPods end locate_iPods -- •••••••••••••••••••••••••••••••• File utilities •••••••••••••••••••••••••••••••• on get_folder(parent_item, folder_name) tell application "Finder" if not (exists folder folder_name of parent_item) then make new folder at parent_item with properties {name:folder_name} end if return (folder folder_name of parent_item) as alias end tell end get_folder on get_iPod_folder(sub_name) local iPod_folder set iPod_folder to get_folder(get_folder(this_iPod, sub_name), "Palm Desktop") tell application "Finder" to delete every item of iPod_folder return iPod_folder end get_iPod_folder on write_to_file(this_data, target_file, append_data) try set the target_file to the target_file as text set the open_target_file to ¬ open for access file target_file with write permission if append_data is false then ¬ set eof of the open_target_file to 0 write this_data to the open_target_file starting at eof close access the open_target_file return true on error try close access file target_file end try return false end try end write_to_file -- •••••••••••••••••••••••••••••••• String utilities •••••••••••••••••••••••••••••••• on get_category(cat) if cat is not missing value then return cat's name else return "«uncategorized»" end if end get_category on get_iCal_categories(cat1, cat2) if cat1 is missing value then if cat2 is missing value then return "" return "CATEGORIES:" & cat2's name & crlf end if if cat2 is missing value then return "CATEGORIES:" & cat1's name & crlf return "CATEGORIES:" & cat1's title & "," & cat2's name & crlf end get_iCal_categories -- XXX should cut off >255 chars, need to convert to Unicode first on make_filename(str) -- XXX until Apple fixes bug in 'open for access', need to replace slashes too return my replace_chars(my replace_chars(str, "/", "-"), ":", "-") end make_filename on replace_chars(this_text, search_string, replacement_string) set AppleScript's text item delimiters | |