Files
2022-08-14 12:54:45 +02:00

323 lines
9.3 KiB
Python
Executable File

#!/usr/bin/python3
from awpy.parser import DemoParser
from awpy.analytics.stats import player_stats
import sqlite3, os, random, time, glob
from flask import Flask, flash, request, redirect, url_for, send_from_directory, render_template, make_response
from werkzeug.utils import secure_filename
from io import StringIO
import csv
UPLOAD_FOLDER = './demos'
ALLOWED_EXTENSIONS = {'dem'}
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
colors = [ '#2488bf', '#d84d3d', '#f39700', '#4caf50' ]
db = "csgo.db"
def demo_parse(demofile, db):
print(f"[Parser] Analysing demo {demofile}")
parser = DemoParser(
demofile = demofile,
parse_rate=128,
trade_time=5,
buy_style="hltv",
parse_frames=False
)
parser.parse()
data = parser.clean_rounds(remove_no_frames=True,
remove_warmups=True,
remove_knifes=True,
remove_excess_players=True)
stats = player_stats(data["gameRounds"])
ranks = data["matchmakingRanks"]
rounds = data["gameRounds"]
matchid = data['matchID']
mapname = data['mapName']
if os.path.exists(f"{matchid}.json"):
os.remove(f"{matchid}.json")
print(f"[GC] {matchid}.json have been sucessfully deleted")
con = sqlite3.connect(db)
c = con.cursor()
tables = c.execute('''SELECT name FROM sqlite_master WHERE type='table' AND name='matches';''').fetchall()
if tables == []:
c.execute('CREATE TABLE matches \
( \
matchid text, \
map text, \
accuracy real, \
adr real, \
assists integer, \
blindTime real, \
deaths integer, \
defuses integer, \
enemiesFlashed integer, \
fireThrown interger, \
firstDeaths interger, \
firstKills integer, \
flashAssists integer, \
flashesThrown integer, \
heThrown integer, \
hs integer, \
hsPercent real, \
kast real, \
kdr real, \
kills integer, \
plants integer, \
playerName text, \
rating real, \
shotsHit integer, \
smokesThrown integer, \
steamID text, \
suicides integer, \
teamKills integer, \
teamName text, \
teammatesFlashed integer, \
totalDamageGiven integer, \
totalDamageTaken integer, \
totalRounds integer, \
totalShots integer, \
totalTeamDamageGiven integer, \
tradeKills integer, \
utilityDamage integer, \
tscore integer, \
ctscore integer, \
side text \
)')
for k, v in stats.items():
for i in rounds[-1]['ctSide']['players']:
if i['steamID'] == v["steamID"]:
side = 'CT'
for i in rounds[-1]['tSide']['players']:
if i['steamID'] == v["steamID"]:
side = 'T'
if not c.execute(f'SELECT * from matches WHERE matchid LIKE "{matchid}" and steamID LIKE {v["steamID"]}').fetchall():
c.execute("INSERT INTO matches VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", \
[
matchid, \
mapname, \
v["accuracy"], \
v["adr"], \
v["assists"], \
v["blindTime"], \
v["deaths"], \
v["defuses"], \
v["enemiesFlashed"], \
v["fireThrown"], \
v["firstDeaths"], \
v["firstKills"], \
v["flashAssists"], \
v["flashesThrown"], \
v["heThrown"], \
v["hs"], \
v["hsPercent"], \
v["kast"], \
v["kdr"], \
v["kills"], \
v["plants"], \
v["playerName"], \
v["rating"], \
v["shotsHit"], \
v["smokesThrown"], \
v["steamID"], \
v["suicides"], \
v["teamKills"], \
v["teamName"], \
v["teammatesFlashed"], \
v["totalDamageGiven"], \
v["totalDamageTaken"], \
v["totalRounds"], \
v["totalShots"], \
v["totalTeamDamageGiven"], \
v["tradeKills"], \
v["utilityDamage"], \
rounds[-1]['endTScore'], \
rounds[-1]['endCTScore'], \
side
])
con.commit()
return (0)
@app.route('/<demo>')
def demo_analyze(demo):
dempath = "demos"
now = time.time()
for file in os.listdir(dempath):
if os.path.getmtime(os.path.join(dempath, file)) < now - 30 * 86400:
os.remove(os.path.join(dempath, file))
print(f"[GC] Removed old demo {file}")
con = sqlite3.connect(db)
c = con.cursor()
if not c.execute('''SELECT name FROM sqlite_master WHERE type='table' AND name='matches';''').fetchall():
demo_parse(f"demos/{demo}.dem", db)
if not c.execute(f'SELECT * FROM matches WHERE matchid LIKE "{demo}"').fetchall():
demo_parse(f"demos/{demo}.dem", db)
if not c.execute('''SELECT name FROM sqlite_master WHERE type='table' AND name='matches';''').fetchall():
flash('Error analysing demo')
return redirect("/")
c.execute(f'SELECT * FROM matches WHERE matchid LIKE "{demo}"')
stats = c.fetchall()
con.close()
team1 = []
team2 = []
for i in range(len(stats)):
if i < 5:
team1.append(stats[i])
else:
team2.append(stats[i])
if team1[0][37] == team1[0][38]:
winner = "Draw"
elif team1[0][37] > team1[0][38] and team1[0][39] == 'T':
winner = team1[0][28] if team1[0][28] else "Team1"
else:
winner = team2[0][28] if team2[0][28] else "Team2"
return (render_template('demo.html', \
team1=sorted(team1, key=lambda tup: tup[22], reverse=True), \
team2=sorted(team2, key=lambda tup: tup[22], reverse=True), \
winner=winner, color=random.choice(colors)))
@app.route('/<demo>/csv')
def download_csv(demo):
con = sqlite3.connect(db)
c = con.cursor()
try:
c.execute(f'SELECT * FROM matches WHERE matchid LIKE "{demo}"')
stats = c.fetchall()
con.close()
except:
return(f"Couldn't fetch stats for the demo {demo}")
si = StringIO()
cw = csv.writer(si)
cw.writerow(['Player',
'Team',
'Rating',
'Kast',
'HS (%)',
'ADR',
'Accuracy (%)',
'Open Attempts',
'Open Success',
'Utility damages',
'Flash used',
'Average flash time',
'Trade kills'])
for i in range(len(stats)):
cw.writerow([stats[i][21],
stats[i][28],
stats[i][22],
stats[i][17],
stats[i][16]*100,
stats[i][3],
stats[i][2]*100,
stats[i][10] + stats[i][11],
stats[i][11],
stats[i][36],
stats[i][14],
round(stats[i][5] / stats[i][8], 2),
stats[i][35]])
file = demo + ".csv"
output = make_response(si.getvalue())
output.headers["Content-Disposition"] = f"attachment; filename={demo}.csv"
output.headers["Content-type"] = "text/csv"
return output
@app.route('/<demo>/download')
def download_file(demo):
file = demo + ".dem"
return send_from_directory(app.config["UPLOAD_FOLDER"], file)
@app.route('/player/<player>')
def get_player(player):
con = sqlite3.connect(db)
c = con.cursor()
if not c.execute('''SELECT name FROM sqlite_master WHERE type='table' AND name='matches';''').fetchall():
flash('Error analysing demo')
return redirect("/")
c.execute(f'SELECT * FROM matches WHERE playerName LIKE "{player}" OR steamID LIKE "{player}"')
stats = c.fetchall()
con.close()
stlen = len(stats)
avg = list(stats[0])
for stat in stats[1:]:
for i in range(len(avg)):
if isinstance(stat[i], int) or isinstance(stat[i], float):
avg[i] += stat[i]
else:
avg[i] = stat[i]
for i in range(len(avg)):
if isinstance(avg[i], int) or isinstance(avg[i], float):
avg[i] /= stlen
if isinstance(avg[i], float):
avg[i] = round(avg[i], 2)
if avg[37] == avg[38]:
winner = 'D'
elif avg[37] > avg[38] and avg[39] == 'T':
winner = 'L'
else:
winner = 'V'
if avg[22] > 1.1:
rating = "#4caf50"
elif avg[22] > 0.9:
rating = "#f39700"
else:
rating = "#d84d3d"
return (render_template('player.html', \
player=avg, \
matches=stats, \
winner=winner, \
rating=rating))
def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
@app.route('/', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
if 'file' not in request.files:
flash('No file part')
return redirect(request.url)
file = request.files['file']
if file.filename == '':
flash('No selected file')
return redirect(request.url)
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
return redirect(url_for('demo_analyze', demo=filename.split('.')[0]))
files = list(filter(os.path.isfile, glob.glob("./demos/*.dem")))
files.sort(key=lambda x: os.path.getmtime(x))
demid = [x.split('/')[2][:-4] for x in files]
return (render_template('upload.html', demos=demid))
@app.route('/favicon.ico')
def favicon():
return ("Not found"), 404