first running version

This commit is contained in:
Yax 2025-09-13 17:15:46 +02:00
parent 62ad8686d9
commit b71ab8d8ae
4 changed files with 110 additions and 0 deletions

4
.env.default Normal file
View file

@ -0,0 +1,4 @@
CALDAV_USERNAME=
CALDAV_PASSWORD=
CALDAV_URL=
NEXT_DAYS=10

1
.gitignore vendored
View file

@ -162,3 +162,4 @@ cython_debug/
# option (not recommended) you can uncomment the following to ignore the entire idea folder. # option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/ #.idea/
.env

80
caldav-reminder.py Normal file
View file

@ -0,0 +1,80 @@
#!/usr/bin/python3
"""calendar reminder
this logs into a caldav server and get a digest of all of the
events scheduled for next days. Good candidate to run from cron
"""
import sys
import os
from dotenv import load_dotenv
from datetime import timedelta, date
from os import environ
from urllib.parse import quote_plus
import caldav
load_dotenv()
# read parameters from dot env
USERNAME = os.getenv('CALDAV_USERNAME')
PASSWORD = os.getenv('CALDAV_PASSWORD')
BASE_URL = os.getenv('CALDAV_URL')
NEXT_DAYS = int(os.getenv('NEXT_DAYS'))
def fill_event(component, calendar) -> dict[str, str]:
# quite some data is tossed away here - like, the recurring rule.
cur = {}
cur["calendar"] = f"{calendar}"
cur["summary"] = component.get("summary")
cur["description"] = component.get("description")
# month/day/year time? Never ever do that!
# It's one of the most confusing date formats ever!
# Use year-month-day time instead ... https://xkcd.com/1179/
cur["start"] = component.start.strftime("%m/%d/%Y %H:%M")
endDate = component.end
if endDate:
cur["end"] = endDate.strftime("%m/%d/%Y %H:%M")
return cur
def fill_todo(component, calendar) -> dict[str, str]:
cur = {}
cur["calendar"] = f"{calendar}"
cur["summary"] = component.get("summary")
cur["description"] = component.get("description")
return cur
def display_event(event: dict[str, str]):
print(event["start"] + " " + event["calendar"] + "/" + event["summary"])
def display_todo(todo: dict[str, str]):
print("Todo : " + todo["summary"])
url = 'https://' + quote_plus(USERNAME) + ":" + quote_plus(PASSWORD) \
+ '@' + BASE_URL + quote_plus(USERNAME) + '/'
start = date.today()
end = start + timedelta(days=NEXT_DAYS)
client = caldav.DAVClient(url)
calendars = client.principal().calendars()
if not calendars:
print("No calendars defined for " + USERNAME)
sys.exit(0)
for cal in calendars:
events = cal.search(event=True, start=start, end=end, expand=True) \
+ cal.search(todo=True)
for event in events:
for component in event.icalendar_instance.walk():
if component.name == "VEVENT":
display_event(fill_event(component, cal))
elif component.name == "VTODO":
display_todo(fill_todo(component, cal))
print(".")

25
pyproject.toml Normal file
View file

@ -0,0 +1,25 @@
[project]
name = "caldav-reminder"
version = "1.0"
description = "CalDav Reminder"
readme = "README.md"
authors = [
{ name = "Yax" }
]
requires-python = ">=3.13.1"
dependencies = [
"caldav>=2.0.1",
"python-dotenv>=1.1.1",
]
[dependency-groups]
dev = [
]
[tool.setuptools]
[tool.setuptools.package-data]
[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"