thermoprint-homework/jobs/tasks.py
2026-02-01 20:20:29 +01:00

109 lines
4.0 KiB
Python

import datetime
import os.path
from .base import Job
# Wrap imports to prevent crashing if dependencies are missing
try:
import requests
import icalendar
import recurring_ical_events
import pytz
HAS_ICAL_DEPS = True
except ImportError:
HAS_ICAL_DEPS = False
class TasksJob(Job):
def get_name(self):
return "UKOLY DNE"
def configure(self):
print("\n--- Configure Calendar URL ---")
print("To find your Google Calendar URL:")
print("1. Go to Settings > Select Calendar > Integrate calendar")
print("2. Copy 'Secret address in iCal format'")
print("-" * 30)
print("Enter the public or secret address in iCal format (.ics).")
print("Example: https://calendar.google.com/calendar/ical/.../basic.ics")
url = input("URL: ").strip()
if url:
with open('calendar_url.txt', 'w') as f:
f.write(url)
print("URL saved.")
def print_body(self, p):
if not HAS_ICAL_DEPS:
print("Error: Missing iCal Libraries.")
p.text("Error: Missing iCal Libraries.\n")
p.text("Run: pip install requests icalendar recurring-ical-events pytz\n")
return
if not os.path.exists('calendar_url.txt'):
print("Error: Calendar URL not configured.")
p.text("Error: Calendar URL not configured.\n")
p.text("Run configuration in TUI first.\n")
return
with open('calendar_url.txt', 'r') as f:
url = f.read().strip()
try:
# 1. Fetch the .ics file
# Timeout is important so the printer doesn't hang forever
response = requests.get(url, timeout=30)
response.raise_for_status()
# 2. Parse Calendar
cal = icalendar.Calendar.from_ical(response.content)
# 3. Calculate Time Range (Today)
now = datetime.datetime.now().astimezone()
start_of_day = now.replace(hour=0, minute=0, second=0, microsecond=0)
end_of_day = now.replace(hour=23, minute=59, second=59, microsecond=0)
# 4. Expand Recurring Events
# This library handles RRULEs (e.g. "Every Monday") automatically
events = recurring_ical_events.of(cal).between(start_of_day, end_of_day)
# 5. Sort by start time
# Helper to get sortable time
def get_start_time(e):
dt = e.get('DTSTART').dt
# If it's a date object (all day), convert to datetime for sorting
if not isinstance(dt, datetime.datetime):
return datetime.datetime.combine(dt, datetime.time.min).replace(tzinfo=now.tzinfo)
return dt
events.sort(key=get_start_time)
if not events:
p.text("Zadne ukoly pro dnesni den.\n")
else:
for event in events:
summary = str(event.get('SUMMARY', '(bez nazvu)'))
dtstart = event.get('DTSTART').dt
# Format time
if not isinstance(dtstart, datetime.datetime):
time_str = "Cely den"
else:
# Convert to local system time for display
# (If dtstart is timezone aware, astimezone(None) converts to local)
local_dt = dtstart.astimezone(now.tzinfo)
time_str = local_dt.strftime('%H:%M')
# Print Entry
p.set(bold=True)
p.text(f"{time_str} [_]")
p.set(bold=False)
p.text(f" {summary}\n")
location = event.get('LOCATION')
if location:
p.text(f" @ {str(location)}\n")
p.text("-" * 32 + "\n")
except Exception as e:
print(f"Error: {e}")
p.text(f"Error: {e}\n")