TeamspeakStats/tsstats.py

203 lines
6.2 KiB
Python
Raw Normal View History

2015-03-05 12:48:10 -05:00
import re
import sys
2015-05-12 15:38:34 -04:00
import json
2015-03-05 12:48:10 -05:00
import configparser
from time import mktime
from os.path import exists
2015-03-05 12:48:10 -05:00
from datetime import datetime, timedelta
from jinja2 import Environment, FileSystemLoader
def exit(error):
print('FATAL ERROR:', error)
import sys
sys.exit(1)
2015-04-16 13:30:03 -04:00
# get path
arg = sys.argv[0]
arg_find = arg.rfind('/')
if arg_find == -1:
path = '.'
else:
path = arg[:arg_find]
path += '/'
config_path = path + 'config.ini'
id_map_path = path + 'id_map.json'
# exists config-file
if not exists(config_path):
exit('Couldn\'t find config-file at {}'.format(config_path))
2015-04-16 13:30:03 -04:00
# parse config
2015-03-05 12:48:10 -05:00
config = configparser.ConfigParser()
config.read(config_path)
2015-05-12 15:38:34 -04:00
# check keys
if 'General' not in config or 'HTML' not in config:
exit('Invalid config!')
2015-05-12 15:38:34 -04:00
general = config['General']
html = config['HTML']
if ('logfile' not in general or 'outputfile' not in general) or ('title' not in html):
exit('Invalid config!')
2015-05-12 15:38:34 -04:00
log_path = general['logfile']
if not exists(log_path):
exit('Couldn\'t access log-file!')
2015-05-12 15:38:34 -04:00
output_path = general['outputfile']
title = html['title']
show_onlinetime = html.get('onlinetime', True)
show_kicks = html.get('kicks', True)
show_pkicks = html.get('pkicks', True)
show_bans = html.get('bans', True)
if exists(id_map_path):
# read id_map
id_map = json.load(open(path + 'id_map.json'))
else:
id_map = {}
2015-03-05 12:48:10 -05:00
generation_start = datetime.now()
clients = {} # clid: {'nick': ..., 'onlinetime': ..., 'kicks': ..., 'pkicks': ..., 'bans': ..., 'last_connect': ..., 'connected': ...}
cldata = re.compile(r"'(.*)'\(id:(\d*)\)")
cldata_ban = re.compile(r"by\ client\ '(.*)'\(id:(\d*)\)")
cldata_invoker = re.compile(r"invokerid=(\d*)\ invokername=(.*)\ invokeruid")
def add_connect(clid, nick, logdatetime):
check_client(clid, nick)
clients[clid]['last_connect'] = mktime(logdatetime.timetuple())
clients[clid]['connected'] = True
def add_disconnect(clid, nick, logdatetime, set_connected=True):
2015-03-05 12:48:10 -05:00
check_client(clid, nick)
connect = datetime.fromtimestamp(clients[clid]['last_connect'])
delta = logdatetime - connect
minutes = delta.seconds // 60
increase_onlinetime(clid, minutes)
if set_connected:
clients[clid]['connected'] = False
2015-03-05 12:48:10 -05:00
def add_ban(clid, nick):
check_client(clid, nick)
if 'bans' in clients[clid]:
clients[clid]['bans'] += 1
else:
clients[clid]['bans'] = 1
def add_kick(clid, nick):
check_client(clid, nick)
if 'kicks' in clients[clid]:
clients[clid]['kicks'] += 1
else:
clients[clid]['kicks'] = 1
def add_pkick(clid, nick):
check_client(clid, nick)
if 'pkicks' in clients[clid]:
clients[clid]['pkicks'] += 1
else:
clients[clid]['pkicks'] = 1
def increase_onlinetime(clid, onlinetime):
if 'onlinetime' in clients[clid]:
clients[clid]['onlinetime'] += onlinetime
else:
clients[clid]['onlinetime'] = onlinetime
def check_client(clid, nick):
if clid not in clients:
clients[clid] = {}
clients[clid]['nick'] = nick
with open(log_path, 'r') as f:
today = datetime.utcnow()
for line in f:
parts = line.split('|')
logdatetime = datetime.strptime(parts[0], '%Y-%m-%d %H:%M:%S.%f')
sid = int(parts[3].strip())
data = '|'.join(parts[4:]).strip()
if data.startswith('client'):
r = cldata.findall(data)[0]
nick = r[0]
2015-05-12 15:38:34 -04:00
clid = r[1]
#print(clid, nick, sep=' | ')
if clid in id_map:
clid = id_map[clid]
2015-03-05 12:48:10 -05:00
if data.startswith('client connected'):
2015-05-12 15:38:34 -04:00
add_connect(clid, nick, logdatetime)
2015-03-05 12:48:10 -05:00
elif data.startswith('client disconnected'):
2015-05-12 15:38:34 -04:00
add_disconnect(clid, nick, logdatetime)
2015-03-05 12:48:10 -05:00
if 'invokerid' in data:
2015-05-12 15:38:34 -04:00
add_pkick(clid, nick)
2015-03-05 12:48:10 -05:00
r = cldata_invoker.findall(data)[0]
nick = r[1]
2015-05-12 15:38:34 -04:00
clid = r[0]
if clid in id_map:
clid = id_map[clid]
add_kick(clid, nick)
2015-03-05 12:48:10 -05:00
elif data.startswith('ban added') and 'cluid' in data:
r = cldata_ban.findall(data)[0]
nick = r[0]
2015-05-12 15:38:34 -04:00
clid = r[1]
add_ban(clid, nick)
2015-03-05 12:48:10 -05:00
for clid in clients:
if 'connected' not in clients[clid]:
clients[clid]['connected'] = False
if clients[clid]['connected']:
add_disconnect(clid, clients[clid]['nick'], today, set_connected=False)
2015-03-05 12:48:10 -05:00
generation_end = datetime.now()
generation_delta = generation_end - generation_start
2015-03-05 12:48:10 -05:00
# helper functions
def desc(key):
r = []
values = {}
for clid in clients:
if key in clients[clid]:
values[clid] = clients[clid][key]
for clid in sorted(values, key=values.get, reverse=True):
value = values[clid]
r.append((clid, clients[clid]['nick'], value))
2015-03-05 12:48:10 -05:00
return r
def render_template():
env = Environment(loader=FileSystemLoader(path))
template = env.get_template('template.html')
# format onlinetime
onlinetime_desc = desc('onlinetime')
for idx, (clid, nick, onlinetime) in enumerate(onlinetime_desc):
2015-03-05 12:48:10 -05:00
if onlinetime > 60:
onlinetime_str = str(onlinetime // 60) + 'h'
m = onlinetime % 60
if m > 0:
onlinetime_str += ' ' + str(m) + 'm'
else:
onlinetime_str = str(onlinetime) + 'm'
onlinetime_desc[idx] = (clid, nick, onlinetime_str, clients[clid]['connected'])
2015-03-05 12:48:10 -05:00
with open(output_path, 'w+') as f:
2015-05-12 15:38:34 -04:00
f.write(template.render(title=title, onlinetime=onlinetime_desc, kicks=desc('kicks'), pkicks=desc('pkicks'), bans=desc('bans'), seconds='{}.{}'.format(generation_delta.seconds, generation_delta.microseconds),
date=generation_end.strftime('%d.%m.%Y %H:%M'),
2015-05-12 15:38:34 -04:00
show_onlinetime=show_onlinetime,
show_kicks=show_kicks,
show_pkicks=show_pkicks,
show_bans=show_bans))
2015-03-05 12:48:10 -05:00
if len(clients) < 1:
print('Not enough data!')
else:
render_template()