#!/usr/bin/env python # # convert.py -- an Address Book -> Google Voice bookmark contact converter thing -- ** MAC ONLY ** # # WHAT THIS SCRIPT DOES: # # Read this: # # http://www.ironicsans.com/2009/08/the_google_voice_speed_dial_bo.html # # Back? Okay- This script does that, only it converts as many of your Address Book contacts as it can into a Netscape # bookmark file. From there, you can import to Safari, sync with your iPhone, and/or put the .htm somewhere # for a quick web-page "phonebook". # # HOW TO USE IT # # 1. Copy/paste this whole python script to a text editor. Then change the two variables below, # "longstring" and "myiphonenumber", using the values described at http://www.ironicsans.com/gv/. longstring = "LONGSTRINGOFCHARACTERS" # the long string Google gives you myiphonenumber= '2223334444' # your iphone phone number. # 2. Save the script as "convert.py" on your Desktop. # # 3. From the Terminal (Applications->Utilities->Terminal.app), type: # # python Desktop/convert.py # # 4. If it worked, a file called "GV-Contacts-bookmarks.htm" should appear on your Desktop. You now can import it into Safari # (File->Import Bookmarks...), and then sync it to your iPhone. Note: if by some freakish coincidence you already have # a file on your Desktop named "GV-Contacts-bookmarks.htm", it'll be overwritten. # # 5. Also, there's a mini-report at the bottom of the .htm file (view with a browser) showing which contacts were NOT added # due to weirdness in the phone number or whatnot. # # Caveats: This only runs on recent Macs. I have neither Google Voice nor an iPhone, so I have no idea if this works at all. # I have an Android phone, which is way better. I wrote this solely for my own entertainment. See disclaimer below. # # You're welcome. # # All code is by me except where noted, particularly the addressBookToList() function) and a regedit expression. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. And this is in no way affiliated with or endorsed by Google or Apple. from AddressBook import * import re from os import path #--------------------------------- # the method below was written as a tutorial by Patrick and can be found at http://www.programmish.com/?p=26 # thanks for providing this! def addressBookToList(): """ Read the current user's AddressBook database, converting each person in the address book into a Dictionary of values. Some values (addresses, phone numbers, email, etc) can have multiple values, in which case a list of all of those values is stored. The result of this method is a List of Dictionaries, with each person represented by a single record in the list. """ # get the shared addressbook and the list of # people from the book. ab = ABAddressBook.sharedAddressBook() people = ab.people() peopleList = [] # convert the ABPerson to a hash for person in people: thisPerson = {} props = person.allProperties() for prop in props: # skip some properties if prop == "com.apple.ABPersonMeProperty": continue elif prop == "com.apple.ABImageData": continue # How we convert the value depends on the ObjC # class used to represent it val = person.valueForProperty_(prop) if type(val) == objc.pyobjc_unicode: # Unicode String thisPerson[prop.lower()] = val elif issubclass(val.__class__, NSDate): # NSDate thisPerson[prop.lower()] = val.description() elif type(val) == ABMultiValueCoreDataWrapper: # List -- convert each item in the list # into the proper format thisPerson[prop.lower()] = [] for valIndex in range(0, val.count()): indexedValue = val.valueAtIndex_(valIndex) if type(indexedValue) == objc.pyobjc_unicode: # Unicode string thisPerson[prop.lower()].append(indexedValue) elif issubclass(indexedValue.__class__, NSDate): # Date thisPerson[prop.lower()].append(indexedValue.description()) elif type(indexedValue) == NSCFDictionary: # NSDictionary -- convert to a Python Dictionary propDict = {} for propKey in indexedValue.keys(): propValue = indexedValue[propKey] propDict[propKey.lower()] = propValue thisPerson[prop.lower()].append(propDict) peopleList.append(thisPerson) return peopleList # ---------------------------- # phonePattern thanks to Mark Pilgrim at http://diveintopython.org/regular_expressions/phone_numbers.html phonePattern = re.compile(r'(\d{3})\D*(\d{3})\D*(\d{4})\D*(\d*)$') # ---------------------------- # okay, back to stuff written by me worked = 0 didntwork = 0 didnt ="" bookmark ="""
\n' peoplelist = addressBookToList() for person in peoplelist: if "phone" in person: for number in person["phone"]: name = "" phone = person["phone"] if "first" in person: name += person["first"] if "last" in person: if name is not "": name += " " name += person["last"] if "organization" in person: if name is not "": name += " at " name += person["organization"] try: num = phonePattern.search(number).groups() fixednum = num[0] + num[1] + num[2] if fixednum.startswith("1"): fixednum = fixednum.lstrip("1") name.strip('\'"') bookmark += ' '*16 +'
" + str(worked) + " contacts converted (hopefully successfully). If there were any errors, sorry.
" if didntwork > 0: bookmark += "At least " + str(didntwork) + " contacts failed to convert. (" + didnt + " and maybe more...)\n\n" f = open(path.expanduser('~') + '/Desktop/GV-Contacts-bookmarks.htm', 'w') f.write(bookmark) f.close()