scheduled-plugin-pretalx-br.../service

260 lines
9.6 KiB
Python
Executable file

#!/usr/bin/python
import os
import sys
import time
import traceback
from calendar import timegm
from datetime import datetime, timedelta
import pytz
from requests import get
from hosted import config, node
config.restart_on_update()
SEND_PREFIX = os.environ["NODE"].replace("root/", "root/plugin/")
def log(msg):
sys.stderr.write("[pretalx] {}\n".format(msg))
def idle(seconds, event_start, event_end, event_tz, event_days):
end = time.time() + seconds
log("sleeping for {} seconds".format(seconds))
while time.time() < end:
send_data = {
"clock": "??",
"day": "??",
"time": int(time.time()),
}
if event_start is not None:
event_now = datetime.now(event_tz)
event_day = None
log("event_now = {}".format(event_now.isoformat()))
send_data["clock"] = event_now.strftime(config["clock_format"])
for day in event_days:
if day["starts"] <= event_now <= day["ends"]:
log("Today is day {} according to schedule".format(day["index"]))
event_day = day["index"]
if event_day is None:
log(
"Schedule does not contain information for this day, calculating using event start time"
)
utc_now = datetime.now(pytz.utc)
day_zero = event_tz.localize(
event_start.replace(hour=0, minute=0, second=0)
) - timedelta(days=1)
day_info = event_now - day_zero
log(
"Today is day {}, based on day zero at {}".format(
day_info.days, day_zero.isoformat()
)
)
event_day = day_info.days
send_data["day"] = event_day
# "single day" is only used in standalone mode to hide the
# the day information
if event_end is not None:
if event_start == event_end:
send_data["single_day"] = 1
else:
send_data["single_day"] = 0
for k, v in send_data.items():
node.send_raw("{}/{}:{}".format(SEND_PREFIX, k, v))
time.sleep(1)
def main():
event_info = None
event_start = None
event_end = None
schedule = None
event_tz = pytz.utc
while True:
schedule_url = config["schedule_url"]
room_uuid_mapping = {}
event_days = []
if "example.com" in schedule_url:
log("default schedule url, waiting for config update")
# sleep forever, service will get restarted if the config
# changes.
time.sleep(99999999)
log("event url: {}".format(schedule_url))
log("using json flavour: {}".format(config["json_flavour"]))
if config["json_flavour"] == "pretalx-broadcast-tools":
if not schedule_url.endswith("/"):
schedule_url = schedule_url + "/"
try:
r = get(
schedule_url + "p/broadcast-tools/event.json",
)
r.raise_for_status()
except Exception as e:
log("updating event info failed: {}".format(repr(e)))
# Only print the error message. If we have fetched the event
# info json blob atleast once, we have all the information
# we need.
else:
event_info = r.json()
if event_info is not None:
event_start = datetime.strptime(event_info["start"], "%Y-%m-%d")
event_end = datetime.strptime(event_info["end"], "%Y-%m-%d")
event_tz = pytz.timezone(event_info["timezone"])
for uuid, room_name in event_info.get("rooms", {}).items():
room_uuid_mapping[room_name] = uuid
try:
r = get(
schedule_url + "p/broadcast-tools/schedule.json",
)
r.raise_for_status()
except Exception as e:
log("updating schedule failed: {}".format(repr(e)))
# Only print the error message. If we have fetched the schedule
# info json blob atleast once, we have all the information
# we need.
else:
schedule = r.json()
tracks = {}
for talk in schedule["talks"]:
talk["start_str"] = (
datetime.fromtimestamp(talk["start_ts"])
.replace(tzinfo=pytz.utc)
.astimezone(event_tz)
.strftime("%H:%M")
)
talk["room_uuid"] = room_uuid_mapping.get("room")
if talk["track"]:
if talk["track"]["name"] not in tracks:
tracks[talk["track"]["name"]] = talk["track"]["color"]
schedule["tracks"] = []
for name, color in sorted(tracks.items()):
schedule["tracks"].append(
{
"name": name,
"color": color,
}
)
node.write_json("schedule.json", schedule)
log("updated schedule json")
elif config["json_flavour"] == "voc-schema":
try:
r = get(schedule_url)
r.raise_for_status()
except Exception as e:
log("getting schedule.json failed: {}".format(repr(e)))
else:
raw_schedule = r.json()["schedule"]
schedule = {
"tracks": raw_schedule["conference"]["tracks"],
"talks": [],
}
for room in raw_schedule["conference"]["rooms"]:
room_uuid_mapping[room["name"]] = room["guid"]
event_start = datetime.strptime(
raw_schedule["conference"]["start"][:10], "%Y-%m-%d"
)
event_end = datetime.strptime(
raw_schedule["conference"]["end"][:10], "%Y-%m-%d"
)
event_tz = pytz.timezone(raw_schedule["conference"]["time_zone_name"])
for day in raw_schedule["conference"]["days"]:
event_days.append(
{
"index": day["index"],
"starts": event_tz.localize(
datetime.strptime(
day["day_start"][:19], "%Y-%m-%dT%H:%M:%S"
)
),
"ends": event_tz.localize(
datetime.strptime(
day["day_end"][:19], "%Y-%m-%dT%H:%M:%S"
)
),
}
)
for room in day["rooms"].values():
for talk in room:
start = event_tz.localize(
datetime.strptime(
talk["date"][:19], "%Y-%m-%dT%H:%M:%S"
)
)
d_h, d_m = talk["duration"].split(":")
end = start + timedelta(hours=int(d_h), minutes=int(d_m))
talk["start_ts"] = int(
timegm(start.timetuple())
- start.utcoffset().total_seconds()
)
talk["start_str"] = talk["start"]
talk["end_ts"] = int(
timegm(end.timetuple())
- end.utcoffset().total_seconds()
)
talk["locale"] = talk["language"]
track = None
if talk["track"]:
for t in raw_schedule["conference"]["tracks"]:
if t["name"] == talk["track"]:
track = {
"color": t["color"],
"name": t["name"],
}
break
talk["track"] = track
talk["room_uuid"] = room_uuid_mapping.get(talk["room"])
persons = []
for p in talk["persons"]:
name = p.get("public_name", p.get("name"))
if name:
persons.append(name)
talk["persons"] = persons
schedule["talks"].append(talk)
node.write_json("schedule.json", schedule)
log("updated schedule json")
else:
log("unknown json flavour, something is very wrong")
uuid_json = {}
for name, uuid in room_uuid_mapping.items():
uuid_json[uuid] = name
node.write_json("uuid.json", uuid_json)
idle(30, event_start, event_end, event_tz, event_days)
if __name__ == "__main__":
try:
main()
except Exception:
traceback.print_exc()
try:
idle(30, None, None, None)
except Exception:
time.sleep(30)