Last active
December 20, 2015 17:29
-
-
Save ClarkGoble/6169144 to your computer and use it in GitHub Desktop.
Python script for displaying a range of calendar events from the Calendar app in a nice formatted form
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# -*- coding: utf-8 -*- | |
## comingevents.py | |
################################################### | |
# Lists in a nice format forthcoming events | |
from appscript import * | |
import osax | |
from AppKit import * | |
from Foundation import * | |
import datetime, time | |
import sys | |
import optparse | |
import parsedatetime.parsedatetime as pdt | |
# path for where to put the html file | |
html_path = "/Users/clarkgoble/Documents/comingevents.html" | |
def sethtmlclipboard(html): | |
"""puts the html on the clipboard as styled text""" | |
pb = NSPasteboard.generalPasteboard() | |
a = NSArray.arrayWithObject_(NSHTMLPboardType) | |
pb.declareTypes_owner_(a, None) | |
pb.setString_forType_( html, NSHTMLPboardType) | |
def datetimeFromString( s ): | |
"""parse date and time from natural string""" | |
# See http://stackoverflow.com/questions/1810432/handling-the-different-results-from-parsedatetime | |
p = pdt.Calendar() | |
result, what = p.parse( s ) | |
dt = 0 | |
if what in (1,2,3): | |
# result is struct_time | |
dt = datetime.datetime( *result[:6] ) | |
if what == 0: | |
# Failed to parse | |
return "" | |
return dt | |
def make_range(numberofdays, starttime=None): | |
"""Makes a range from now to a specified number of days in the future""" | |
# calculate our date range | |
if starttime is None: | |
starttime = datetime.datetime.now() | |
endtime = starttime + datetime.timedelta(days = numberofdays) | |
return [starttime, endtime] | |
def get_range(): | |
"""Brings up a dialog box to specify a date range""" | |
sa = osax.OSAX() | |
sa.activate() | |
# set up some defaults | |
startdate, enddate = make_range(15) | |
startstring = startdate.strftime( "%b %d %Y") | |
endstring = enddate.strftime( "%b %d %Y") | |
range = sa.display_dialog("Date range to display", with_title="Date Range", default_answer= startstring + " - " + endstring ) | |
startstring, endstring = range[k.text_returned].split("-") | |
startstring = startstring.strip() | |
endstring = endstring.strip() | |
print startstring, endstring | |
startdate = datetimeFromString( startstring ) | |
enddate = datetimeFromString( endstring ) | |
# startdate = datetime.datetime.strptime( startstring, "%b %d %Y" ) | |
# enddate = datetime.datetime.strptime( endstring, "%b %d %Y" ) | |
return [startdate, enddate] | |
def sort_calinfo( events ): | |
"""sorts the array of calendar events by startdate""" | |
return sorted(events, key = lambda r: r['startdate']) | |
def print_calinfo( events ): | |
"""prints in plain text the events""" | |
for e in events: | |
print "{} Start: {} End: {} ".format( e['calendar'], e['startdate'], e['enddate']) | |
print e['summary'] | |
return | |
def html_calinfo( events, startdate, enddate ): | |
"""returns the list of events as formatted html""" | |
html =u"""<html><body> | |
<style type="text/css"> | |
body {{ background: #F2E2CD; font-family:Helvetica; font-size: 10pt; }} | |
#caltable {{ width: 480px; text-align: left; border-collapse: collapse; font-size: 10pt; }} | |
#caltable th {{ background: #b9c9fe; padding: 8px; color: #039; font-style:bold; font-size: 12pt; text-align: center; height: 28pt; vertical-align:top}} | |
#caltable td {{ padding: 12px; padding-bottom: 4px; background: #e8edff; border-top: 1px solid #fff; color: #669; }} | |
#caltable #note {{ padding:12px; padding-bottom: 4px; background: #e8edff; border-top: none; color: #669; font-size: 8pt; }} | |
#caltable #small {{ padding: 12px; background: #e8edff; border-top: none; color: #669; font-size: 8pt; }} | |
</style> | |
<div id="cal"> | |
<table id="caltable"> | |
<thead><tr> | |
<th colspan=4>Calendar {} — {}</th></thead> | |
<tbody>\n""".format( startdate.strftime( "%I:%M %p %b %d %Y "), enddate.strftime( "%b %d %Y") ) | |
# — = \u2014 | |
for e in events: | |
html = html + u"""<tr><td colspan=4>{}<br/></td></tr>\n""".format( e['summary'] ) | |
if e['note'] != k.missing_value and e['note'] != None: | |
html = html + u"""<tr><td id="note"></td><td id="note" colspan=3>{}</td></tr>\n""".format( e['note'] ) | |
if e['allday'] == True: | |
html = html + u"""<tr><td id="small"></td><td id="small">Calendar: {}</td><td id="small" colspan=2>{}</td></tr>\n""".format( | |
e['calendar'], e['startdate'].strftime( "%b %d %Y (All Day)") ) | |
else: | |
html = html + u"""<tr><td id="small"></td><td id="small">Calendar: {}</td><td id="small" colspan=2>{} — {}</td></tr>\n""".format( | |
e['calendar'], e['startdate'].strftime( " %b %d %Y %I:%M %p"), e['enddate'].strftime( "%I:%M %p") ) | |
html = html + u"""\n</table></div></body></html>""" | |
return html | |
def get_calinfo(startdate, enddate): | |
"""Gets the list of events for the next numberofdays """ | |
# all the calendars | |
Cal = app(u'Calendar').calendars.get() | |
print startdate, enddate | |
# empty array of events we'll fill | |
events = [] | |
for c in Cal: | |
name = c.name() | |
eventlist = c.events[(its.start_date > startdate).AND(its.start_date < enddate)]() | |
for e in eventlist: | |
eventstart = e.start_date() | |
if eventstart == None: | |
continue | |
eventend = e.end_date() | |
summary = e.summary() | |
note = e.description() | |
allday = e.allday_event() | |
#description = e.description | |
d = {'calendar':name, 'startdate':eventstart, 'enddate':eventend, 'summary':summary, 'note':note, 'allday':allday} | |
events.append( d ) | |
return events | |
def updatehtml(html): | |
"""Saves the html to a file""" | |
f = open(html_path, "w") | |
f.write(html.encode('utf16')) | |
f.close() | |
def openhtml(html): | |
"""Opens html with Safari""" | |
Safari = app(u'/Applications/Safari.app') | |
tab = Safari.windows[1].make(new=k.tab, with_properties={k.URL: u'file://'+html_path }) | |
Safari.windows[1].current_tab.set( tab ) | |
def interactive(): | |
"""Runs the script interactively bringing up a dialog to prompt for a date range""" | |
startdate, enddate = get_range() | |
print startdate, enddate | |
events = get_calinfo(startdate, enddate) | |
events = sort_calinfo( events ) | |
html = html_calinfo( events, startdate, enddate ) | |
print html | |
sethtmlclipboard( html ) | |
updatehtml(html) | |
openhtml( html ) | |
def automated(startdate, enddate): | |
"""Runs the script in an automated fashion with no interaction""" | |
events = get_calinfo(startdate, enddate) | |
events = sort_calinfo( events ) | |
html = html_calinfo( events, startdate, enddate ) | |
print html | |
sethtmlclipboard( html ) | |
updatehtml( html ) | |
openhtml( html ) | |
def main(): | |
"""Handle command line options and run appropriately""" | |
usage = "useage: %prog [options]" | |
option_parser = optparse.OptionParser() | |
option_parser.add_option('-i','--interactive', action='store_true', dest='interactive', default=False, | |
help="run interactively with a dialog box") | |
option_parser.add_option('-s',"--start", action='store', type='string', dest='starttime', | |
help="start date for display") | |
option_parser.add_option('-e',"--end", action='store', type='string',dest='endtime', | |
help="end date for display") | |
option_parser.add_option('-d',"--days", action='store', type='int',dest='days', | |
help="days to display") | |
options, args = option_parser.parse_args() | |
if options.interactive is True: | |
interactive() | |
return | |
if options.days is not None: | |
if options.starttime is None: | |
startdate = datetime.datetime.now() | |
else: | |
# startdate = datetime.datetime.strptime( options.starttime, "%b %d %Y" ) | |
startdate = datetimeFromString( option.starttime ) | |
startdate, enddate = make_range( int(options.days), startdate) | |
automated( startdate, enddate ) | |
return | |
if options.starttime is None and options.endtime is not None: | |
startdate = datetime.datetime.now() | |
# enddate = datetime.datetime.strptime( options.endtime, "%b %d %Y" ) | |
enddate = datetimeFromString( options.endtime ) | |
automated( startdate, enddate ) | |
return | |
if options.starttime is None and options.endtime is None: | |
startdate, enddate = make_range(10) | |
automated( startdate, enddate ) | |
return | |
# startdate = datetime.datetime.strptime( options.starttime, "%b %d %Y" ) | |
# enddate = datetime.datetime.strptime( options.endtime, "%b %d %Y" ) | |
startdate = datetimeFromString( options.starttime ) | |
enddate = datetimeFromString( options.endtime ) | |
automated( startdate, enddate ) | |
return | |
if __name__ == '__main__': | |
main() | |
# change to 0 for success, 1 for (partial) failure | |
sys.exit(0) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment