diff options
| author | user <user@node5.net> | 2024-07-19 23:32:40 +0200 |
|---|---|---|
| committer | user <user@node5.net> | 2024-07-19 23:32:40 +0200 |
| commit | 78e3f6ea427a10edaeac1c056f8a3ab5640e2a0c (patch) | |
| tree | 0bd7a010f00fb07c15577e7fea9fb2128239b82f /src | |
Initial commit - displays events
Diffstat (limited to 'src')
| -rw-r--r-- | src/app.py | 69 | ||||
| -rwxr-xr-x | src/program_parser.py | 104 | ||||
| -rw-r--r-- | src/static/favicon.ico | bin | 0 -> 15406 bytes | |||
| -rw-r--r-- | src/static/main.css | 72 | ||||
| -rw-r--r-- | src/static/main.js | 31 | ||||
| -rw-r--r-- | src/static/news_headline.png | bin | 0 -> 2597 bytes | |||
| -rw-r--r-- | src/static/title_headline.png | bin | 0 -> 2255 bytes | |||
| -rw-r--r-- | src/templates/base.html | 24 | ||||
| -rw-r--r-- | src/templates/event.html | 1 | ||||
| -rw-r--r-- | src/templates/index.html | 24 |
10 files changed, 325 insertions, 0 deletions
diff --git a/src/app.py b/src/app.py new file mode 100644 index 0000000..b063bec --- /dev/null +++ b/src/app.py @@ -0,0 +1,69 @@ +import logging +import os +import datetime + +import flask +import yaml + +import program_parser + +#import db_handler + +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) + +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.program, programs_to_show_count = 16) + #{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()) + diff --git a/src/program_parser.py b/src/program_parser.py new file mode 100755 index 0000000..59f1159 --- /dev/null +++ b/src/program_parser.py @@ -0,0 +1,104 @@ +#!/run/current-system/sw/bin/python +import os +import json +import datetime +import copy +import dataclasses + +input_file_path = '../../content/program.json' +tmp_file_path = '/tmp/teletext/bh_events_to_show_TMP' +output_file_path = '/tmp/teletext/bh_events_to_show' + +title_max_length = 30 +#current_date = datetime.datetime(year=2024, month=7, day=18, hour=14, minute=59) # DEBUG + +@dataclasses.dataclass +class Event: + title: str = None + 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: int = None + +icons = { + 'Startent at Info Desk' : "⭐", + 'Speakers Tent': "🏕", + 'Workshop Room': "🛠️", + 'Bar Meetup Area': "🍺", + 'Bar Area': "🍺", + 'External': "🚗", + 'Pyjam.as Village in Party Area': "🐍" +} + + +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) + + 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_date = datetime.datetime.now() + # 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_date: + 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[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 = (datetime.datetime.now() - event_to_show.end_date).total_seconds() + event_to_show.progress = 100 + (progress_sec / duration_sec) * 100 + + return events_to_show + +program: list[Event] = get_program() +events_to_show: list[Event] = get_events_to_show(program) + +# 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/favicon.ico b/src/static/favicon.ico Binary files differnew file mode 100644 index 0000000..653155d --- /dev/null +++ b/src/static/favicon.ico diff --git a/src/static/main.css b/src/static/main.css new file mode 100644 index 0000000..e4d5aef --- /dev/null +++ b/src/static/main.css @@ -0,0 +1,72 @@ +body { + color: white; + background: black; + image-rendering: pixelated; + zoom: 2; +} + +#root-container { + margin: auto; + text-align: center; + width: min-content; +} + +.content { + margin-top: 0.1em; +} + +#top { + font-size: 1.36em; + color: grey; +} + +#program { + font-size: 1.64em; +} + +#news { + font-size: 1.36em; + text-align: left; +} + +.grey { + color: grey !important; +} + +input { + width: 80%; + height: 200%; + font-size: 1em; +} + +#news_input_label { + font-size: 0.7em; +} + +input[type=submit] { + width: fit-content; +} + + +progress { + -webkit-appearance: none; + background: #000; + border: none; + width: 93%; +} + +progress::-moz-progress-bar { background: #006688; } + +#progress-bar span { + position: absolute; + display: inline-block; + color: #fff; + text-align: right; +} + +#progress-bar { + display: block; + position: relative; + width: 100%; +} + diff --git a/src/static/main.js b/src/static/main.js new file mode 100644 index 0000000..7bea389 --- /dev/null +++ b/src/static/main.js @@ -0,0 +1,31 @@ +const url = '/text'; +const parts = ["top", "program"]; +const elements = {}; + +function get_element(part){ + elements[part] = document.getElementById(part); +} + +const program_element = parts.forEach(get_element); + +function set_element_text(part, text){ + elements[part].innerHTML = text; +} + +async function getEvents() { + try { + const response = await fetch(url); + if (!response.ok) { + throw new Error(`Response status: ${response.status}`); + } + + const events = await response.json(); + console.log(events) + + } catch (error) { + console.error(error.message); + } +} + +getEvents(); + diff --git a/src/static/news_headline.png b/src/static/news_headline.png Binary files differnew file mode 100644 index 0000000..f9876a1 --- /dev/null +++ b/src/static/news_headline.png diff --git a/src/static/title_headline.png b/src/static/title_headline.png Binary files differnew file mode 100644 index 0000000..dec80be --- /dev/null +++ b/src/static/title_headline.png diff --git a/src/templates/base.html b/src/templates/base.html new file mode 100644 index 0000000..ac28685 --- /dev/null +++ b/src/templates/base.html @@ -0,0 +1,24 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + {% block head %} + <link rel="stylesheet" href="/main.css"/> + <title>Text TV - Bornhack 24</title> + <link rel="icon" type="image/x-icon" href="favicon.ico"> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <script src="main.js" defer></script> + {% endblock %} + <meta http-equiv="refresh" content="10"> +</head> +<body> + + <div id="root-container"> + + {% block content %} + {% endblock %} + + <div> + +</body> +</html> diff --git a/src/templates/event.html b/src/templates/event.html new file mode 100644 index 0000000..efe4cba --- /dev/null +++ b/src/templates/event.html @@ -0,0 +1 @@ +<div id="progress-bar"><span data-value="60" style="width: 60%;">{{event.title}} {{event.day}} {{ event.time}} {{ event.icon }}</span><progress value="{{event.progress}}" max="100"></progress></div> diff --git a/src/templates/index.html b/src/templates/index.html new file mode 100644 index 0000000..6e94876 --- /dev/null +++ b/src/templates/index.html @@ -0,0 +1,24 @@ +{% extends "base.html" %} + +{% block content %} + + <pre class="content" id="top">{{parts.top}}</pre> + + <img src="title_headline.png"> + + <pre class="content" id="program">{% for event in parts.program %}{% include 'event.html' %}{% endfor %}</pre> +{# + <img src="news_headline.png"> + + <pre class="content" id="news">{{parts.news}}</pre> + --> + <br> +<!-- + <form> + <label id="news_input_label" for="news_input">Post your own news, or anything you'd like here:</label><br> + <input type="text" id="news_input" name="news_input" maxlength="{{ news_max_length }}" placeholder="Type text here"> + <input type="submit" value="Post" /> + </form> +#} + +{% endblock %} |
