#!/usr/bin/env python3 import requests import os from bs4 import BeautifulSoup from datetime import datetime, timedelta import locale import pytz from icalendar import Calendar, Event def zic2ics(): locale.setlocale(locale.LC_TIME,'it_IT.UTF-8') os.makedirs('history', exist_ok=True) cal = Calendar() cal.add('prodid', '-//Agenda di zic.it//') cal.add('version', '2.0') page = requests.get("https://zic.it/agenda/") soup = BeautifulSoup(page.content, "html.parser") agenda = soup.find("div", class_="entry-content clearfix") entries = agenda.find_all("p", style=None) for entry in entries: try: lnk = entry.find('a', href=True)['href'] spe = entry.get_text(strip=True, separator='\n').splitlines() tit = spe[0].strip() dat = datetime.strptime(spe[2], "%A %d %B %Y - %H:%M").replace(tzinfo=pytz.timezone('Europe/Rome')) det = spe[3][2:-2].split(";") dov = det[0].strip() chi = det[1].strip() if 1 < len(det) else "" # print(" ~ ".join([tit, str(dat), dov, chi])) uid = "|".join([dat.strftime("%Y%m%d"), tit, dov]) event = Event() event.add('summary', tit) event.add('dtstart', dat) event.add('description', chi) event.add('location', dov) event.add('url', lnk) event.add('uid', uid) cal.add_component(event) except: pass ical = cal.to_ical() try: with open('zic.ics', 'rb') as f: ical_last = f.read() except: ical_last = "" if ical != ical_last: try: with open('zic_all.ics', 'rb') as f: cal_all = Calendar.from_ical(f.read()) except: cal_all = Calendar() ical_all = icalmerge(cal_all, cal).to_ical() with open('zic.ics', 'wb') as f: f.write(ical) with open('zic_all.ics', 'wb') as f: f.write(ical_all) with open(os.path.join('history','zic_%s.ics' % datetime.now().strftime("%Y%m%d%H%M%S")), 'wb') as f: f.write(ical) with open(os.path.join('history','zic_%s.html' % datetime.now().strftime("%Y%m%d%H%M%S")), 'wb') as f: f.write(page.content) def icalmerge(calold, calnew, delete = False, tolerance = 15): cal = Calendar() cal.add('prodid', calnew.get('prodid').to_ical().decode('utf-8')) cal.add('version', calnew.get('version').to_ical().decode('utf-8')) #Add a computed UID if missing for e in calold.walk('VEVENT'): if e.get('UID') is None: uid = "|".join([e.decoded('dtstart').strftime("%Y%m%d"), e.get('Summary').to_ical().decode('utf-8'), e.get('Location').to_ical().decode('utf-8')]) e.add('uid', uid) for e in calnew.walk('VEVENT'): if e.get('UID') is None: uid = "|".join([e.decoded('dtstart').strftime("%Y%m%d"), e.get('Summary').to_ical().decode('utf-8'), e.get('Location').to_ical().decode('utf-8')]) e.add('uid', uid) calold_uids = [e.get('UID').to_ical().decode('utf-8') for e in calold.walk('VEVENT')] calnew_uids = [e.get('UID').to_ical().decode('utf-8') for e in calnew.walk('VEVENT')] imported_uids = [] for e in calold.walk('VEVENT'): uid = e.get('UID').to_ical().decode('utf-8') if uid not in calnew_uids: if e.decoded('dtstart') < datetime.now(pytz.UTC) + timedelta(minutes = tolerance): print("Past \"%s\"" % uid) cal.add_component(e) else: if delete: print("Deleted \"%s\"" % uid) else: print("Cancelled \"%s\"" % uid) e.add('status', 'CANCELLED') cal.add_component(e) for e in calnew.walk('VEVENT'): uid = e.get('UID').to_ical().decode('utf-8') if uid not in calold_uids: print("Added \"%s\"" % uid) cal.add_component(e) else: # print("Updated \"%s\"" % uid) cal.add_component(e) return(cal) if __name__ == "__main__": os.chdir(os.path.dirname(__file__)) zic2ics()