gcal2org / gcal2org.py

#!/usr/bin/env python
# Copyright (C) 2011 by Felix Geller
# 
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
# (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
# 
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
# Queries Google Calendar for entries in that are at most 30 days in
# the past or future, then prints each entry into a org-entry to a
# given file.
#
# N.B.: Uses authinfo_pw to retrieve a password from an encrypted
# file. Please change this according to your preferences.
#
# Usage:
#  > gcal2org.py email@gmail.com org-file

import gdata.calendar.client
from datetime import date, datetime, timedelta
from time import strftime, strptime, mktime, localtime
import sys, re, os, getopt

preamble = """#+STARTUP: overview
#+DESCRIPTION: Converted on %s
* Events
"""

item = """** %s
   :PROPERTIES:
   :When:     %s
   :Where:    %s
   :Who:      %s
   :END:
 - Description:
%s
"""

def date_range_query(cal_client, 
                     max_results = 333, 
                     start_date = str(date.today() - timedelta(30)), 
                     end_date = str(date.today() + timedelta(30))):
  query = gdata.calendar.client.CalendarEventQuery()
  query.start_min = start_date
  query.start_max = end_date
  query.max_results = max_results
  feed = cal_client.GetCalendarEventFeed(q=query)
  return feed.entry

def date_range(start_time, end_time):
  if 'T' in start_time:
    st = strptime(start_time[:16], '%Y-%m-%dT%H:%M')
    et = strptime(end_time[:16], '%Y-%m-%dT%H:%M')
    tstamp = '<%Y-%m-%d %a %H:%M>'
  else:
    st = strptime(start_time, '%Y-%m-%d')
    et = localtime(mktime(strptime(end_time, '%Y-%m-%d')) - 86400.0)
    tstamp = '<%Y-%m-%d %a>'
  return '%s--%s' % tuple([strftime(tstamp, t) for t in (st, et)])

def write_item(event, org_file):
  title = event.title.text
  when = date_range(event.when[0].start, event.when[0].end)
  where = event.where[0].text or 'N/A'
  who = ', '.join([x.value for x in event.who])
  description = event.content.text or 'N/A'
  itemdata =  tuple([s.encode('UTF-8') for s in (title, when, where, who, description)])
  org_file.write(item % itemdata)

def authinfo_pw(login):
  p = re.compile('login %s password ([^ ]+)' % login)
  authinfo = os.popen('gpg -q --no-tty -d ~/.gcal.gpg').read()
  return p.search(authinfo).group(1)

def create_calendar_client(login):
  client = gdata.calendar.client.CalendarClient(source='acme-gcal2org-v1')
  client.ssl = True
  client.ClientLogin(login, authinfo_pw(login), client.source)
  return client

def create_org_file(login, filename):
  org_file = open(filename, 'w')
  org_file.write(preamble % datetime.now())
  client = create_calendar_client(login)
  for event in date_range_query(client):
    write_item(event, org_file)
  org_file.close()

def main():
  if 3 > len(sys.argv):
    print >>sys.stderr, 'Please provide login and filename for output as arguments'
    return 2
  else:
    return create_org_file(sys.argv[1], sys.argv[2])

if __name__ == '__main__':
  sys.exit(main())
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.