Last active
April 18, 2016 14:35
-
-
Save dstanek/b0c1e839b2dd937faff1f81728e51e27 to your computer and use it in GitHub Desktop.
Code to take the OpenStack schedule that was downloaded from https://www.openstack.org/api/v1/summits/6/schedule and turn it into something almost usable.
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 python3 | |
import collections | |
import datetime | |
import json | |
MIN_INC = 5 | |
EVENT_CONTINUED = object() | |
EMPTY = object() | |
EMPTY_CONTINUED = object() | |
class Event: | |
def __init__(self, start, end, title, location): | |
format = '%Y-%m-%d %H:%M' | |
self.start = datetime.datetime.strptime(start.rsplit(':', 1)[0], format) | |
self.end = datetime.datetime.strptime(end.rsplit(':', 1)[0], format) | |
self.title = title | |
self.location = location | |
def __str__(self): | |
return '<div class="title">{}</div><div class="dates">{}-{}</div> in {}'.format( | |
self.title, | |
self.start.strftime('%H:%M'), | |
self.end.strftime('%H:%M'), self.location) | |
class Location: | |
def __init__(self, location_id): | |
self.location_id = location_id | |
self.events = {} | |
def add_event(self, e): | |
self.events[e.start] = e | |
def get_event_at(self, dt): | |
return self.events.get(dt) | |
class Table: | |
def __init__(self): | |
self.day_start = datetime.datetime.max | |
self.day_end = datetime.datetime.min | |
self.locations = {} | |
self.datetimes = set([]) | |
def add_event(self, e): | |
location = self.locations.get(e.location) | |
if not location: | |
location = self.locations[e.location] = Location(e.location) | |
self.locations[e.location].add_event(e) | |
self.datetimes.add(e.start) | |
self.datetimes.add(e.end) | |
if e.start < self.day_start: | |
self.day_start = e.start | |
if e.end > self.day_end: | |
self.day_end = e.end | |
def draw(self): | |
times_map = {dt: n for n, dt in enumerate(sorted(self.datetimes))} | |
all_times = list(sorted(self.datetimes)) | |
sorted_locations = [self.locations[_id] for _id in sorted(self.locations)] | |
col_cnt = len(sorted_locations) + 1 | |
row_cnt = len(all_times) | |
num_cols = range(len(sorted_locations)+1) | |
num_rows = range(len(all_times)) | |
table = [[None for _ in num_cols] for _ in num_rows] | |
for n, dt in enumerate(all_times): | |
table[n][0] = (dt.strftime('%H:%M'), 1) | |
cur_time_loc = times_map[dt] | |
for n_loc, location in enumerate(sorted_locations, start=1): | |
event = location.get_event_at(dt) | |
if event: | |
end_time_loc = times_map[event.end] | |
num_slots = end_time_loc - cur_time_loc | |
table[n][n_loc] = (event, num_slots) | |
if num_slots > 1: | |
for inc in range(1, num_slots): | |
table[n+inc][n_loc] = EVENT_CONTINUED | |
for n_row, row in enumerate(table): | |
for n_col, col in enumerate(row): | |
if col is None: | |
extra = 1 | |
for x in range(n_row+1, row_cnt): | |
if table[x][n_col] is None: | |
table[x][n_col] = EMPTY_CONTINUED | |
extra +=1 | |
else: | |
break | |
table[n_row][n_col] = (EMPTY, extra) | |
print('<table border="1" id="{}">'.format(self.date.strftime('%m-%d-%Y'))) | |
print('<caption>Schedule for {}</caption'.format(self.date.strftime('%m-%d-%Y'))) | |
print('<tr>') | |
print('<td> </td>') | |
for location in sorted_locations: | |
print('<td>{:d}</td>'.format(location.location_id)) | |
print('</tr>') | |
for row in table: | |
print('<tr>') | |
for col in row: | |
if col in (EVENT_CONTINUED, EMPTY_CONTINUED): | |
continue | |
elif col[0] is EMPTY: | |
print('<td class="empty" rowspan="{:d}"> </td>'.format(col[1])) | |
elif col: | |
event, slots = col | |
print('<td rowspan="{:d}">{}</td>'.format(slots, event)) | |
else: | |
raise Exception # something broke | |
print('</tr>') | |
print('</table>') | |
@property | |
def date(self): | |
x = list(list(self.locations.values())[-1].events.values())[-1] | |
return x.start | |
class Page: | |
def __init__(self, tables): | |
self.tables = tables | |
def draw_nav(self): | |
print('<ul class="nav">') | |
for date in sorted(self.tables): | |
print('<li><a href="#{0}">{0}</a></li>'.format(date.strftime('%m-%d-%Y'))) | |
print('</ul>') | |
def draw(self): | |
for date in sorted(self.tables): | |
self.tables[date].draw() | |
tables = collections.defaultdict(Table) | |
data = json.load(open('sched.json')) | |
for event in data['events']: | |
e = Event(event['start_datetime'], | |
event['end_datetime'], | |
event['title'], | |
event['location_id']) | |
tables[e.start.date()].add_event(e) | |
page = Page(tables) | |
print("""\ | |
<html> | |
<head> | |
<style type="text/css"> | |
table { | |
border-collapse: collapse; | |
margin: 2em 0; | |
overflow: scroll; | |
overflow-y: hidden; | |
width: 100%; | |
} | |
caption { | |
font-size: 1.25em; | |
text-align: left; | |
} | |
table tr td { | |
padding: .5em; | |
} | |
.empty { | |
background-color: lightgray; | |
} | |
ul.nav { | |
list-style-type: none; | |
margin: 0; | |
padding: 0; | |
} | |
ul.nav li { | |
display: inline; | |
padding-right: 1em; | |
} | |
</style> | |
</head> | |
<body> | |
""") | |
page.draw_nav() | |
page.draw() | |
print(""" | |
</body> | |
</html> | |
""") |
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 python3 | |
import json | |
import requests | |
headers = { | |
'Cookie': '-*- Get this from your own browser session -*-', | |
'Accept': '*/*', | |
'Accept-Encoding': 'gzip, deflate, sdch', | |
'Accept-Language': 'en-US,en;q=0.8', | |
'If-None-Match': '-*- Get this from your own browser session -*-', | |
'Referer': 'https://www.openstack.org/summit/austin-2016/summit-schedule', | |
'X-Requested-With': 'XMLHttpRequest', | |
} | |
resp = requests.get('https://www.openstack.org/api/v1/summits/6/schedule', headers=headers) | |
print(json.dumps(resp.json())) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment