rename files, generate SVG page without XML
This commit is contained in:
parent
63f3c9d3ae
commit
725198e4c9
|
@ -0,0 +1,62 @@
|
||||||
|
from json import loads
|
||||||
|
from datetime import datetime
|
||||||
|
from re import compile
|
||||||
|
|
||||||
|
# scale down coordinates to dx=1 per day to prevent SVG coordinate overflows
|
||||||
|
scale = 1/60/60/24
|
||||||
|
|
||||||
|
def get_date(dtime):
|
||||||
|
return datetime.fromtimestamp(dtime).strftime('%Y-%m-%d %H:%M')
|
||||||
|
|
||||||
|
def make_line(event):
|
||||||
|
evstart = event['period'][0]
|
||||||
|
evstop = event['period'][1]
|
||||||
|
return '<line{type} x1="{start}" x2="{stop}" y1="{height}" y2="{height}"><title>{text} ({start_date} — {stop_date})</title></line>'.format(
|
||||||
|
type = '' if event['status'] == 'online' else ' class="error"',
|
||||||
|
start = scale*evstart,
|
||||||
|
stop = scale*evstop,
|
||||||
|
start_date = get_date(evstart),
|
||||||
|
stop_date = get_date(evstop),
|
||||||
|
height = len(event['players']) if 'players' in event else 0,
|
||||||
|
text = ('no one' if len(event['players']) == 0 else ', '.join(event['players'])) if event['status'] == 'online' else event['status']
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_lines(start,stop):
|
||||||
|
lines = []
|
||||||
|
find_start = compile(r'x1="([0-9.]+)"')
|
||||||
|
find_stop = compile(r'x2="([0-9.]+)"')
|
||||||
|
with open('events.log', 'r') as fin:
|
||||||
|
for l in fin:
|
||||||
|
evstart = float(find_start.search(l).group(1))
|
||||||
|
evstop = float(find_stop.search(l).group(1))
|
||||||
|
|
||||||
|
if evstop > start and evstart < stop:
|
||||||
|
lines.append(l)
|
||||||
|
with open('current-state.json', 'r') as fin:
|
||||||
|
lines.append(make_line(loads(fin.read())))
|
||||||
|
|
||||||
|
return lines
|
||||||
|
|
||||||
|
def make_html(name,period):
|
||||||
|
stop = scale*datetime.now().timestamp()
|
||||||
|
start = stop-period
|
||||||
|
lines = get_lines(start, stop)
|
||||||
|
display_scale = 24*60/10 # 1 pixel per 10 minutes
|
||||||
|
with open('template.html', 'r') as fin:
|
||||||
|
with open(name+'.html', 'w') as fout:
|
||||||
|
fout.write(fin.read().format(
|
||||||
|
outer_width = display_scale*period+10,
|
||||||
|
inner_width = display_scale*period,
|
||||||
|
start = start,
|
||||||
|
period = period,
|
||||||
|
day_start = scale*datetime.fromtimestamp(start/scale).replace(hour=0,minute=0,second=0,microsecond=0).timestamp(),
|
||||||
|
day_stop = stop,
|
||||||
|
events = ''.join(lines)
|
||||||
|
))
|
||||||
|
|
||||||
|
def make_htmls():
|
||||||
|
make_html('day', 1)
|
||||||
|
make_html('month', 31)
|
||||||
|
make_html('4months', 120)
|
||||||
|
|
||||||
|
make_htmls()
|
|
@ -1,82 +0,0 @@
|
||||||
from json import loads
|
|
||||||
from xml.etree.ElementTree import Element, tostring
|
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
def readEvents():
|
|
||||||
events = []
|
|
||||||
with open('events.json', 'r') as f:
|
|
||||||
for line in f:
|
|
||||||
events.append(loads(line))
|
|
||||||
|
|
||||||
with open('current-state.json', 'r') as f:
|
|
||||||
events.append(loads(f.read()))
|
|
||||||
|
|
||||||
return events
|
|
||||||
|
|
||||||
def getSVG(events):
|
|
||||||
scale = 1/60/60/24
|
|
||||||
period = 3*30 *60*60*24
|
|
||||||
end = datetime.now().timestamp()
|
|
||||||
start = end-period
|
|
||||||
# start = events[0]['period'][0]
|
|
||||||
# end = events[-1]['period'][1]
|
|
||||||
root = Element('svg', {
|
|
||||||
'version': '1.1',
|
|
||||||
'xmlns': 'http://www.w3.org/2000/svg',
|
|
||||||
'viewBox': '0 0 {} 200'.format(scale*period*200),
|
|
||||||
'width': str(scale*period*200),
|
|
||||||
'height': '200',
|
|
||||||
})
|
|
||||||
group = Element('svg', {
|
|
||||||
'viewBox': '{} 0 {} 10'.format(scale*start,scale*period),
|
|
||||||
'width': '100%',
|
|
||||||
'height': '100%',
|
|
||||||
'preserveAspectRatio': 'none'
|
|
||||||
})
|
|
||||||
|
|
||||||
for i in range(0,10+1):
|
|
||||||
num = Element('text', {
|
|
||||||
'x': str(scale*period*200-20),
|
|
||||||
'y': str((1-i/10)*200)
|
|
||||||
})
|
|
||||||
num.text = str(i)
|
|
||||||
root.append(num)
|
|
||||||
root.append(group)
|
|
||||||
|
|
||||||
for event in events:
|
|
||||||
evstart = event['period'][0]
|
|
||||||
evend = event['period'][1]
|
|
||||||
|
|
||||||
if evend < start or evstart > end:
|
|
||||||
continue
|
|
||||||
|
|
||||||
props = { 'x1': str(scale*evstart), 'x2': str(scale*evend), 'y1': '0', 'y2': '0' }
|
|
||||||
titletext = 'unknown'
|
|
||||||
|
|
||||||
if 'players' in event:
|
|
||||||
y = str(len(event['players']))
|
|
||||||
props['y1'] = y
|
|
||||||
props['y2'] = y
|
|
||||||
if len(event['players']) == 0:
|
|
||||||
titletext = '(no one)'
|
|
||||||
else:
|
|
||||||
titletext = ', '.join(event['players'])
|
|
||||||
|
|
||||||
if event['type'] == 'error':
|
|
||||||
props['class'] = 'error'
|
|
||||||
titletext = 'error'
|
|
||||||
|
|
||||||
ev = Element('line', props)
|
|
||||||
title = Element('title')
|
|
||||||
title.text = '{} ({} — {})'.format(titletext, datetime.fromtimestamp(evstart).strftime('%Y-%m-%d %H:%M'), datetime.fromtimestamp(evend).strftime('%Y-%m-%d %H:%M'))
|
|
||||||
ev.append(title)
|
|
||||||
group.append(ev)
|
|
||||||
|
|
||||||
return root
|
|
||||||
|
|
||||||
def dumpHTML(arg):
|
|
||||||
with open('index.html', 'r') as f:
|
|
||||||
html = f.read()
|
|
||||||
print( html.format(arg) )
|
|
||||||
|
|
||||||
dumpHTML(tostring(getSVG(readEvents()), encoding='unicode'))
|
|
11
index.html
11
index.html
|
@ -1,11 +0,0 @@
|
||||||
<!doctype html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset='utf-8'>
|
|
||||||
<link rel='stylesheet' href='style.css'>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
{}
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
73
parse.py
73
parse.py
|
@ -1,73 +0,0 @@
|
||||||
from json import loads, dumps
|
|
||||||
|
|
||||||
events = []
|
|
||||||
|
|
||||||
def doOffline(state, cur_t, cur_ps):
|
|
||||||
(last_t, last_ev, last_evt, last_ps) = state
|
|
||||||
working = (cur_t - last_t < 70)
|
|
||||||
|
|
||||||
if not working and last_ev == 'online':
|
|
||||||
events.append({'period': [last_evt, last_t], 'type': 'players', 'players': last_ps})
|
|
||||||
return (cur_t, 'error', last_t, cur_ps)
|
|
||||||
else:
|
|
||||||
return state
|
|
||||||
|
|
||||||
|
|
||||||
def doBackOnline(state, cur_t, cur_ps):
|
|
||||||
(last_t, last_ev, last_evt, last_ps) = state
|
|
||||||
working = (cur_t - last_t < 70)
|
|
||||||
|
|
||||||
if working and last_ev != 'online':
|
|
||||||
events.append({'period': [last_evt, cur_t], 'type': 'error'})
|
|
||||||
return (cur_t, 'online', last_t, last_ps)
|
|
||||||
else:
|
|
||||||
return state
|
|
||||||
|
|
||||||
|
|
||||||
def doPlayerChange(state, cur_t, cur_ps):
|
|
||||||
(last_t, last_ev, last_evt, last_ps) = state
|
|
||||||
working = (cur_t - last_t < 70)
|
|
||||||
|
|
||||||
if working and last_ps != cur_ps:
|
|
||||||
events.append({'period': [last_evt, cur_t], 'type': 'players', 'players': last_ps})
|
|
||||||
return (cur_t, 'online', cur_t, cur_ps)
|
|
||||||
else:
|
|
||||||
return state
|
|
||||||
|
|
||||||
|
|
||||||
def doUpdateTime(state, cur_t, cur_ps):
|
|
||||||
(last_t, last_ev, last_evt, last_ps) = state
|
|
||||||
return (cur_t, last_ev, last_evt, last_ps)
|
|
||||||
|
|
||||||
|
|
||||||
def doCurrent(state):
|
|
||||||
(last_t, last_ev, last_evt, last_ps) = state
|
|
||||||
events.append({'period': [last_evt, last_t], 'type': 'current', 'players': last_ps})
|
|
||||||
|
|
||||||
|
|
||||||
with open('all-time.txt') as f:
|
|
||||||
state = ()
|
|
||||||
cur_t = 0
|
|
||||||
cur_ps = []
|
|
||||||
|
|
||||||
for line in f:
|
|
||||||
current = loads(line)
|
|
||||||
cur_t = current['time']
|
|
||||||
cur_ps = current['players']
|
|
||||||
|
|
||||||
if state == ():
|
|
||||||
state = (cur_t, 'online', cur_t, cur_ps)
|
|
||||||
else:
|
|
||||||
state = doOffline(state, cur_t, cur_ps)
|
|
||||||
state = doBackOnline(state, cur_t, cur_ps)
|
|
||||||
state = doPlayerChange(state, cur_t, cur_ps)
|
|
||||||
state = doUpdateTime(state, cur_t, cur_ps)
|
|
||||||
|
|
||||||
doCurrent(state)
|
|
||||||
|
|
||||||
|
|
||||||
def dumpJSON(events):
|
|
||||||
for event in events:
|
|
||||||
print(dumps(event))
|
|
||||||
|
|
||||||
dumpJSON(events)
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset='utf-8'>
|
||||||
|
<!-- <meta http-equiv='refresh' content='29'> -->
|
||||||
|
<link rel='stylesheet' href='svg.css'>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav>
|
||||||
|
<a href="day.html">last 24 hours</a>
|
||||||
|
<a href="month.html">last month</a>
|
||||||
|
<a href="4months.html">last 4 months</a>
|
||||||
|
</nav>
|
||||||
|
<svg id='graph' height='200' width='{outer_width}' viewBox='0 10 {outer_width} 200' version='1.1' xmlns='http://www.w3.org/2000/svg'>
|
||||||
|
<text y='200'>0</text>
|
||||||
|
<text y='180'>1</text>
|
||||||
|
<text y='160'>2</text>
|
||||||
|
<text y='140'>3</text>
|
||||||
|
<text y='120'>4</text>
|
||||||
|
<text y='100'>5</text>
|
||||||
|
<text y= '80'>6</text>
|
||||||
|
<text y= '60'>7</text>
|
||||||
|
<text y= '40'>8</text>
|
||||||
|
<text y= '20'>9</text>
|
||||||
|
<svg id='events' x='10' y='-10' width='{inner_width}' height='100%' preserveAspectRatio='none' viewBox='{start} -0.5 {period} 10'>
|
||||||
|
<line id='days' x1='{day_start}' x2='{day_stop}'></line>
|
||||||
|
{events}
|
||||||
|
</svg>
|
||||||
|
</svg>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue