hackertours-schedule/voc/webcal2.py
2025-11-18 19:05:41 +01:00

119 lines
No EOL
4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import re
import icalendar
import requests
from voc import GenericConference
from voc.event import Event, EventSourceInterface
from voc.schedule import Schedule, ScheduleException
from voc.tools import format_duration, gen_person_uuid, gen_uuid
class WebcalConference2(GenericConference, EventSourceInterface):
def __init__(self, **args):
GenericConference.__init__(self, **args)
def schedule(self, template: Schedule):
if not self.schedule_url or self.schedule_url == 'TBD':
raise ScheduleException(' has no schedule url yet ignoring')
url = re.sub(r'^webcal', 'http', self.schedule_url)
r = requests.get(url, timeout=10)
if r.status_code != 200:
raise ScheduleException(f' Failed to retrieve iCal feed: Error ({r.status_code})')
cal = icalendar.Calendar.from_ical(r.text)
schedule = template.copy(self['name']) or Schedule(conference=self)
for e in cal.walk('vevent'):
try:
event = Event(convert_to_dict(e, self), origin=self)
schedule.add_event(event)
except Exception as e:
print(e)
return schedule
def convert_to_dict(e: icalendar.Event, context: WebcalConference2) -> dict:
# title, subtitle, event_type = re.match(r"^(.+?)(?:( ?[:] .+?))?(?: \((.+?)\))?$", e.name).groups()
track, = [ str(c) for c in e.get('categories').cats] or [None]
begin = e['dtstart'].dt
end = e['dtend'].dt
duration = end - begin
return { k: (v if isinstance(v, list) or v is None else str(v)) for k, v in {
"guid": gen_uuid(e['uid']),
"id": e['event-id'],
"title": e.get('summary'),
"subtitle": '',
"abstract": e['description'],
"description": '', # empty description for pretalx importer (temporary workaround)
"date": begin.isoformat(),
"start": begin.strftime("%H:%M"),
"duration": format_duration(duration),
"room": track, #context['name'],
"persons": [{
**p,
"id": 0
} for p in extract_persons(e)],
"track": track,
"language": 'de',
"type": 'Session' or 'Other',
"url": e.get('url', None),
}.items() }
def extract_persons(e: icalendar.Event) -> list:
person_str = str(e.get('location', '')).replace(' und ', '; ').strip()
print(person_str)
# persons = re.split(r'\s*[,;/]\s*', person_str)
persons = re.split(r'[,;/](?![^()]*\))', person_str)
if len(persons) == 0:
return []
pattern = r'([^()]+)(?:\((\w{2,3}\s+)?([^)]*)\))'
result = []
for p in persons:
# p is either "name (org)" or or "name (org role)" or "name (name@org.tld)"
match = re.match(pattern, p)
if match:
name, org, role = match.groups()
if role and '@' in role:
match = re.search(r'@(.+)(\.de)?$', role)
org = match.group(1)
result.append({
"name": name.strip(),
"org": org.strip(),
"email": role.strip(),
"guid": gen_person_uuid(role)
})
else:
if not org:
if len(role) <= 3:
org = role
role = None
else:
# try catch `Distribution Cordinator, ZER` and split org
m = re.match(r'^(.+?), (\w{2,3})$', role)
if m:
org = m.group(2)
role = m.group(1)
if name:
result.append({
"name": name.strip(),
"org": org.strip() if org else None,
"role": role.strip() if role else None,
})
elif p:
result.append({
"name": p.strip(),
})
print(result)
print()
return result
if __name__ == '__main__':
WebcalConference()