#!/usr/bin/env python #-*- encoding: utf-8 import sys import requests from html.parser import HTMLParser from datetime import datetime as dt, time import caldav from icalendar import Calendar, Event import pytz # Constants definition URL = "https://docs.google.com/spreadsheets/u/0/d/e/2PACX-1vQ9yzFLr5mXbIZVK3ucdUZuScAbLoCyPqzHr-5V0aYeCFEz7LuidPdk_EnkkJT-zjemzQQHaKvpeXW2/pubhtml/sheet?headers=false&gid=1619638924" TIMETABLE = [ ('08:00','08:00'), ('09:00','09:00'), ('10:00','10:15'), ('11:15','11:15'), ('12:15','12:15'), ('13:00','13:00'), ('13:30','13:30'), ('14:30','14:30'), ('15:30','15:45'), ('16:45','16:45'), ('17:45','17:45'), ] DAVURL = "https://cal.edgarpierre.fr" CALURL = "https://cal.edgarpierre.fr/edpibu/817427eb-be7c-4540-872a-dfb723a205a6/" class GoogleSheetsCalParser(HTMLParser): """ Definition of a Google Sheets parser providing a table with each cell and its position and size """ def __init__(self): self.inTable = False self.inCell = False self.inDate = False self.inEvent = False self.row = -1 self.column = -1 self.nextCol = -1 self.rowspan = 0 self.multirows = {} self.date = {} self.event = Event() self.event['uid'] = 0 self.uids = [] import priv client = caldav.DAVClient(url=DAVURL, username=priv.USERNAME, password=priv.PASSWORD) self.calendar = caldav.Calendar(client=client, url=CALURL) #print(self.calendar.event_by_uid('42x26').data) HTMLParser.__init__(self) def handle_starttag(self, tag, attrs): dAttrs = dict(attrs) if self.inTable: if tag == 'tr': self.row += 1 self.nextCol = -1 elif tag == 'td': while self.nextCol in self.multirows.keys() and self.multirows[self.nextCol][1] > 0: self.nextCol += self.multirows[self.nextCol][0] self.column = self.nextCol if 'colspan' in dAttrs.keys(): self.nextCol += int(dAttrs['colspan']) else: self.nextCol += 1 if not (self.row < 3 or (self.row - 2) % 12 < 2): self.inCell = True if 'rowspan' in dAttrs.keys(): self.rowspan = int(dAttrs['rowspan']) self.multirows[self.column] = [self.nextCol - self.column, self.rowspan] else: self.rowspan = 1 elif (self.row - 2) % 12 == 1: self.inDate = True elif tag == 'tbody': self.inTable = True def handle_endtag(self, tag): if tag == 'td': self.inCell = False self.inDate = False if self.inEvent: self.inEvent = False cal = Calendar() cal.add('prodid', '-//edpibu//edt-parser//FR') cal.add('version', '2.0') cal.add_component(self.event) self.uids.append(self.event['uid']) try: ev = self.calendar.event_by_uid(self.event['uid']) except caldav.lib.error.NotFoundError: ev = None if ev: icev = Calendar.from_ical(ev.data).subcomponents[1] ex = True if icev['summary'] != self.event['summary']: ex = False else: for key in ['dtstart', 'dtend']: if icev[key].to_ical() != self.event[key].to_ical(): ex = False if ex: return print(f'Change on {self.event.decoded("dtstart").isoformat()}') ev.data = cal.to_ical().decode('utf-8') ev.save() return print(f'New event on {self.event.decoded("dtstart").isoformat()}') self.calendar.save_event(cal.to_ical().decode('utf-8')) elif tag == 'tr': for mr in self.multirows.values(): mr[1] -= 1 elif tag == 'tbody': self.inTable = False for ev in self.calendar.events(): icev = Calendar.from_ical(ev.data).subcomponents[1] if icev['uid'] not in self.uids: ev.delete() print(f'Deleted event on {icev.decoded("dtstart").isoformat()}') def handle_data(self, data): if self.inDate: self.date[self.column] = dt.strptime(data, '%d-%b-%y').date() elif self.inCell and data not in ['', '-']: self.inEvent = True times = [time.fromisoformat(TIMETABLE[(self.row - 2) % 12 - 2][1]), time.fromisoformat(TIMETABLE[(self.row - 2) % 12 - 2 + self.rowspan][0])] if self.event['uid'] == f'{self.row}x{self.column}': self.event['summary'] = f'{self.event["summary"]} {data}' else: self.event = Event() self.event.add('uid', f'{self.row}x{self.column}') self.event.add('summary', data) self.event.add('dtstamp', dt.now()) self.event.add('dtstart', dt.combine(self.date[self.column], times[0], pytz.timezone('Europe/Paris'))) self.event.add('dtend', dt.combine(self.date[self.column], times[1], pytz.timezone('Europe/Paris'))) # Getting the Google Sheet try: r = requests.get(URL) except ConnectionError as e: print(e) sys.exit(1) if r.status_code != 200: print(f'Status Code {r.status_code}; could not continue.') sys.exit(1) # Parsing the Sheet calParser = GoogleSheetsCalParser() calParser.feed(r.text)