Skip to content

Instantly share code, notes, and snippets.

@amalex5
Last active April 12, 2017 01:21
Show Gist options
  • Save amalex5/a22ed2acdf983ff2d7bbecd49a9999b0 to your computer and use it in GitHub Desktop.
Save amalex5/a22ed2acdf983ff2d7bbecd49a9999b0 to your computer and use it in GitHub Desktop.
"""
this is a set of scripts that have evolved over the years to make life easier with my fliphone
my LG VX8150 lets you download all of your contacts to your computer as vCard (.vcf) files
and these scripts can parse them and save them into a variety of convenient formats
"""
def loadContactsFromPhone():
"""
no, just kidding. there doesn't seem to be an easy way to automate the phone-> computer contacts transfer
here are my manual steps
1) on the phone: contacts menu -> options -> "2. Manage Contacts" -> "4. Send" -> "4. Via Bluetooth"
2) which gets you to "Send Name Card" pane and a list of all your contacts
3) options -> "2. Mark All"
4) and then "Done"
5) and then select device
the contacts arrive each as a seperte .vcf (vCard) file
"""
def loadContactsFromVCards(directory):
"""
the LG VX8150 lets you download all your contacts as vCard (.vcf) files
this function opens all the .vcf files in the given directory and pulls out the name and phone number
(in principle it might be nicer to use a vCard library
in practice, they all seemed shitty, and it works fine to pull these two fields out with regexes
a parser would be nicer, too.
this function returns a python list of contacts in the form, [{'displayName': 'Alistair Russell', 'number': 6073421613}]
"""
import re,os
namePattern = re.compile("(?<=FN\;CHARSET\=utf\-8:)(.*)")
phonePattern = re.compile("(?<=TEL;(?:CELL|HOME):)(.*)")
contacts = []
files = filter(lambda x: x[0] != '#' and x[-4:] == '.vcf' , os.listdir(directory))
for file in files:
contents = open(directory+file,"r").read()
contact = {}
if namePattern.findall(contents) and phonePattern.findall(contents):
phname = namePattern.findall(contents)[0][:-1]
phone = phonePattern.findall(contents)[0]
if phone[0] == "1": phone = phone[1:]
contact['number'] = int(phone)
contact['displayName'] = phname
#print contact
splits = phname.split(' ')
if len(splits) >= 2:
testFirstName = splits[0]
testLastName = splits[1]
contact['firstName'] = testFirstName
contact['lastName'] = testLastName
contacts.append(contact)
print str(len(contacts)) + " contacts processed!"
return contacts
def prettyPrintContacts(contacts):
pp = ''
for i in range(len(contacts)):
thisContact = contacts[i]
pp += thisContact['displayName'] + ' ' + printPhone(str(thisContact['number'])) + '\n'
if i != (len(contacts) -1):
nextContact = contacts[i+1]
if nextContact['displayName'][0] != thisContact['displayName'][0]:
pp += '\n'
return pp
def loadContactsFromJson(sourcePath):
import json
myJsonFile = open(sourcePath,'rb').read()
decoded = json.loads(myJsonFile)
decoded.sort(key=lambda item: item['displayName'].lower() ) #have to convert it to lowercase or it sorts by case
return decoded
def loadContactsFromCSV(sourcePath):
# load contacts from a comma-delimeted CSV file
# no fancy parsing or anything, so breaks easily
contacts = []
with open(sourcePath,'r+') as f:
lines = f.readlines()
for line in lines:
contact = {}
splat = line.split(",")
contact['displayName'] = splat[0]
contact['number'] = int(splat[1])
contacts.append(contact)
return contacts
def diffContacts(contacts1,contacts2):
"""
i got a new phone, and it turned out verizon had auto-saved all my contacts
but from like 2014
so i wrote this to figure out which new contacts I needed to re-enter by hand
holy shit, list comprehensions make this so easy!
"""
additions = [x for x in contacts2 if not contactPresentByNumber(x['number'],contacts1)]
deletions = [x for x in contacts1 if not contactPresentByNumber(x['number'],contacts2)]
print "deletions:\n----------"
for contact in deletions: print prettyPrintContact(contact)
print ""
print "additions:\n----------"
for contact in additions: print prettyPrintContact(contact)
return {'additions':additions, 'deletions':deletions}
def contactPresentByNumber(number,contacts):
if len(filter(lambda z: z['number'] == number,contacts)) > 0 : return True
else: return False
def updateMergeContacts(contacts1,contacts2):
diff = diffContacts(contacts1,contacts2)
return contacts1 + diff['additions'] #screw deletions!
def printPhone(number):
"""
pretty-prints phone numbers into the form "(607) 257-2653"
accepts as input unformatted phone numbers ("6072572653") either as string or int
(aaagh weak typing!)
"""
# coerce if int
if type(number) == int: number = str(number)
#strip leading 1
if number[0] == "1": number = number[1:]
#deal with weird short text numbers
if len(number) < 10: return number
return "(" + number[0:3] + ") " + number[3:6] + "-" + number[6:]
def today():
"""
returns today's date in the format "19861204"
used for prepending to files
"""
import datetime
return datetime.date.today().strftime("%Y%m%d")
def todayPretty():
"""
returns today's date in the format "4 December 1986"
used for pretty-printing
"""
import datetime
day = str(int(datetime.date.today().strftime("%d"))) # yipes. doing this to strip the potential leading zero
return day + ' ' + datetime.date.today().strftime("%B %Y")
def prettyPrintContact(contact):
"""
doesn't actually print; just formats for other uses
returns something like "Andrew Alexander: (607) 592-4759"
"""
return contact['displayName'] + ': ' + printPhone(str(contact['number']))
def saveJson(contacts,destinationPath):
"""
save contacts as a JSON file
(with pretty-printed JSON)
"""
import json
destinationFile = destinationPath + today() + 'allContacts.json'
with open(destinationFile, 'w') as f:
json.dump(contacts, f, sort_keys=True,
indent=4, separators=(',', ': '))
def saveCSV(contacts,destinationPath):
"""
save contacts as a minimal csv, comma-delimeted
with names as in the cell phone
and numbers unformatted
note that it doesn't escape commas :(
"""
destinationFile = destinationPath + today() + 'allContacts.csv'
delimiter = ','
with open(destinationFile,'w') as f:
f.seek(0)
f.truncate() #clear anything existing in the file
for contact in contacts:
outputLine = contact['displayName'] + delimiter + str(contact['number']) + '\n'
f.write(outputLine)
def savePretty(contacts,destinationPath):
"""
save contacts as an easily-human-readable text file
with names as in the cell phone, numbers nicely formatted, and line breaks at every new starting letter
"""
destinationFile = destinationPath + today() + 'allContacts.txt'
with open(destinationFile,'w') as f:
f.seek(0)
f.truncate() #clear anything existing in the file
outputLines = "Andrew's phone book\n"
outputLines += "as rendered " + todayPretty() + "\n"
outputLines += "=============\n\n"
for i in range(len(contacts)):
print contacts[i]
#outputLines += contacts[i]['displayName'] + ': ' + printPhone(str(contacts[i]['number']))
outputLines += prettyPrintContact(contacts[i])
if i+1 != len(contacts): #this is a stupid way to do it but it complains otherwise
# double newline if there's a letter change; single newline outherwise
# (no trailing newline)
if contacts[i+1]['displayName'][0].lower() != contacts[i]['displayName'][0].lower(): outputLines += '\n\n'
else: outputLines += '\n'
print outputLines
f.write(outputLines)
def main():
source = '/Users/amha/Documents/allContacts20160601.json'
destination = '/Users/amha/Documents/'
contacts = loadContactsFromJson(source)
savePretty(contacts,destination)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment