""" modules/calendar.py — FRIDAY Calendar Manager Active calendar management: - Add events/reminders - Upcoming events check - Time tracking - Meeting reminders """ import json import os import time from datetime import datetime, timedelta from config import DATA_DIR CAL_FILE = os.path.join(DATA_DIR, "calendar.json") def _load() -> dict: if not os.path.exists(CAL_FILE): return {"events": []} try: with open(CAL_FILE, "r") as f: return json.load(f) except Exception: return {"events": []} def _save(data: dict): with open(CAL_FILE, "w") as f: json.dump(data, f, indent=2) def add_event(title: str, when: str = "", duration: int = 60) -> str: """Add calendar event.""" data = _load() # Simple time parsing event_time = time.time() if "today" in when.lower(): pass # today elif "tomorrow" in when.lower(): event_time += 86400 elif "monday" in when.lower(): # Find next Monday days_ahead = (7 - datetime.now().weekday() + 0) % 7 if days_ahead == 0: days_ahead = 7 event_time += days_ahead * 86400 elif "week" in when.lower(): event_time += 7 * 86400 data.setdefault("events", []).append({ "title": title, "time": event_time, "duration": duration, }) _save(data) return f"Event: {title}, added." def get_upcoming(limit: int = 5) -> list: """Get upcoming events.""" data = _load() now = time.time() upcoming = [e for e in data.get("events", []) if e.get("time", 0) > now] upcoming.sort(key=lambda x: x.get("time", 0)) return upcoming[:limit] def view_today() -> str: """View today's events.""" data = _load() now = time.time() today_start = now - (now % 86400) today_end = today_start + 86400 today_events = [] for e in data.get("events", []): t = e.get("time", 0) if today_start <= t < today_end: dt = datetime.fromtimestamp(t) time_str = dt.strftime("%I:%M") today_events.append(f"{time_str} - {e['title']}") if not today_events: return "Nothing scheduled today." return "Today: " + ", ".join(today_events) def check_reminders() -> list: """Check if any reminders due.""" import threading data = _load() now = time.time() due = [] for e in data.get("events", []): t = e.get("time", 0) if t <= now < t + 300: # within 5 min window due.append(e) return due # ── Voice Commands ──────────────────────────────────────────── def handle_command(command: str, speak) -> bool: """Handle calendar commands.""" c = command.lower() # Add event if "schedule" in c or "add event" in c or "remind me" in c: title = c.replace("schedule", "").replace("add event", "").replace("remind me to", "").strip() if title: when = c # Could parse more msg = add_event(title, when) speak(msg) return True # Today's schedule if "today" in c and ("schedule" in c or "events" in c or "what" in c): msg = view_today() speak(msg) return True # Upcoming if "upcoming" in c or "next" in c: events = get_upcoming() if events: lines = [datetime.fromtimestamp(e['time']).strftime("%a %I:%M") + " " + e['title'] for e in events[:3]] speak("Upcoming: " + ", ".join(lines)) else: speak("No upcoming events.") return True # Check reminders if "check reminders" in c or "alerts" in c: reminders = check_reminders() if reminders: for r in reminders: speak(f"REMINDER: {r['title']}") else: speak("No reminders due.") return True return False