#!/usr/bin/env python from __future__ import print_function import sys import time import datetime import optparse from six.moves import urllib import itertools import traceback import os sys.path.append(os.path.join(os.path.dirname(__file__), '../api')) import zulip from typing import List, Set, Tuple, Iterable, Optional parser = optparse.OptionParser(r""" %prog \ --user foo@zulip.com \ --calendar http://www.google.com/calendar/feeds/foo%40zulip.com/private-fedcba9876543210fedcba9876543210/basic Send yourself reminders on Zulip of Google Calendar events. To get the calendar URL: - Load Google Calendar in a web browser - Find your calendar in the "My calendars" list on the left - Click the down-wedge icon that appears on mouseover, and select "Calendar settings" - Copy the link address for the "XML" button under "Private Address" Run this on your personal machine. Your API key and calendar URL are revealed to local users through the command line. Depends on: python-gdata """) parser.add_option('--calendar', dest='calendar', action='store', help='Google Calendar XML "Private Address"', metavar='URL') parser.add_option('--interval', dest='interval', default=10, type=int, action='store', help='Minutes before event for reminder [default: 10]', metavar='MINUTES') parser.add_option_group(zulip.generate_option_group(parser)) (options, args) = parser.parse_args() if not (options.zulip_email and options.calendar): parser.error('You must specify --user and --calendar') try: from gdata.calendar.client import CalendarClient except ImportError: parser.error('Install python-gdata') def get_calendar_url(): # type: () -> str parts = urllib.parse.urlparse(options.calendar) pat = os.path.split(parts.path) if pat[1] != 'basic': parser.error('The --calendar URL should be the XML "Private Address" ' + 'from your calendar settings') return urllib.parse.urlunparse((parts.scheme, parts.netloc, pat[0] + '/full', '', 'futureevents=true&orderby=startdate', '')) calendar_url = get_calendar_url() client = zulip.init_from_options(options) def get_events(): # type: () -> Iterable[Tuple[int, datetime.datetime, str]] feed = CalendarClient().GetCalendarEventFeed(uri=calendar_url) for event in feed.entry: start = event.when[0].start.split('.')[0] # All-day events can have only a date fmt = '%Y-%m-%dT%H:%M:%S' if 'T' in start else '%Y-%m-%d' start = datetime.datetime.strptime(start, fmt) yield (event.uid.value, start, event.title.text) # Our cached view of the calendar, updated periodically. events = [] # type: List[Tuple[int, datetime.datetime, str]] # Unique keys for events we've already sent, so we don't remind twice. sent = set() # type: Set[Tuple[int, datetime.datetime]] def send_reminders(): # type: () -> Optional[None] global sent messages = [] keys = set() now = datetime.datetime.now() for uid, start, title in events: dt = start - now if dt.days == 0 and dt.seconds < 60*options.interval: # The unique key includes the start time, because of # repeating events. key = (uid, start) if key not in sent: line = '%s starts at %s' % (title, start.strftime('%H:%M')) print('Sending reminder:', line) messages.append(line) keys.add(key) if not messages: return if len(messages) == 1: message = 'Reminder: ' + messages[0] else: message = 'Reminder:\n\n' + '\n'.join('* ' + m for m in messages) client.send_message(dict( type = 'private', to = options.user, content = message)) sent |= keys # Loop forever for i in itertools.count(): try: # We check reminders every minute, but only # download the calendar every 10 minutes. if not i % 10: events = list(get_events()) send_reminders() except: traceback.print_exc() time.sleep(60)