import yaml import caldav import sys if len(sys.argv) > 1: import os os.chdir(sys.argv[1]) with open('auth.yaml') as f: auth = yaml.full_load(f) try: with open('data.yaml') as f: known = yaml.full_load(f) except: known = {} logins = {} for login, content in auth['logins'].items(): logins[login] = caldav.DAVClient(url=content['url'], username=content['user'], password=content['password']) cals = [] for cal in auth['cals']: cals.append(caldav.Calendar(client = logins[cal['login']], url = cal['url'])) changed = {} deleted = {} def cal_contains_uid(cal, uid): try: event = cal.event_by_uid(uid) return True except caldav.lib.error.NotFoundError: return False for cal in cals: print("Checking %s" % (cal.canonical_url,)) for event in cal.events(): uid = event.vobject_instance.vevent.uid.value data = event.data entry = (cal.canonical_url, event) if uid not in known: print("Found new event with summary %s" % (event.vobject_instance.vevent.summary.value,)) if uid not in changed: changed[uid] = [entry] else: changed[uid].append(entry) else: if data != known[uid]: print("Found changed event with summary %s" % (event.vobject_instance.vevent.summary.value,)) if uid not in changed: changed[uid] = [entry] else: changed[uid].append(entry) print("Checking for deletions") for uid, data in known.items(): for cal in cals: if not cal_contains_uid(cal, uid): print("Item with uid %s got deleted in %s" % (uid, cal.canonical_url)) if uid not in deleted: deleted[uid] = [cal.canonical_url] else: deleted[uid].append(cal.canonical_url) for uid, arr in changed.items(): if uid in deleted: print("Changed/new entry with UID (%s), summary \"%s\" was also deleted, recreating it." % (uid, arr[0][1].vobject_instance.vevent.uid.value), file=sys.stderr) print("Deletions in:", file=sys.stderr) for cal in deleted[uid]: print(" - %s" % (cal,), file=sys.stderr) print("Changes in:", file=sys.stderr) for entry in arr: print(" - %s" % (entry[0],), file=sys.stderr) print("", file=sys.stderr) del deleted[uid] if len(set([entry[1].data for entry in arr])) != 1: print("Multiple changed/new entries with the same UID (%s) detected:" % (uid,), file=sys.stderr) for ev in arr: print(" %s: %s" % (ev[0], ev[1].vobject_instance.vevent.summary.value), file = sys.stderr) continue entry = arr[0] changed_cals = [ entry[0] for entry in arr ] for cal in cals: if cal.canonical_url not in changed_cals: try: old = cal.event_by_uid(uid) print("Overwriting event from %s with data %s (source: %s)" % (cal.canonical_url, repr(old.data), changed_cals)) new = False except: new = True cal.save_event(entry[1].data) if new: print("Creating new event in %s with summary %s" % (cal.canonical_url, cal.event_by_uid(uid).vobject_instance.vevent.summary.value)) known[uid] = entry[1].data for uid in deleted: for cal in cals: if cal_contains_uid(cal, uid): evt = cal.event_by_uid(uid) print("Deleting event from %s with data %s (source: %s)" % (cal.canonical_url, repr(evt.data), deleted[uid])) cal.event_by_uid(uid).delete() del known[uid] print("Done.") print() with open("data.yaml", "w") as f: yaml.dump(known, f)