Personal noctalia plugins collection
at 1a731775408725b0212555294f1d387e1fdf1125 105 lines 3.9 kB view raw
1#!/usr/bin/env python3 2"""Update or delete a VEVENT item via Evolution Data Server.""" 3 4import argparse 5import json 6import sys 7from datetime import datetime, timezone 8 9import gi 10gi.require_version("ECal", "2.0") 11gi.require_version("EDataServer", "1.2") 12gi.require_version("ICalGLib", "3.0") 13from gi.repository import ECal, EDataServer, ICalGLib 14 15 16def find_calendar_source(registry, calendar_uid): 17 source = registry.ref_source(calendar_uid) 18 if source and source.has_extension(EDataServer.SOURCE_EXTENSION_CALENDAR): 19 return source 20 for src in registry.list_sources(EDataServer.SOURCE_EXTENSION_CALENDAR): 21 if src.get_display_name() == calendar_uid or src.get_uid() == calendar_uid: 22 return src 23 return None 24 25 26def remove_property(comp, kind): 27 """Remove all properties of the given kind from a component.""" 28 prop = comp.get_first_property(kind) 29 while prop: 30 comp.remove_property(prop) 31 prop = comp.get_first_property(kind) 32 33 34def main(): 35 parser = argparse.ArgumentParser(description="Update/delete EDS VEVENT item") 36 parser.add_argument("--calendar", required=True, help="Calendar source UID") 37 parser.add_argument("--uid", required=True, help="VEVENT UID") 38 parser.add_argument("--action", required=True, choices=["delete", "update"], 39 help="Action to perform") 40 parser.add_argument("--summary", help="New event summary") 41 parser.add_argument("--location", help="New event location") 42 parser.add_argument("--description", help="New event description") 43 parser.add_argument("--start", type=int, help="New start time (unix timestamp)") 44 parser.add_argument("--end", type=int, help="New end time (unix timestamp)") 45 args = parser.parse_args() 46 47 try: 48 registry = EDataServer.SourceRegistry.new_sync(None) 49 source = find_calendar_source(registry, args.calendar) 50 if not source: 51 print(json.dumps({"success": False, "error": f"Calendar not found: {args.calendar}"})) 52 sys.exit(1) 53 54 client = ECal.Client.connect_sync( 55 source, ECal.ClientSourceType.EVENTS, 1, None 56 ) 57 58 if args.action == "delete": 59 client.remove_object_sync(args.uid, None, ECal.ObjModType.ALL, ECal.OperationFlags.NONE, None) 60 print(json.dumps({"success": True})) 61 return 62 63 # For update, fetch the existing component first 64 success, comp = client.get_object_sync(args.uid, None, None) 65 if not success or not comp: 66 print(json.dumps({"success": False, "error": "VEVENT not found"})) 67 sys.exit(1) 68 69 ical = comp.get_icalcomponent() 70 71 if args.summary is not None: 72 ical.set_summary(args.summary) 73 74 if args.location is not None: 75 ical.set_location(args.location) 76 77 if args.description is not None: 78 ical.set_description(args.description) 79 80 if args.start is not None: 81 dt = datetime.fromtimestamp(args.start, tz=timezone.utc) 82 t = ICalGLib.Time.new_null_time() 83 t.set_date(dt.year, dt.month, dt.day) 84 t.set_time(dt.hour, dt.minute, dt.second) 85 t.set_timezone(ICalGLib.Timezone.get_utc_timezone()) 86 ical.set_dtstart(t) 87 88 if args.end is not None: 89 dt = datetime.fromtimestamp(args.end, tz=timezone.utc) 90 t = ICalGLib.Time.new_null_time() 91 t.set_date(dt.year, dt.month, dt.day) 92 t.set_time(dt.hour, dt.minute, dt.second) 93 t.set_timezone(ICalGLib.Timezone.get_utc_timezone()) 94 ical.set_dtend(t) 95 96 client.modify_object_sync(comp, ECal.ObjModType.ALL, ECal.OperationFlags.NONE, None) 97 print(json.dumps({"success": True})) 98 99 except Exception as e: 100 print(json.dumps({"success": False, "error": str(e)})) 101 sys.exit(1) 102 103 104if __name__ == "__main__": 105 main()