Massive refactoring, json functionality added

This commit is contained in:
Yessiest 2022-02-02 01:53:03 +04:00
parent 038fbd0f9f
commit 75a2dff92d
2 changed files with 66 additions and 42 deletions

View File

@ -14,7 +14,7 @@ This project is currently very WIP, the todo list is:
- [ ] Task lists as calendar tags (maybe?) - [ ] Task lists as calendar tags (maybe?)
- [ ] Creating, modifying, removing, completing tasks - [ ] Creating, modifying, removing, completing tasks
- [ ] Offline caching - [ ] Offline caching
- [ ] JSON export - [x] JSON export
# Dependencies # Dependencies
``` ```

96
decal
View File

@ -1,6 +1,8 @@
#!/usr/bin/python #!/usr/bin/python
# if you're reading the source code for this (oof), feel free to suggest improvements for this, or, well, anything above or below this comment (as long as it's not just "rewrite this entire thing in C++ for me because i think python bad", "idk how but optimize stuff kthx". just don't be a dick, ok? thanks).
import configparser import configparser
import datetime import datetime
from datetime import date, timedelta
import calendar import calendar
import caldav import caldav
import argparse import argparse
@ -11,7 +13,7 @@ Version = "%(prog)s 0.1"
configpath = os.getenv("HOME")+"/.config/decal.conf" configpath = os.getenv("HOME")+"/.config/decal.conf"
config.read(configpath) config.read(configpath)
#define arguments #define arguments
today = datetime.date.today() today = date.today()
parser = argparse.ArgumentParser(description="Cal with events.") parser = argparse.ArgumentParser(description="Cal with events.")
parser.add_argument("year", parser.add_argument("year",
action="store", action="store",
@ -64,9 +66,7 @@ args = vars(parser.parse_args())
if args["create"]: if args["create"]:
print("Not implemented") print("Not implemented")
exit(0) exit(0)
if args["json"]:
print("Not implemented")
exit(0)
#check some stuff, do some warnings, initiate the config, etc. #check some stuff, do some warnings, initiate the config, etc.
if not os.path.exists(configpath): if not os.path.exists(configpath):
config['DEFAULT'] = {'uri': 'your caldav server here', config['DEFAULT'] = {'uri': 'your caldav server here',
@ -97,9 +97,9 @@ def gencal(year,month,firstweekday=6,cell_modifier=lambda d: d,append_year=True)
lines = [""]*6 lines = [""]*6
monthstart = False monthstart = False
counter = 0 counter = 0
for date in cal.itermonthdates(year,month): for curdate in cal.itermonthdates(year,month):
lines[counter//7] lines[counter//7]
day = str(date)[-2:] day = str(curdate)[-2:]
if day == "01": if day == "01":
monthstart = not monthstart monthstart = not monthstart
if monthstart: if monthstart:
@ -112,7 +112,7 @@ def gencal(year,month,firstweekday=6,cell_modifier=lambda d: d,append_year=True)
for times in range(firstweekday): for times in range(firstweekday):
weeklines.append(weeklines.pop(0)) weeklines.append(weeklines.pop(0))
lines.insert(0," ".join(weeklines)+" ") lines.insert(0," ".join(weeklines)+" ")
lines.insert(0,datetime.date(year,month,1).strftime("%B %Y").center(21)) lines.insert(0,date(year,month,1).strftime("%B %Y").center(21))
lines[-1] += " "*(21-len(lines[-1])) lines[-1] += " "*(21-len(lines[-1]))
return lines return lines
@ -152,12 +152,12 @@ def span(year,month,offset):
#get 2 date values - start value to scan from and end value to scan up to. #get 2 date values - start value to scan from and end value to scan up to.
def getbounds(y,m,offset): def getbounds(y,m,offset):
start = datetime.date(y,m,1) start = date(y,m,1)
postnextmonth = span(y,m,offset) postnextmonth = span(y,m,offset)
nextmonth = span(postnextmonth[0],postnextmonth[1],-1) nextmonth = span(postnextmonth[0],postnextmonth[1],-1)
end = datetime.date(nextmonth[0], end = date(nextmonth[0],
nextmonth[1], nextmonth[1],
(datetime.date(postnextmonth[0],postnextmonth[1],1)-datetime.timedelta(days=1)).day) (date(postnextmonth[0],postnextmonth[1],1)-timedelta(days=1)).day)
return start,end return start,end
# generator for year/month pairs # generator for year/month pairs
@ -194,49 +194,73 @@ principal = client.principal()
calendars = principal.calendars() calendars = principal.calendars()
# aggregate selected calendars # aggregate selected calendars
if "calendars" in config['DEFAULT']: def aggregateCalendars(calendars):
calendars2 = [] calendars2 = []
cals = config['DEFAULT']["calendars"].split(",") cals = config['DEFAULT']["calendars"].split(",")
for cal in calendars: for cal in calendars:
if cal.name in cal: if cal.name in cal:
calendars2.append(cal) calendars2.append(cal)
calendars = calendars2 return calendars2
# hooo boy, fun things start here. if "calendars" in config['DEFAULT']:
# we generate a dict of (year,month) pairs for easier indexing calendars = aggregateCalendars(calendars)
events = {}
for ympair in ympairs((args['year'],args['month']),offset,dstart=args['3']):
events[ympair] = {} def daysOfEvent(event):
# next, we iterate over events in each calendar, sorting them the folliwng way:
# events[(int year,int month)][int day] = [event event1, event event2, ...]
# looks awful, is awful, overall i love this.
for cal in calendars:
events_fetched = cal.date_search(start,end)
for event in events_fetched:
event = event.vobject_instance.vevent.contents event = event.vobject_instance.vevent.contents
curdate = event["dtstart"][0].value curdate = event["dtstart"][0].value
enddate = event["dtend"][0].value enddate = event["dtend"][0].value
while curdate <= enddate: while curdate <= enddate:
curdindex = (curdate.year,curdate.month) if type(curdate) == datetime.datetime:
if curdindex in events: yield str(curdate.date())
if not curdate.day in events[curdindex]: else:
events[curdindex][curdate.day] = [] yield str(curdate)
events[curdindex][curdate.day].append(event) curdate += timedelta(days=1)
curdate += datetime.timedelta(days=1) return
# if you're reading the source code for this (oof), feel free to suggest improvements for this, or, well, anything above or below this comment (as long as it's not just "rewrite this entire thing in C++ for me because i think python bad", "idk how but optimize stuff kthx". just don't be a dick, ok? thanks).
def jsonifyEvent(event):
event = event.vobject_instance.vevent.contents
evdata = {
"uid": event["uid"][0].value,
"dtstart": str(event["dtstart"][0].value),
"dtend": str(event["dtend"][0].value)
}
# may or may not be there, idk why. vobject format is really weird
for key in ["summary","description","status"]:
if key in event:
evdata[key] = event[key][0].value
return evdata
def generateDateTree(calendars):
events = {}
for cal in calendars:
events_fetched = cal.date_search(start,end)
for event in events_fetched:
for date in daysOfEvent(event):
if not date in events:
events[date] = []
events[date].append(jsonifyEvent(event))
return events
events = generateDateTree(calendars)
if args["json"]:
print(json.JSONEncoder().encode(events))
exit(0)
# and now we're just generating calendar lines # and now we're just generating calendar lines
cal_prints = [] cal_prints = []
selected_date = datetime.date(args['year'],args['month'],args['day']) selected_date = date(args['year'],args['month'],args['day'])
for year,month in ympairs((args['year'],args['month']),offset,dstart=args['3']): for year,month in ympairs((args['year'],args['month']),offset,dstart=args['3']):
# a function to colorize cells in a more or less generic way # a function to colorize cells in a more or less generic way
def lambdafunc(cell): def lambdafunc(cell):
day = int(cell) day = date(year,month,int(cell))
if day in events[(year,month)]: if str(day) in events:
event = events[(year,month)][day] event = events[str(day)]
uid = event[0]["uid"][0].value.encode() uid = event[0]["uid"].encode()
cell = colorize(cell,uid) cell = colorize(cell,uid)
if datetime.date(year,month,day) == selected_date: if day == selected_date:
cell = colorize(cell,"inverse") cell = colorize(cell,"inverse")
return cell return cell
cal_prints.append(gencal(year, cal_prints.append(gencal(year,