|
|
#!/usr/bin/env python3
|
|
|
import pickle
|
|
|
from matplotlib import pyplot as plt
|
|
|
import requests
|
|
|
import json
|
|
|
from datetime import datetime
|
|
|
from dataclasses import dataclass
|
|
|
from collections import defaultdict
|
|
|
from time import sleep
|
|
|
from pathlib import Path
|
|
|
|
|
|
api_url = r'https://review.video.fosdem.org/api/v1/event/1/overview'
|
|
|
poll_rate = 10*60 # seconds
|
|
|
pickle_file = Path(r'./talk_data.pickle')
|
|
|
|
|
|
@dataclass
|
|
|
class TimeSeries:
|
|
|
"The object to pickle and unpickle"
|
|
|
states: set[str]
|
|
|
jobstates: set[str]
|
|
|
data: dict[datetime, tuple[dict[str, int], dict[str, int]]] # time → (states(name → count), jobstates(ditto))
|
|
|
|
|
|
def get_data() -> tuple[datetime, dict[str, int], dict[str, int]]:
|
|
|
resp = requests.get(api_url)
|
|
|
# TODO: error handling?
|
|
|
time = datetime.now().astimezone()
|
|
|
data = json.loads(resp.content.decode())
|
|
|
states = defaultdict(lambda: 0)
|
|
|
jobstates = defaultdict(lambda: 0)
|
|
|
# should be an array/list
|
|
|
for talk in data:
|
|
|
states[talk['state']] += 1
|
|
|
jobstates[talk['progress']] += 1
|
|
|
return time, states, jobstates
|
|
|
|
|
|
|
|
|
def main():
|
|
|
if pickle_file.exists():
|
|
|
with open(pickle_file, 'rb') as f:
|
|
|
ts = pickle.load(f)
|
|
|
else:
|
|
|
print("New time series.")
|
|
|
ts = TimeSeries(states=set(), jobstates=set(), data=dict())
|
|
|
|
|
|
while True:
|
|
|
time, states, jobstates = get_data()
|
|
|
assert time not in ts.data
|
|
|
ts.data[time] = (states, jobstates)
|
|
|
ts.states |= states.keys()
|
|
|
ts.jobstates |= jobstates.keys()
|
|
|
|
|
|
# Save the pickle
|
|
|
# Should probably save elsewhere and do atomic rename, but whatever.
|
|
|
with open(pickle_file, 'wb') as f:
|
|
|
pickle.dump(ts, f)
|
|
|
|
|
|
# Show the plot
|
|
|
x = sorted(ts.data.keys()) # times
|
|
|
# vvv should be a defaultdict anyway, but let's be defensive :-)
|
|
|
ys = [tuple(ts.data[time][0].get(state, 0) for state in ts.states) for time in x] # numbers per state
|
|
|
# We do not show jobstates atm. Too lazy.
|
|
|
# ys are transposed – we need vectors by times, not by states.
|
|
|
ys = list(zip(*ys))
|
|
|
plt.stackplot(x, *ys)
|
|
|
plt.show(block=False)
|
|
|
|
|
|
sleep(poll_rate)
|
|
|
plt.close()
|
|
|
plt.clf()
|
|
|
|
|
|
|
|
|
main()
|