summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/get_program_for_pixel_flut.py (renamed from src/app.py)46
-rw-r--r--src/logger.py36
-rwxr-xr-xsrc/program_parser.py157
-rw-r--r--src/static/title_headline.pngbin12481 -> 2302 bytes
-rw-r--r--src/text_tv_bornhack.py47
5 files changed, 172 insertions, 114 deletions
diff --git a/src/app.py b/src/get_program_for_pixel_flut.py
index 977288b..5557184 100644
--- a/src/app.py
+++ b/src/get_program_for_pixel_flut.py
@@ -1,13 +1,8 @@
import logging
import os
-import datetime
-
-import flask
-import yaml
import program_parser
-
-#import db_handler
+from program_parser import Event
class CustomFormatter(logging.Formatter):
grey = "\x1b[90;20m"
@@ -41,29 +36,18 @@ stream_handler = logging.StreamHandler()
stream_handler.setFormatter(CustomFormatter())
logger.root.addHandler(stream_handler)
-app = flask.Flask(__name__, template_folder='templates', static_folder='static', static_url_path='')
-
-@app.route('/top')
-def top():
- return f'BornHack S105 {datetime.datetime.now().strftime("%a %d %b %R:%S")} '
-
-@app.route('/program.json')
-def program():
- events_to_show: list[Event] = program_parser.get_events_to_show(program_parser.get_program(), programs_to_show_count = 1000)
- #{event.title} {day} {start_time}-{end_time} {icon}
- json = [{'title': a.title, 'day': a.day, 'time': a.time, 'progress': a.progress, 'icon': a.icon} for a in events_to_show]
- return json
-'''
-@app.route('/news')
-def news():
- with open(news_file_path, "r") as news_file:
- return news_file.read().replace('\n', '<br>')
-'''
-@app.route('/text')
-def text() -> dict[str, str]:
- return {part: eval(part)() for part in ['top', 'program']}
-
-@app.route('/')
-def index():
- return flask.render_template('index.html', parts=text())
+events_to_show: list[Event] = program_parser.get_events_to_show(program_parser.get_program(), programs_to_show_count = 1000)
+#{event.title} {day} {start_time}-{end_time} {icon}
+programs_formatted_list = []
+last_event = None
+for event in events_to_show:
+ programs_formatted_list.append(f"{event.title} {event.time} {event.icon} {event.progress if event.progress > 0 else ''}")
+ if last_event and last_event.day != event.day:
+ # Day change
+ programs_formatted_list.append(f'\n\n{event.day}\n')
+ last_event = event
+
+program_formatted = '\n'.join([f"" for a in events_to_show ])
+program_formatted = '\n'.join(programs_formatted_list)
+print(program_formatted)
diff --git a/src/logger.py b/src/logger.py
new file mode 100644
index 0000000..aaa1441
--- /dev/null
+++ b/src/logger.py
@@ -0,0 +1,36 @@
+import logging
+import os
+
+
+class CustomFormatter(logging.Formatter):
+ grey = "\x1b[90;20m"
+ blue = "\x1b[34;20m"
+ yellow = "\x1b[33;20m"
+ red = "\x1b[31;20m"
+ bold_red = "\x1b[31;1m"
+ reset = "\x1b[0m"
+ format = "%(asctime)s,%(msecs)03d %(levelname)-8s [%(filename)s:%(lineno)d] %(message)s"
+
+ FORMATS = {
+ logging.DEBUG: grey + format + reset,
+ logging.INFO: blue + format + reset,
+ logging.WARNING: yellow + format + reset,
+ logging.ERROR: red + format + reset,
+ logging.CRITICAL: bold_red + format + reset
+ }
+
+ def format(self, record):
+ log_fmt = self.FORMATS.get(record.levelno)
+ formatter = logging.Formatter(log_fmt)
+ return formatter.format(record)
+
+logger = logging.getLogger(__name__)
+if os.environ.get('FLASK_DEBUG') == '1': # Local development
+ logger.root.setLevel(logging.DEBUG)
+else: # Production
+ logger.root.setLevel(logging.INFO)
+
+stream_handler = logging.StreamHandler()
+stream_handler.setFormatter(CustomFormatter())
+logger.root.addHandler(stream_handler)
+
diff --git a/src/program_parser.py b/src/program_parser.py
index 67103b1..66c0858 100755
--- a/src/program_parser.py
+++ b/src/program_parser.py
@@ -1,13 +1,10 @@
-#!/run/current-system/sw/bin/python
import os
import json
import datetime
-import copy
import dataclasses
+import logging
-input_file_path = './program.json'
-
-title_max_length = 34
+logger = logging.getLogger(__name__) # Set the logger name, to the name of the module
@dataclasses.dataclass
class Event:
@@ -22,89 +19,83 @@ class Event:
pretty: str = None
progress: int = None
-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': "🌐",
-}
+class ProgramParser:
+ def __init__(self, program_path:os.PathLike, title_max_length:int=34, override_date:datetime.datetime|None=None):
+ self.program_path = program_path
+ self.title_max_length = title_max_length
+ 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': "🌐",
+ }
-def get_program() -> list[Event]:
- program: list[Event] = []
- # Parse program into data format (interpret datetime, and such)
- with open(input_file_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()
- program.append(event)
+ 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()
+ program.append(event)
- program = sorted(program, key=lambda x: x.start_date)
- return program
+ program = sorted(program, key=lambda x: x.start_date)
+ return program
-def get_events_to_show(program: list[Event], programs_to_show_count=4) -> list[Event]:
- current_datetime = datetime.datetime.now()
- #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) >= programs_to_show_count:
- break
- if event.end_date > current_datetime:
- events_to_show.append(event)
+ def get_events_to_show(self, program: list[Event], programs_to_show_count=4) -> 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) >= programs_to_show_count:
+ break
+ if event.end_date > current_datetime:
+ events_to_show.append(event)
- def format_program(event: Event, cli=False) -> str:
- if len(event.title) > title_max_length:
- event.title = f'{event.title[:title_max_length - 3]}...' # Truncate title by deleting was 1-3 chars and putting ...
- else:
- event.title += " " * (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 = icons.get(event.room)
- if event.icon == None:
- event.icon = '?'
- print(f"NEW ICON NEEDED!!! for {event.room}")
- event.time = f"{start_time}-{end_time}"
- return f"{event.title} {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)
- 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()
- event_to_show.progress = 100 + (progress_sec / duration_sec) * 100
+ def format_program(event: Event, cli=False) -> str:
+ if len(event.title) > self.title_max_length:
+ # Truncate title by deleting was 1-3 chars and putting ...
+ event.title = f'{event.title[:self.title_max_length - 3]}...'
+ else:
+ event.title += " " * (self.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.title} {event.day} {start_time}-{end_time} {event.icon}"
- return events_to_show
+ for event_to_show in events_to_show:
+ event_to_show.pretty = format_program(event_to_show)
+ 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()
+ event_to_show.progress = 100 + (progress_sec / duration_sec) * 100
-program: list[Event] = get_program()
-events_to_show: list[Event] = get_events_to_show(program)
+ return events_to_show
-'''
-# Convert to the output string
-events_to_show_string = '\n'.join([a.pretty for a in events_to_show])
-print(f"{events_to_show_string}\n")
-# Write to output file
-with open(tmp_file_path, 'w') as tmp_file:
- tmp_file.write(events_to_show_string)
-os.rename(tmp_file_path, output_file_path)
-print(f'Written to {output_file_path} length: {len(events_to_show_string)}')
-'''
diff --git a/src/static/title_headline.png b/src/static/title_headline.png
index e53e0cf..a6aada9 100644
--- a/src/static/title_headline.png
+++ b/src/static/title_headline.png
Binary files differ
diff --git a/src/text_tv_bornhack.py b/src/text_tv_bornhack.py
new file mode 100644
index 0000000..9514da2
--- /dev/null
+++ b/src/text_tv_bornhack.py
@@ -0,0 +1,47 @@
+import datetime
+import os
+
+import flask
+
+from program_parser import ProgramParser
+
+
+app = flask.Flask(__name__, template_folder='templates', static_folder='static', static_url_path='')
+
+program_path = os.environ["PROGRAM_PATH"] if "PROGRAM_PATH" in os.environ else './programs/current.json'
+override_date = datetime.datetime.fromisoformat(os.environ["OVERRIDE_DATE"]) if "OVERRIDE_DATE" in os.environ else None
+program_parser = ProgramParser(program_path=program_path, override_date=override_date)
+debug = 'PROD' not in os.environ
+
+
+@app.route('/top')
+def top():
+ now = datetime.datetime.now() if not override_date else override_date
+ return f'BornHack S105 {now.strftime("%a %d %b %R:%S")} '
+
+
+@app.route('/program.json')
+def program():
+ events_to_show: list[Event] = program_parser.get_events_to_show(program_parser.get_program(), programs_to_show_count = 1000)
+ #{event.title} {day} {start_time}-{end_time} {icon}
+ json = [{'title': a.title, 'day': a.day, 'time': a.time, 'progress': a.progress, 'icon': a.icon} for a in events_to_show]
+ return json
+
+
+@app.route('/text')
+def text() -> dict[str, str]:
+ return {part: eval(part)() for part in ['top', 'program']}
+
+
+@app.route('/')
+def index():
+ return flask.render_template('index.html', parts=text())
+
+
+def main():
+ global app
+ app.run(debug=debug)
+
+
+if __name__ == '__main__':
+ main()