#! /usr/bin/python import gflags import httplib2 import math import re from apiclient.discovery import build from oauth2client.file import Storage from oauth2client.client import OAuth2WebServerFlow from oauth2client.tools import run ######################################################################## # Algorithm from pg 7 of Peter Duffet-Smith, # Practical Astronomy With Your Calculator, 3d ed. # Check against http://www.onlineconversion.com/julian_date.htm # and /Utils/Date.exe # This version does not check for Gregorian calendar or BC!!! # This version does not handle fractional days!!! def JulianDate (Year,Month,Day,modified=False): if (Month == 1)or(Month == 2): Yprime = Year - 1 Mprime = Month + 12 else: Yprime = Year Mprime = Month A = math.floor(Yprime / 100.0) B = 2.0 - A + math.floor(A / 4.0) C = math.floor(365.25 * Yprime) D = math.floor(30.6001 * (Mprime + 1.0)) # Julian Day JD = B + C + D + Day + 1720994.5 # Modified Julian Day MJD = B + C + D + Day - 679006.0 if modified: return MJD else: return JD ######################################################################## # Given a year, month, and day, compute the day of the week def DayOfWeek(Year,Month,Day): dayNames = [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ] mjd = JulianDate(Year,Month,Day,True) diff = mjd - 15019.0 # dayIndex = math.floor(diff) % 7 dayIndex = int(diff) % 7 return dayNames[dayIndex] ######################################################################## # Given a string which represents a date and time, e.g. # '2012-01-30T23:59:00Z' RFC 3339 timestamp # Format it into a Org-Mode date. def formatDateTimeStringToOrgMode(DateTimeString,angleBrackets=True): prog = re.compile('([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})(.{1})') match = prog.match(DateTimeString) Year = int(match.group(1)) Month = int(match.group(2)) Day = int(match.group(3)) ShortDayName = DayOfWeek(Year,Month,Day) Hour = int(match.group(4)) Minute = int(match.group(5)) Second = int(match.group(6)) TimeZone = match.group(7) # TODO: Use the timezone somehow if angleBrackets: openBracket = '<' closeBracket = '>' else: openBracket = '[' closeBracket = ']' retString = '%s%04d-%02d-%02d %s %02d:%02d:%02d%s' % \ (openBracket, \ Year, Month, Day, ShortDayName, Hour, Minute, Second, \ closeBracket) return retString ######################################################################## # A simple utility function to print out a given attribute of a dict. def printDictAttributeIfExists(dict,label,attr): try: print label + dict[attr] except KeyError: pass ######################################################################## # Print out all the fields of a task def printTask(task): printDictAttributeIfExists(task," Task : ", 'title') printDictAttributeIfExists(task," Kind : ", 'kind') printDictAttributeIfExists(task," id : ", 'id') printDictAttributeIfExists(task," etag : ", 'etag') printDictAttributeIfExists(task," updated : ", 'updated') printDictAttributeIfExists(task," selfLink : ", 'selfLink') printDictAttributeIfExists(task," position : ", 'position') printDictAttributeIfExists(task," parent : ", 'parent') printDictAttributeIfExists(task," notes : ", 'notes') printDictAttributeIfExists(task," status : ", 'status') printDictAttributeIfExists(task," due : ", 'due') printDictAttributeIfExists(task," completed: ", 'completed') printDictAttributeIfExists(task," deleted : ", 'deleted') printDictAttributeIfExists(task," hidden : ", 'hidden') print ######################################################################## # Given a list of nodes, which may themselves contain a list of nodes # in their children attribute, find a node which has the given id and # return it. def findNode(nodeList, nodeId): for i in range(len(nodeList)): if (nodeList[i]['id'] == nodeId): return nodeList[i] if (len(nodeList[i]['children']) > 0): rv = (findNode(nodeList[i]['children'], nodeId)) if (rv != False): return rv return False ######################################################################## # Given a list of nodes representing tasks, print out the tree in # Org-mode format. def printNodeList(nodeList, depth=0): stars = '*' for i in range(depth): stars = stars + '*' spaces = ' ' for i in range(depth): spaces = spaces + ' ' for i in range(len(nodeList)): node = nodeList[i] if (node['status'] == 'needsAction'): status = ' TODO ' elif (node['status'] == 'completed'): status = ' DONE ' else: status = ' ' try: deadline = node['due'] except KeyError: deadline = False try: notes = node['notes'] except KeyError: notes = False # TODO: Add completed date try: completed = node['completed'] except KeyError: completed = False # For recording when the item was closed, or the deadline dates_line = '' print stars + status + node['title'] if (deadline or completed): dates_line = dates_line + spaces if (completed): dates_line = dates_line + \ 'CLOSED: ' + formatDateTimeStringToOrgMode(completed,False) if (completed and deadline): dates_line = dates_line + ' ' if (deadline): dates_line = dates_line + 'DEADLINE: ' + \ formatDateTimeStringToOrgMode(deadline) if (dates_line != ''): print dates_line # Properties. TODO: Any others? print spaces + ':PROPERTIES:' print spaces + ':ID:' + ' ' + node['id'] print spaces + ':UPDATED:' + ' ' + node['updated'] print spaces + ':END:' if (notes): noteslines = notes.split('\n') for line in noteslines: print spaces + line printNodeList(node['children'], depth+1) FLAGS = gflags.FLAGS # Set up a Flow object to be used if we need to authenticate. This # sample uses OAuth 2.0, and we set up the OAuth2WebServerFlow with # the information it needs to authenticate. Note that it is called # the Web Server Flow, but it can also handle the flow for native # applications # The client_id and client_secret are copied from the API Access tab on # the Google APIs Console FLOW = OAuth2WebServerFlow( client_id='218130629659.apps.googleusercontent.com', client_secret='4/kMrW-AHZalDLvMnJlWTopIR2E1Cx', scope='https://www.googleapis.com/auth/tasks', user_agent='TasksToOrgMode/1.0') # To disable the local server feature, uncomment the following line: FLAGS.auth_local_webserver = False # If the Credentials don't exist or are invalid, run through the native client # flow. The Storage object will ensure that if successful the good # Credentials will get written back to a file. storage = Storage('tasks.dat') credentials = storage.get() if credentials is None or credentials.invalid == True: credentials = run(FLOW, storage) # Create an httplib2.Http object to handle our HTTP requests and authorize it # with our good Credentials. http = httplib2.Http() http = credentials.authorize(http) # Build a service object for interacting with the API. Visit # the Google APIs Console # to get a developerKey for your own application. service = build(serviceName='tasks', version='v1', http=http) # Get all of the task lists tasklists = service.tasklists().list().execute() # Loop through the returned task lists for tasklist in tasklists['items']: # Create a flat list of all the tasks. orgTaskList = {} orgTaskList['title'] = tasklist['title'] orgTaskList['children'] = [] # print 'Task List Title = ' + tasklist['title'] # print 'Task List id = ' + tasklist['id'] tasklist_id = tasklist['id'] tasks = service.tasks().list(tasklist=tasklist_id).execute() # Loop through the tasks, add them to a flat list of tasks for task_item in tasks['items']: task_item_id = task_item['id'] task = service.tasks().get(tasklist=tasklist_id,task=task_item_id).execute() task['children'] = [] # print "Adding task " + task['title'] orgTaskList['children'].append(task) # Now take tasks and add them to their correct parents i = 0 while (i