import caldav from caldav import DAVClient from caldav import error # Importar correctamente import datetime import locale import json import pytz import os import logging # Configurar el registro de logs logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) # Establecer el locale a español para formatear fechas try: locale.setlocale(locale.LC_TIME, "es_ES.utf8") except locale.Error: logger.error("El locale 'es_ES.utf8' no está disponible en este sistema.") exit() # Ruta al archivo de credenciales credentials_file = '/home/teraflops/apikeys/icloud' # Verificar si el archivo existe if not os.path.isfile(credentials_file): logger.error(f"El archivo de credenciales '{credentials_file}' no existe.") exit() # Leer las credenciales del archivo credentials = {} with open(credentials_file, 'r') as f: for line in f: line = line.strip() if line and not line.startswith('#'): key, value = line.split('=', 1) # Remover comillas y espacios key = key.strip() value = value.strip().strip("'").strip('"') credentials[key] = value # Obtener el Apple ID y la contraseña APPLE_ID = credentials.get('ICLOUD_APPLE_ID') APP_PASSWORD = credentials.get('ICLOUD_APP_PASSWORD') if not APPLE_ID or not APP_PASSWORD: logger.error( "Las credenciales de Apple no están configuradas correctamente en el archivo.") exit() # Configuración de la zona horaria timezone = pytz.timezone('Europe/Madrid') # Cambia esto a tu zona horaria # Inicializar el cliente con verificación SSL client = DAVClient( url='https://caldav.icloud.com/', username=APPLE_ID, password=APP_PASSWORD, # ssl_verify_cert=True # Asegúrate de que la verificación SSL esté habilitada ) # Obtener el principal (usuario de iCloud) principal = client.principal() # Listar todos los calendarios disponibles calendars = principal.calendars() # Mostrar los nombres de los calendarios disponibles logger.info("Calendarios disponibles:") for calendar in calendars: logger.info(f"- '{calendar.name}'") # Definir los nombres de los calendarios deseados DESIRED_CALENDARS = ["Trabajo", "Recordatorios ⚠️"] # Inicializar una lista para los calendarios seleccionados selected_calendars = [] # Iterar a través de los calendarios para encontrar los deseados for calendar in calendars: for desired_name in DESIRED_CALENDARS: if calendar.name.strip().lower() == desired_name.strip().lower(): selected_calendars.append(calendar) logger.info(f"Calendario seleccionado: '{calendar.name}'") break # Salimos del bucle interno una vez que encontramos una coincidencia # Verificar si se encontraron los calendarios deseados if not selected_calendars: logger.error(f"No se encontraron los calendarios especificados: { ', '.join(DESIRED_CALENDARS)}") exit() # Definir el rango de tiempo: ahora hasta 7 días después now = datetime.datetime.now(timezone) in_7_days = now + datetime.timedelta(days=7) # Inicializar una lista para todos los eventos all_events = [] # Obtener eventos de cada calendario seleccionado utilizando calendar.search for calendar in selected_calendars: try: events = calendar.search( start=now, end=in_7_days, event=True, expand=True ) logger.info(f"Eventos obtenidos del calendario '{ calendar.name}': {len(events)}") # Agregar una tupla con el evento y el nombre del calendario for event in events: all_events.append((event, calendar.name)) except error.CalDAVError as e: logger.error(f"Error al obtener eventos del calendario '{ calendar.name}': {e}") continue # Función clave para ordenar los eventos def sort_key(event_tuple): event = event_tuple[0] dtstart = event.instance.vevent.dtstart.value if isinstance(dtstart, datetime.date) and not isinstance(dtstart, datetime.datetime): # Convertir datetime.date a datetime.datetime a medianoche dtstart = datetime.datetime.combine( dtstart, datetime.time(0, 0), tzinfo=timezone) elif dtstart.tzinfo is None: # Si dtstart es datetime pero sin información de zona horaria dtstart = timezone.localize(dtstart) else: # Asegurarse de que dtstart esté en la zona horaria correcta dtstart = dtstart.astimezone(timezone) return dtstart # Ordenar los eventos usando la función sort_key all_events.sort(key=sort_key) # Preparar eventos para el tooltip con formato de fecha en español event_list = [] if all_events: for event, calendar_name in all_events: try: event_details = event.vobject_instance vevent = event_details.vevent # Título del evento summary = vevent.summary.value if hasattr( vevent, 'summary') else 'Sin título' # Fecha y hora de inicio dtstart = vevent.dtstart.value if hasattr( vevent, 'dtstart') else None # Fecha y hora de fin dtend = vevent.dtend.value if hasattr(vevent, 'dtend') else None # Todo el día all_day = isinstance(dtstart, datetime.date) and not isinstance( dtstart, datetime.datetime) # Formatear fecha y hora de inicio if dtstart: if all_day: dtstart_str = dtstart.strftime( '%A %d de %B') + " (Todo el día)" else: if dtstart.tzinfo is None: dtstart = timezone.localize(dtstart) else: dtstart = dtstart.astimezone(timezone) dtstart_str = dtstart.strftime('%A %d de %B %H:%M') else: dtstart_str = '' # Formatear fecha y hora de fin if dtend: if all_day: dtend_str = dtend.strftime( '%A %d de %B') + " (Todo el día)" else: if dtend.tzinfo is None: dtend = timezone.localize(dtend) else: dtend = dtend.astimezone(timezone) dtend_str = dtend.strftime('%A %d de %B %H:%M') else: dtend_str = '' # Construir el texto del evento event_text = f"📅 {summary} ({calendar_name})" event_text += f"\n 🕒 Inicio: {dtstart_str}" if dtstart_str else '' event_text += f"\n 🕔 Fin: {dtend_str}" if dtend_str else '' event_text += "\n 📆 Todo el día: Sí" if all_day else '' event_list.append(event_text) except Exception as e: logger.error(f"Error al procesar el evento: {e}") continue else: event_list.append("No hay eventos en los próximos 7 días") # **Modificar la creación del JSON de salida para Waybar** # 1. Mostrar la fecha actual en español en la barra # 2. Si hay eventos, añadir un icono o número junto a la fecha # Definir el icono que se mostrará si hay eventos EVENT_ICON = "󱢞" # Puedes cambiar este icono por otro que prefieras # Calcular el número de eventos próximos event_count = len(all_events) # Construir el texto para la barra if event_count > 0: # Puedes optar por mostrar solo el número, el icono, o ambos # Ejemplos: # Solo número: text = "Fecha | 3" # Solo icono: text = "Fecha 📅" # Icono y número: text = "Fecha 📅3" # Aquí mostramos el icono y el número text = f"{now.strftime('%A %d de %B %H:%M')} {EVENT_ICON}{event_count}" else: text = now.strftime('%A %d de %B %H:%M') # Crear el JSON de salida para Waybar con tooltip en español output = { "text": text, # Texto modificado "tooltip": "\n\n".join(event_list), "class": "calendar" } # Salida JSON print(json.dumps(output))