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