1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
import os
import json
import datetime
import dataclasses
import logging
logger = logging.getLogger(__name__) # Set the logger name, to the name of the module
@dataclasses.dataclass
class Event:
title: str = None
short: str = None
spacer: str = ''
room: str = None
day: str = None
start_date: datetime.datetime = None
end_date: datetime.datetime = None
icon: str = '?'
time: str = None
duration: datetime.timedelta = None
pretty: str = None
progress: float = 0
classes: list[str] = dataclasses.field(default_factory=list)
specials = { # Special programs get an easter with a css class
'rainbow': [ 'hello world', 'hacker jeopardy', 'goodbye world' ],
'radio': ['radio'],
'egg': ['æg'],
'ctf': ['ctf'],
}
class ProgramParser:
'''
Parse the JSON program into dataformat for easy processing
'''
def __init__(self, program_path:os.PathLike=None, override_date:datetime.datetime|None=None):
self.program_path = program_path
self.override_date = override_date
self.icons = {
'Startent at Info Desk' : "⭐",
'Speakers Tent': "🏕",
'Workshop Room': "🛠️",
'Bar Meetup Area': "🍺",
'Bar Area': "🍺",
'External': "🚗",
'Pyjam.as Village in Party Area': "🐍",
'Workshop Room (possibly outside of it)': "🛠️(🏞️)",
'Workshop Room (sofa area)': "🛠️(🛋️)",
'NWWC Village in Party Area': "🔊",
'Wellness area': "🛀",
'Online': "🌐",
'Cabin fireplace': "🔥(🏚️)",
'Cabin Fireplace': "🔥(🏚️)",
'Main camping fireplace': "🔥(🏞️)",
}
def get_program(self) -> list[Event]:
program: list[Event] = []
# Parse program into data format (interpret datetime, and such)
with open(self.program_path, "r") as json_file:
program_raw = json.load(json_file)
for event_raw in program_raw:
event = Event()
#print(event_raw["title"])
for d in ["title", "room"]: # 1 to 1 mapping
setattr(event, d, event_raw[d])
event.start_date = datetime.datetime.strptime(event_raw["date"], "%Y-%m-%dT%H:%M:%S+00:00")
event.start_date += datetime.timedelta(hours=2) # Hvad er vinter tid?
end_bogus = datetime.datetime.strptime(event_raw["duration"],"%H:%M:%S")
event.duration = datetime.timedelta(
hours=end_bogus.hour, minutes=end_bogus.minute, seconds=end_bogus.second)
event.end_date = event.start_date + event.duration
#print('Start date: ', event["start_date"])
#print("End date: ", event["end_date"])
#print()
# css classes
for css_class, titles in specials.items():
for title in titles:
if title in event.title.lower():
event.classes.append(css_class)
program.append(event)
program = sorted(program, key=lambda x: x.start_date)
return program
def get_events_to_show(self, program: list[Event], lines=1000,title_max_length:int=34) -> list[Event]:
current_datetime = datetime.datetime.now() if not self.override_date else self.override_date
#current_datetime = datetime.datetime(year=2025, month=7, day=18, hour=15, minute=30) # DEBUG
# Get events to show
events_to_show = []
for event in program:
if len(events_to_show) >= lines:
break
if event.end_date > current_datetime:
events_to_show.append(event)
def format_program(event: Event) -> str:
if len(event.title) > title_max_length:
# Truncate title by deleting was 1-3 chars and putting ...
event.short = f'{event.title[:title_max_length - 3]}...'
else:
event.short = event.title
event.spacer = "." * (title_max_length - len(event.title)) # Pad title
event.day = event.start_date.strftime('%a')
start_time = event.start_date.strftime('%H:%M')
end_time = event.end_date.strftime('%H:%M')
event.icon = self.icons.get(event.room)
if event.icon == None:
event.icon = '?'
logger.warning(f"NEW ICON NEEDED!!! for {event.room}")
event.time = f"{start_time}-{end_time}"
return f"{event.short}{event.spacer} {event.day} {start_time}-{end_time} {event.icon}"
for event_to_show in events_to_show:
event_to_show.pretty = format_program(event_to_show)
# Get progress
duration_sec = (event_to_show.end_date - event_to_show.start_date).total_seconds()
progress_sec = (current_datetime - event_to_show.end_date).total_seconds()
progress = 100 + (progress_sec / duration_sec) * 100
if progress > 0:
event_to_show.progress = progress
return events_to_show
def program_parser_factory():
program_path = os.environ["PROGRAM_PATH"] if "PROGRAM_PATH" in os.environ else os.path.join(os.getcwd(),'programs', 'current.json')
override_date = datetime.datetime.fromisoformat(os.environ["OVERRIDE_DATE"]) if "OVERRIDE_DATE" in os.environ else None
return ProgramParser(program_path=program_path, override_date=override_date)
|