diff --git a/plugins/talks.py b/plugins/talks.py index 5717dc3..fa18898 100644 --- a/plugins/talks.py +++ b/plugins/talks.py @@ -24,6 +24,14 @@ from docutils.parsers.rst import directives, Directive from pelican import signals, generators import jinja2 +try: + import ics +except ImportError: + ICS_ENABLED = False +else: + ICS_ENABLED = True +import unidecode + pelican = None # This will be set during register() @@ -110,6 +118,8 @@ def get_talk_data(talkname): if 'text' not in data: logging.warn("Talk <{}> has no `text` field".format(talkname)) data['text'] = '' + else: + data['text'] = unicode(data['text']) if 'duration' not in data: logging.info("Talk <{}> has no `duration` field (50min used)" .format(talkname)) @@ -303,37 +313,33 @@ class TalkGridDirective(Directive): def talks_to_ics(): - content = u'BEGIN:VCALENDAR\nVERSION:2.0\nPRODID:pelican\n' + c = ics.Calendar() + c.creator = u'pelican' for t in all_talks(): - try: - content += talk_to_ics(t) - except: - logging.exception("Error producing calendar for talk %s", t['id']) - content += 'END:VCALENDAR\n' - return content + e = talk_to_ics(t) + if e is not None: + c.events.add(e) + return unicode(c) def talk_to_ics(talk): if 'time' not in talk or 'duration' not in talk: - return '' - start = talk['time'] - end = start + datetime.timedelta(minutes=talk['duration']) - content = 'BEGIN:VEVENT\n' - content += "UID:%s@%d.hackmeeting.org\n" % (talk['id'], talk['day'].year) - content += "SUMMARY:%s\n" % talk['title'] - content += "DTSTAMP:%s\n" % time.strftime('%Y%m%dT%H%M%SZ', - time.gmtime(float( - start.strftime('%s')))) - content += "DTSTART:%s\n" % time.strftime('%Y%m%dT%H%M%SZ', - time.gmtime(float( - start.strftime('%s')))) - content += "DTEND:%s\n" % time.strftime('%Y%m%dT%H%M%SZ', - time.gmtime(float( - end.strftime('%s')))) - - content += "LOCATION:%s\n" % (talk['room'] if 'room' in talk else 'todo') - content += 'END:VEVENT\n' - return content + return None + e = ics.Event( + uid="%s@%d.hackmeeting.org\n" % (talk['id'], talk['day'].year), + name=talk['id'], + begin=talk['time'], + duration=datetime.timedelta(minutes=talk['duration']), + transparent=True, + ) + # ics.py has some problems with unicode + # unidecode replaces letters with their most similar ASCII counterparts + # (ie: accents get stripped) + e.description = unidecode.unidecode(talk['text']) + + e.url = pelican.settings['SCHEDULEURL'] + '#talk-' + talk['id'] + + return e class TalksGenerator(generators.Generator): @@ -354,10 +360,13 @@ class TalksGenerator(generators.Generator): if os.path.isdir(outdir): shutil.rmtree(outdir) shutil.copytree(self.talks[talkname]['resources'], outdir) - with io.open(os.path.join(self.output_path, pelican.settings.get('TALKS_ICS')), - 'w', - encoding='utf8') as buf: - buf.write(talks_to_ics()) + if ICS_ENABLED: + with io.open(os.path.join(self.output_path, pelican.settings.get('TALKS_ICS')), + 'w', + encoding='utf8') as buf: + buf.write(talks_to_ics()) + else: + logging.warning('module `ics` not found. ICS calendar will not be generated') def add_talks_option_defaults(pelican): diff --git a/publishconf.py b/publishconf.py index 3ccbd63..33818fc 100644 --- a/publishconf.py +++ b/publishconf.py @@ -14,6 +14,9 @@ SITEURL = '/hackit18' RELATIVE_URLS = True TALKS_GRID_STEP = 30 +# plugin/talks.py +SCHEDULEURL = 'https://hackmeeting.org' + SITEURL + '/schedule.html' + # DELETE_OUTPUT_DIRECTORY = True # Following items are often useful when publishing diff --git a/requirements.txt b/requirements.txt index abbf4e3..f27bc0c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,6 +3,7 @@ beautifulsoup4==4.6.0 blinker==1.3 docutils==0.12 feedgenerator==1.7 +ics==0.4 Jinja2==2.7.3 Markdown==2.6.1 MarkupSafe==0.23