Skip to content

Instantly share code, notes, and snippets.

@ysc3839
Last active February 25, 2019 14:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ysc3839/b52137fda3181a61a1c87bd6ff39fbb5 to your computer and use it in GitHub Desktop.
Save ysc3839/b52137fda3181a61a1c87bd6ff39fbb5 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
# -*- encoding: utf-8 -*-
import json, uuid, os, datetime
from datetime import time as tm
from functools import partial
open_utf8 = partial(open, encoding='utf-8')
ICAL_HEADER = r'''BEGIN:VCALENDAR
PRODID:-//ysc3839//classlist-to-ical.py//
VERSION:0.1
CALSCALE:GREGORIAN
METHOD:PUBLISH
BEGIN:VTIMEZONE
TZID:Asia/Shanghai
BEGIN:STANDARD
TZOFFSETFROM:+0800
TZOFFSETTO:+0800
TZNAME:CST
DTSTART:19700101T000000
END:STANDARD
END:VTIMEZONE
'''
ICAL_VEVENT = r'''BEGIN:VEVENT
DTSTART;TZID=Asia/Shanghai:{DTSTART}
DTEND;TZID=Asia/Shanghai:{DTEND}
RRULE:FREQ=WEEKLY;COUNT={RCOUNT};BYDAY={RDAY}
DTSTAMP:{DTSTAMP}
UID:Ical{UID}
CREATED:{DTSTAMP}
DESCRIPTION:{DESC}
LAST-MODIFIED:{DTSTAMP}
LOCATION:{LOC}
SEQUENCE:0
STATUS:CONFIRMED
SUMMARY:{SUMMARY}
TRANSP:{TRANSP}
END:VEVENT
'''
ICAL_FOOTER = r'''END:VCALENDAR
'''
DATE_START = datetime.date(2019, 2, 25)
CLASS_TIMES = [
None, #0 None
# Morning
(tm(8, 30), tm(9, 15)), # 1 08:30-09:15
(tm(9, 20), tm(10, 5)), # 2 09:20-10:05
(tm(10, 25), tm(11, 10)), # 3 10:25-11:10
(tm(11, 15), tm(12, 00)), # 4 11:15-12:00
# Afternoon
(tm(13, 50), tm(14, 35)), # 5 13:50-14:35
(tm(14, 40), tm(15, 25)), # 6 14:40-15:25
(tm(15, 45), tm(16, 30)), # 7 15:45-16:30
(tm(16, 35), tm(17, 20)), # 8 16:35-17:20
# Night
(tm(18, 20), tm(19, 5)), # 9 18:20-19:05
(tm(19, 10), tm(19, 55)), # 10 19:10-19:55
(tm(20, 0), tm(20, 45)), # 11 20:00-20:45
]
WEEK_DAYS = [
None,
'MO',
'TU',
'WE',
'TH',
'FR',
'SA',
'SU'
]
def dt_to_str(dt):
return "%04d%02d%02dT%02d%02d%02d" % (
dt.year,
dt.month,
dt.day,
dt.hour,
dt.minute,
dt.second
)
def main():
with open_utf8('classlist.json', 'r') as f:
classlist = json.load(f)
with open_utf8('out.ics', 'w', newline='\r\n') as f:
f.write(ICAL_HEADER)
xsbjList = {}
for xsbj in classlist['xsbjList']:
xsbjList[xsbj['xslxbj']] = xsbj['xsmc']
utcnow_str = dt_to_str(datetime.datetime.utcnow()) + 'Z'
kbList = classlist['kbList']
for kb in kbList:
if kb['sxbj'] != '1': # =='1':已选上, else:待筛选
continue
kb['xsmc'] = xsbjList[kb['xslxbj']] if 'xslxbj' in kb else ''
if 'zcmc'in kb:
kb['zcmc'] = kb['zcmc'].replace('(', '(').replace(')', ')')
week_range = kb['zcd'].rstrip('周').split('-')
week_range = [int(_) for _ in week_range]
weekday = int(kb['xqj'])
weeks = week_range[1] - week_range[0] + 1 if len(week_range) == 2 else 1
start_date = DATE_START + datetime.timedelta(days=weekday-1, weeks=week_range[0]-1)
class_range = kb['jcs'].split('-')
class_range = [int(_) for _ in class_range]
start_time = CLASS_TIMES[class_range[0]][0]
end_time = CLASS_TIMES[class_range[1]][1]
event_data = {}
event_data['DTSTART'] = dt_to_str(datetime.datetime.combine(start_date, start_time))
event_data['DTEND'] = dt_to_str(datetime.datetime.combine(start_date, end_time))
event_data['RCOUNT'] = weeks
event_data['RDAY'] = WEEK_DAYS[weekday]
event_data['DTSTAMP'] = utcnow_str
event_data['UID'] = uuid.uuid4().hex
event_data['DESC'] = r'''周: {zcd}
教师: {xm}{0}
考察方式: {khfsmc}
课程性质: {xsmc}
教学班名称: {jxbmc}'''.format('' if 'zcmc' not in kb else ' (%s)' % kb['zcmc'], **kb).replace('\n', '\\n')
event_data['LOC'] = kb['cdmc']
event_data['SUMMARY'] = kb['kcmc']
event_data['TRANSP'] = 'OPAQUE'
f.write(ICAL_VEVENT.format(**event_data))
if week_range[0] != 1:
start_date = DATE_START + datetime.timedelta(days=weekday-1)
event_data['DTSTART'] = dt_to_str(datetime.datetime.combine(start_date, start_time))
event_data['DTEND'] = dt_to_str(datetime.datetime.combine(start_date, end_time))
event_data['RCOUNT'] = week_range[0] - 1
event_data['UID'] = uuid.uuid4().hex
event_data['SUMMARY'] = '!!!' + event_data['SUMMARY']
event_data['TRANSP'] = 'TRANSPARENT'
f.write(ICAL_VEVENT.format(**event_data))
f.write(ICAL_FOOTER)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment