add daily todo printer
This commit is contained in:
parent
ec86c1c307
commit
42062c2eb6
1 changed files with 168 additions and 0 deletions
168
daily-todo.py
Normal file
168
daily-todo.py
Normal file
|
@ -0,0 +1,168 @@
|
|||
import logging
|
||||
import os
|
||||
import sys
|
||||
from datetime import date, datetime, timedelta
|
||||
from random import randint
|
||||
|
||||
from caldav import DAVClient
|
||||
from dotenv import find_dotenv, load_dotenv
|
||||
|
||||
from printer import p
|
||||
|
||||
logging.basicConfig(
|
||||
format="{asctime} {levelname:8} {name}: {message}",
|
||||
datefmt="%Y-%m-%d %H:%M:%S",
|
||||
style="{",
|
||||
stream=sys.stdout,
|
||||
force=True,
|
||||
)
|
||||
|
||||
log = logging.getLogger("todo-receipt")
|
||||
log.setLevel(logging.DEBUG)
|
||||
|
||||
if load_dotenv(find_dotenv(usecwd=True)):
|
||||
log.debug("Loaded .env")
|
||||
else:
|
||||
log.debug("Didn't find .env")
|
||||
|
||||
CALDAV_URL = os.getenv("CALDAV_URL")
|
||||
CALDAV_USERNAME = os.getenv("CALDAV_USERNAME")
|
||||
CALDAV_PASSWORD = os.getenv("CALDAV_PASSWORD")
|
||||
|
||||
day = timedelta(days=1)
|
||||
week = timedelta(days=7)
|
||||
today = date.today()
|
||||
yesterday = today - day
|
||||
tomorrow = today + day
|
||||
next_week = today + week
|
||||
|
||||
|
||||
def coerce_date(datetime):
|
||||
try:
|
||||
return datetime.date()
|
||||
except:
|
||||
return datetime
|
||||
|
||||
|
||||
def shuffle_with_priority(tasks):
|
||||
return sorted(
|
||||
tasks,
|
||||
key=lambda task: (
|
||||
task.icalendar_component.get("priority", 5),
|
||||
randint(0, 10),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
with DAVClient(
|
||||
url=CALDAV_URL, username=CALDAV_USERNAME, password=CALDAV_PASSWORD
|
||||
) as client:
|
||||
log.debug("Loading calendars")
|
||||
principal = client.principal()
|
||||
calendars = principal.calendars()
|
||||
|
||||
events = []
|
||||
todos = []
|
||||
|
||||
for c in calendars:
|
||||
log.debug(f"Fetching from {c.name}")
|
||||
if c.name not in ["Schedule"]:
|
||||
log.debug("Fetching events and todos")
|
||||
events.extend(c.events())
|
||||
todos.extend(c.todos())
|
||||
else:
|
||||
log.debug("Finding cancelled classes")
|
||||
for event in c.events():
|
||||
if event.icalendar_component.get("status") == "CANCELED":
|
||||
log.debug(
|
||||
f"Found cancelled class {event.icalendar_component.get('summary')}"
|
||||
)
|
||||
events.append(event)
|
||||
|
||||
must_do = []
|
||||
should_do = []
|
||||
want_to_do = []
|
||||
|
||||
log.debug("Processing todos")
|
||||
for task in todos:
|
||||
due = task.get_due()
|
||||
if due is None:
|
||||
want_to_do.append(task)
|
||||
continue
|
||||
|
||||
task.expand_rrule(yesterday, next_week)
|
||||
due = coerce_date(due)
|
||||
|
||||
start = coerce_date(task.icalendar_component.get("dtstart").dt or yesterday)
|
||||
|
||||
if today < start:
|
||||
continue
|
||||
|
||||
if due < tomorrow:
|
||||
must_do.append(task)
|
||||
elif due < next_week:
|
||||
should_do.append(task)
|
||||
else:
|
||||
want_to_do.append(task)
|
||||
|
||||
scheduled = []
|
||||
|
||||
log.debug("Processing events")
|
||||
for event in events:
|
||||
event.expand_rrule(yesterday, next_week)
|
||||
start_day = coerce_date(event.icalendar_component.get("dtstart").dt)
|
||||
end_day = coerce_date(event.icalendar_component.get("dtend").dt)
|
||||
|
||||
if end_day < today or today < start_day:
|
||||
continue
|
||||
else:
|
||||
scheduled.append(event)
|
||||
|
||||
should_do = shuffle_with_priority(should_do)
|
||||
want_to_do = shuffle_with_priority(want_to_do)
|
||||
|
||||
while len(must_do) < 2:
|
||||
if should_do:
|
||||
must_do.append(should_do.pop(0))
|
||||
elif want_to_do:
|
||||
must_do.append(want_to_do.pop(0))
|
||||
else:
|
||||
break # No remaining tasks
|
||||
|
||||
while len(should_do) < 3:
|
||||
if want_to_do:
|
||||
should_do.append(want_to_do.pop(0))
|
||||
else:
|
||||
break # No remaining tasks
|
||||
|
||||
categories = {
|
||||
"Must do": must_do,
|
||||
"Should do": should_do[:3],
|
||||
"Want to do": want_to_do[:3],
|
||||
}
|
||||
|
||||
with p:
|
||||
log.debug("Printing output")
|
||||
p.title(" TODO List ", size=4)
|
||||
p.subtitle(datetime.today().strftime("%Y-%m-%d"))
|
||||
p.ln()
|
||||
|
||||
if scheduled:
|
||||
p.textln("Scheduled:")
|
||||
for event in scheduled:
|
||||
summary = event.icalendar_component["summary"]
|
||||
if event.icalendar_component.get("status") == "CANCELED":
|
||||
summary += " (CANCELED)"
|
||||
start = event.icalendar_component.get("dtstart").dt
|
||||
p.textln(f"[ ] {summary} @ {start.strftime('%H:%M')}")
|
||||
else:
|
||||
p.textln("Scheduled: (None)")
|
||||
|
||||
for k, v in categories.items():
|
||||
p.ln()
|
||||
if v:
|
||||
p.textln(f"{k}:")
|
||||
for task in v:
|
||||
p.textln(f"[ ] {task.icalendar_component['summary']}")
|
||||
else:
|
||||
p.textln(f"{k}: (None)")
|
Loading…
Add table
Reference in a new issue