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