Interactive Program ScheduleURL: http://fanime.info/ (http://fanime.info/)Status: Complete!So, in some previous years Fanime has had an online program schedule, and I've generally found it really handy to tweak it to a color-coded schedule of what I may want to see that I can pull up on my phone (e.g. http://thesilentb.com/fanime/index.2011.html (http://thesilentb.com/fanime/index.2011.html) from 2011). So, last night I spent a couple hours and put together most of the tech for one, which I plan on completely finishing tonight. Anyway, I thought others might also like such a thing and benefit from it, so I'm sharing it here, and also hoping others may help fill in the missing data. Right now it's set to a wide-screen, open edit mode where anyone can help fill in the schedule (note: this mode only works well in Chrome, and kind of in IE, not at all in FireFox), I'll switch it to a more compact "planner" mode this evening so we can start marking what things we're interested in (and get an output like the example from 2011 which you should be able to pull up on your smart phone during the convention).
Current plan/schedule for development of this evening:
Definitely going to have:
- Done! - Video programming data entered
- Done! - Planner mode (viewable on IE/FF/Chrome and mobile browsers; enter a name to view plan, or name+password to edit plan, where editing is simply clicking any time slot to toggle it between normal (white), want to see (green), maybe see (yellow))
Stretch goals:
- Done! Non-video programming data entered
- Done! Ability to toggle which rows show up on your planner
- Time/zoom controls (so whenever you look at a plan page it just shows -1 hours to +4 hours around the current time, not the entire thing)
- Info/notes pages (allow people to leave a (public or private) note about any event, fill in event info, and, by default, this page will just be populated by a Google search for the event term (most useful for video programmming))
Anyway, if you're interested in using this, let me know on the forums here, or get in contact with me. If you're a staffer and have access to a spreadsheet with all of this data already and could send it my way, that would also be awesome =).
Jimbly
Usual cosplay: Purple kitty, Rurouni Kenshin
Google Chat:
[email protected] AIM: Wasteland777
Y!M: Wasteland7
ICQ: 435337
See you at the con!
Update: Video programming data is now complete, planner mode now works, feel free to jump over to http://fanime.info (http://fanime.info) put in a username and password (if an account does not exist, it simply auto-creates one), and start planning your Fanime!
The planner mode seems to work fine on IE, FireFox, Chrome, and the Android mobile browser, if anyone could give it a whirl on an iOS browser, it would be nice to know if it works there as well.
Not-interactive as your, but it has more stuff:
Mobile: http://m.fanime.com/
Desktop: http://apps.fanime.com/2013/schedule/grid.php?width=1200px
Ooh, excellent, should be pretty trivial to scrape that data and put into interactive form. Any reason that schedule is not linked from the Fanime page, or announced anywhere?
I have no idea. I was reading their pocket book and saw it by surprise.
I did scrapper that I used last year. It still worked, so I use it to make a schedule for Guidebook. Here is the CSV: http://wikisend.com/download/299700/FAnime_2013.csv
Scrapper:
from pyquery.pyquery import PyQuery
from datetime import datetime, timedelta, time
import re
def parse_time(hour_time):
try:
return datetime.strptime(hour_time, '%I:%M%p').time()
except ValueError:
return datetime.strptime(hour_time, '%I%p').time()
def parse_fanime_sessions(unix_time):
url = 'http://m.fanime.com/index.php?grid=%d' % unix_time
dom = PyQuery(url)
event_datetime = datetime.fromtimestamp(unix_time)
date = event_datetime.date()
time_start = event_datetime.time()
time_end = (event_datetime + timedelta(hours = 1)).time()
row_pattern = r'table.grid tr'
col_pattern = r'td'
rows = dom(row_pattern)
schedule = []
MIDNIGHT_TIME = time(0, 0, 0)
for row in rows:
py_row = PyQuery(row)
cols = py_row(col_pattern)
for index in range(len(cols)):
td = PyQuery(cols[index])
css_class = td.attr.class_
# clean_text = td.text().replace(' ', ' ')
clean_room_and_track = td.text().replace(u'\xa0', ' ')
room_and_track_re = re.search('([^\(]+)\s\(([^\)]+)', clean_room_and_track)
if css_class == 'track':
schedule += [{
'date': date,
'title': None,
'room': room_and_track_re.group(2),
'track': room_and_track_re.group(1),
'time_start': time_start,
'time_end': time_end,
}]
elif css_class in ['skip', 'partial']:
#===============================================================================
# Case
# continues from 11:30am, begins at 12:30pm => start_time: 11:30am
# ends at 12:30pm, runs until 2:30pm => end_time: 12:30pm
# [all day] => start_time = end_time = 0:00am
#===============================================================================
event = schedule[-1]
if clean_room_and_track == '[all day]':
event['time_start'] = MIDNIGHT_TIME
event['time_end'] = MIDNIGHT_TIME
elif 'continues from' in clean_room_and_track or 'begins at' in clean_room_and_track:
text_parts = clean_room_and_track.split()
event['time_start'] = parse_time(text_parts[-1])
elif 'ends at' in clean_room_and_track or 'runs until' in clean_room_and_track:
text_parts = clean_room_and_track.split()
event['time_end'] = parse_time(text_parts[-1])
else:
raise Exception("UNHANDLED CASE")
else:
schedule[-1]['title'] = clean_room_and_track
return schedule
def get_schedule(start_time, end_time):
current_unix_time = start_time
schedule = []
while current_unix_time < end_time:
sessions = parse_fanime_sessions(current_unix_time)
# for item in schedule:
# pprint(item, indent=4)
schedule += sessions
current_unix_time += (60 * 60)
return schedule
def print_guidebook_csv(schedule, filename = None):
if filename:
file_handle = open(filename, 'w')
else:
file_handle = None
CSV_HEADER = 'Session Title,Date,Time Start,Time End,Room/Location,Schedule Track (Optional),Description (Optional)'
if file_handle:
file_handle.write("{}\n".format(CSV_HEADER))
else:
print CSV_HEADER
for session in schedule:
# print session
session['title'] = session['title'].replace('"', '')
session['track'] = session['track'].replace('Tabletop Gaming Tournaments', 'Tabletop Gaming')
csv_line = '"%(title)s", %(date)s, %(time_start)s, %(time_end)s, %(room)s, %(track)s, ""' % session
if file_handle:
file_handle.write("{}\n".format(csv_line))
else:
print csv_line
if file_handle:
file_handle.close()
if __name__ == '__main__':
#===========================================================================
# Fanime 2013 (1369350000 to 1369695600) ( Thursday 5pm - Monday 4pm)
# 1369688400 - Monday, 2pm
# 1369692000 - Monday, 3pm
#===========================================================================
# Thursdaay 6pm - Midnight
ONE_HOUR = 60 * 60
SIX_HOUR = ONE_HOUR * 6
schedule = []
# THURSDAY
THURSDAY_6PM = 1369357200
THURSDAY_11PM = THURSDAY_6PM + SIX_HOUR - ONE_HOUR
print '%d - %d ' % (THURSDAY_6PM, THURSDAY_11PM)
schedule += get_schedule(THURSDAY_6PM, THURSDAY_11PM)
# FRIDAY
FRIDAY_MIDNIGHT = THURSDAY_11PM + ONE_HOUR
FRIDAY_11PM = FRIDAY_MIDNIGHT + (SIX_HOUR * 4) - ONE_HOUR
print '%d - %d ' % (FRIDAY_MIDNIGHT, FRIDAY_11PM)
schedule += get_schedule(FRIDAY_MIDNIGHT, FRIDAY_11PM)
# SATURDAY
SATURDAY_MIDNIGHT = FRIDAY_11PM + ONE_HOUR
SATURDAY_11PM = SATURDAY_MIDNIGHT + (SIX_HOUR * 4) - ONE_HOUR
print '%d - %d ' % (SATURDAY_MIDNIGHT, SATURDAY_11PM)
schedule += get_schedule(SATURDAY_MIDNIGHT, SATURDAY_11PM)
# SUNDAY
SUNDAY_MIDNIGHT = SATURDAY_11PM + ONE_HOUR
SUNDAY_11PM = SUNDAY_MIDNIGHT + (SIX_HOUR * 4) - ONE_HOUR
print '%d - %d ' % (SUNDAY_MIDNIGHT, SUNDAY_11PM)
schedule += get_schedule(SUNDAY_MIDNIGHT, SUNDAY_11PM)
# MONDAY
MONDAY_MIDNIGHT = SUNDAY_11PM + ONE_HOUR
MONDAY_3PM = 1369692000
print '%d - %d ' % (MONDAY_MIDNIGHT, MONDAY_3PM)
schedule += get_schedule(MONDAY_MIDNIGHT, MONDAY_3PM)
filename = 'Fanime_2013.csv'
print_guidebook_csv(schedule, filename)
In case you use Guidebook on your smartphone, here are guides you can download using the Redeem Code.
Fanime 2013: yjg6wo2k
Clockwork Alchemy 2013: 29tsb4ap
Heh, I ended up scraping the data myself before seeing your post, but it's now scraped and all imported into the interactive planner!
This has now been updated to work better both without an account (plan is just saved locally) and when network connections are poor (loads much faster now).