mirror of
https://github.com/FAUSheppy/open-web-leaderboard.git
synced 2025-12-09 00:18:33 +01:00
Compare commits
3 Commits
ese-custom
...
ese-custom
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
159871be47 | ||
|
|
6e677c663b | ||
|
|
12c001ac71 |
@@ -1,63 +0,0 @@
|
|||||||
import json
|
|
||||||
import datetime
|
|
||||||
import player
|
|
||||||
import datetime
|
|
||||||
|
|
||||||
class MapSummary:
|
|
||||||
def __init__(self, rounds):
|
|
||||||
'''Create a map MapSummary from a Round-Array'''
|
|
||||||
|
|
||||||
self.securityWins = 0
|
|
||||||
self.insurgentWins = 0
|
|
||||||
self.times = []
|
|
||||||
self.predictions = []
|
|
||||||
self.totalGames = 0
|
|
||||||
self.confidence = []
|
|
||||||
self.mapName = None
|
|
||||||
|
|
||||||
for r in rounds:
|
|
||||||
self.mapName = r.mapName
|
|
||||||
self.totalGames += 1
|
|
||||||
if r.winnerSideString == "Insurgent":
|
|
||||||
self.insurgentWins += 1
|
|
||||||
else:
|
|
||||||
self.securityWins += 1
|
|
||||||
|
|
||||||
self.predictions += [r.numericPrediction]
|
|
||||||
self.confidence += [r.confidence]
|
|
||||||
self.times += [r.duration]
|
|
||||||
|
|
||||||
self.insurgentWinPercent = ""
|
|
||||||
self.securityWinPercent = ""
|
|
||||||
self.ratingSystemDeviation = "-"
|
|
||||||
self.averageTime = ""
|
|
||||||
|
|
||||||
try:
|
|
||||||
self.insurgentWinPercent = self.insurgentWins / self.totalGames*100
|
|
||||||
self.securityWinPercent = self.securityWins / self.totalGames*100
|
|
||||||
averageSeconds = sum([t.total_seconds() for t in self.times]) / len(self.times)
|
|
||||||
self.averageTime = datetime.timedelta(seconds=int(averageSeconds))
|
|
||||||
|
|
||||||
mapper = [ 1 if x == 0 else -1 for x in self.predictions ]
|
|
||||||
reverseMapper = [ 1 if x == 0 else 0 for x in self.predictions ]
|
|
||||||
self.ratingSystemDeviation = 0
|
|
||||||
|
|
||||||
confidenceCutoff = 60
|
|
||||||
confidenceTupels = list(filter(lambda x: x[1] > confidenceCutoff,
|
|
||||||
zip(reverseMapper, self.confidence)))
|
|
||||||
|
|
||||||
mapperTupels = list(filter(lambda x: x[1] > confidenceCutoff,
|
|
||||||
zip(mapper, self.confidence)))
|
|
||||||
|
|
||||||
for i in range(0, len(mapperTupels)):
|
|
||||||
self.ratingSystemDeviation += mapperTupels[i][0] * max(100, 50+mapperTupels[i][1])
|
|
||||||
|
|
||||||
self.ratingSystemDeviation /= len(mapperTupels)
|
|
||||||
self.predictionCorrectPercentage = sum([x[0] for x in confidenceTupels])
|
|
||||||
self.predictionCorrectPercentage /= len(confidenceTupels)
|
|
||||||
self.predictionCorrectPercentage *= 100
|
|
||||||
self.predictionCorrectPercentage = round(self.predictionCorrectPercentage)
|
|
||||||
|
|
||||||
except ZeroDivisionError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
60
Round.py
60
Round.py
@@ -1,60 +0,0 @@
|
|||||||
import json
|
|
||||||
import datetime
|
|
||||||
import player
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
|
|
||||||
class Round:
|
|
||||||
def __init__(self, dbRow):
|
|
||||||
'''Create Round Object from cursor database row'''
|
|
||||||
|
|
||||||
timestamp, winners, losers, winnerSide, mapName, duration, prediction, confidence = dbRow
|
|
||||||
startTime = datetime.datetime.fromtimestamp(int(float(timestamp)))
|
|
||||||
winnersParsed = json.loads(winners)
|
|
||||||
losersParsed = json.loads(losers)
|
|
||||||
|
|
||||||
self.startTime = startTime
|
|
||||||
self.id = int(float(timestamp))
|
|
||||||
self.winners = [ player.playerFromDict(wp, int(duration)) for wp in winnersParsed ]
|
|
||||||
self.losers = [ player.playerFromDict(lp, int(duration)) for lp in losersParsed ]
|
|
||||||
self.winnerSide = winnerSide
|
|
||||||
self.duration = datetime.timedelta(seconds=int(duration))
|
|
||||||
|
|
||||||
self.blacklist = False
|
|
||||||
blacklistNames = []
|
|
||||||
blacklistFile = "blacklist.json"
|
|
||||||
if os.path.isfile(blacklistFile):
|
|
||||||
with open(blacklistFile) as f:
|
|
||||||
blacklistNames = json.load(f)["blacklist"]
|
|
||||||
|
|
||||||
for name in blacklistNames:
|
|
||||||
for p in self.winners:
|
|
||||||
if p.name == name:
|
|
||||||
self.blacklist = True
|
|
||||||
for p in self.losers:
|
|
||||||
if p.name == name:
|
|
||||||
self.blacklist = True
|
|
||||||
|
|
||||||
|
|
||||||
if winnerSide == 1:
|
|
||||||
self.winnerSideString = "Red"
|
|
||||||
self.loserSideString = "Blue"
|
|
||||||
else:
|
|
||||||
self.winnerSideString = "Blue"
|
|
||||||
self.loserSideString = "Red"
|
|
||||||
if mapName:
|
|
||||||
self.mapName = mapName
|
|
||||||
else:
|
|
||||||
self.mapName = "unavailiable"
|
|
||||||
|
|
||||||
self.numericPrediction = prediction
|
|
||||||
self.confidence = (int(confidence * 100) - 50)*2
|
|
||||||
self.quality = int(150 - self.confidence)
|
|
||||||
if self.confidence < 50:
|
|
||||||
self.prediction = "-"
|
|
||||||
elif prediction == 0:
|
|
||||||
self.prediction = self.winnerSideString
|
|
||||||
elif prediction == 1:
|
|
||||||
self.prediction = self.loserSideString
|
|
||||||
else:
|
|
||||||
self.prediction = "Error"
|
|
||||||
68
balance.py
Normal file
68
balance.py
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
from constants import *
|
||||||
|
|
||||||
|
NO_CHANGE = -1
|
||||||
|
|
||||||
|
def shouldSwapBasedOnPrio(teams, curIndex, compareIndex, curTeamIndex):
|
||||||
|
'''Return a team ID in which to switch with the compare index'''
|
||||||
|
|
||||||
|
otherTeam = (curTeamIndex + 1) % 2
|
||||||
|
|
||||||
|
curPrio = teams[curTeamIndex].affinityFor(curIndex)
|
||||||
|
compPrioOtherTeam = teams[otherTeam].affinityFor(compareIndex)
|
||||||
|
compPrioSameTeam = team[otherTeam].affinityFor(compareIndex)
|
||||||
|
|
||||||
|
if curPrio > compPrioSameTeam and compPrioSameTeam > compPrioOtherTeam:
|
||||||
|
return compPrioSameTeam
|
||||||
|
elif curPrio > compPrioOtherTeam:
|
||||||
|
return compPrioOtherTeam
|
||||||
|
else:
|
||||||
|
return NO_CHANGE
|
||||||
|
|
||||||
|
def swap(teams, teamIndex1, teamIndex2, pos1, pos2):
|
||||||
|
'''Swap two positions in the same or different teams'''
|
||||||
|
|
||||||
|
tmp = teams[teamIndex1][pos1]
|
||||||
|
teams[teamIndex1][pos1] = teams[teamIndex2][pos2]
|
||||||
|
teams[teamIndex2][pos2] = tmp
|
||||||
|
|
||||||
|
def ratingDiff(team1, team2):
|
||||||
|
'''Positive if first > seconds, negative if second > first, 0 if equal'''
|
||||||
|
return sum([p.rating for p in team1]) - sum([p.rating for p in team2])
|
||||||
|
|
||||||
|
def balance(players):
|
||||||
|
|
||||||
|
# initial teams #
|
||||||
|
playersByRating = sorted(players, key=lambda p: p.rating)
|
||||||
|
|
||||||
|
teams = dict( { 0 : [] }, { 1 : [] } )
|
||||||
|
for i in range(0, len(playersByRating)):
|
||||||
|
teams[i%2] = playersByRating[i]
|
||||||
|
|
||||||
|
# optimize positions worst case ~8n^2 * 2log(n) #
|
||||||
|
for teamIndex in teams.keys():
|
||||||
|
changed = True
|
||||||
|
while changed:
|
||||||
|
changed = False
|
||||||
|
for curIndex in range(0, 5)
|
||||||
|
for compareIndex in range(curIndex, 5)
|
||||||
|
if curIndex == compareIndex:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# shouldSwap return -1 for no swap or the team to swap with #
|
||||||
|
swapTeam = shouldSwapBasedOnPrio(teams, curIndex, compareIndex, teamIndex)
|
||||||
|
elif VALID_INDEX(swapTeam):
|
||||||
|
changed = True
|
||||||
|
swap(teams, teamIndex, swapTeam, curIndex, compareIndex)
|
||||||
|
|
||||||
|
# optimize team rating #
|
||||||
|
changedRating = True
|
||||||
|
while changedRating:
|
||||||
|
|
||||||
|
diff = ratingDiff(teams[0], teams[1])
|
||||||
|
diffByPos = [ teams[0][i] - teams[1][i] for i in range(0, 5) ]
|
||||||
|
|
||||||
|
for i in range(0, diffByPos):
|
||||||
|
diffHelper = abs(diffByPos[i]-diff)
|
||||||
|
if diffHelper <
|
||||||
|
for curIndex in range(0, len(teams[0])):
|
||||||
|
if rating diff
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
# rename to config.py and remove this line for this file to have effect
|
|
||||||
DB_PATH="players.sqlite"
|
|
||||||
8
constants.py
Normal file
8
constants.py
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
POSITIONS_NAMES = ["Top", "Jungle", "Mid", "Bottom", "Support" ]
|
||||||
|
DATABASE_PRIO_NAMES = ["prioTop", "prioJungle", "prioMid", "prioBot", "prioSupport" ]
|
||||||
|
TYPE_JSON = 'application/json'
|
||||||
|
|
||||||
|
HTTP_OK = 200
|
||||||
|
|
||||||
|
def VALID_INDEX(index):
|
||||||
|
return index == 0 or index == 1
|
||||||
49
player.py
49
player.py
@@ -1,49 +0,0 @@
|
|||||||
#!/usr/bin/python3
|
|
||||||
import flask
|
|
||||||
|
|
||||||
def playerFromDict(d, duration):
|
|
||||||
p = PlayerInLeaderboard([d["id"], d["name"], None, 0, 0, 0, 0])
|
|
||||||
p.participation = min(int(d["active_time"]/duration*100), 100)
|
|
||||||
return p
|
|
||||||
|
|
||||||
class PlayerInLeaderboard:
|
|
||||||
def __init__(self, dbRow):
|
|
||||||
'''Initialize a player object later to be serialized to HTML'''
|
|
||||||
|
|
||||||
playerId, name, lastGame, wins, mu, sigma, games = dbRow
|
|
||||||
|
|
||||||
# set relevant values #
|
|
||||||
self.name = name
|
|
||||||
self.playerId = playerId
|
|
||||||
self.mu = mu
|
|
||||||
self.sigma = sigma
|
|
||||||
self.rating = int(self.mu) - 2*int(self.sigma)
|
|
||||||
self.ratingStr = str(self.rating)
|
|
||||||
self.games = int(games)
|
|
||||||
self.wins = int(wins)
|
|
||||||
self.loses = self.games - self.wins
|
|
||||||
self.rank = None
|
|
||||||
self.lastGame = lastGame
|
|
||||||
self.participation = -1
|
|
||||||
|
|
||||||
self.muChange = None
|
|
||||||
self.sigmaChange = None
|
|
||||||
self.ratingChangeString = "N/A"
|
|
||||||
|
|
||||||
# determine winratio #
|
|
||||||
if self.games == 0:
|
|
||||||
self.winratio = "N/A"
|
|
||||||
else:
|
|
||||||
self.winratio = str(int(self.wins/self.games * 100))
|
|
||||||
|
|
||||||
def getLineHTML(self, rank):
|
|
||||||
'''Build a single line for a specific player in the leaderboard'''
|
|
||||||
|
|
||||||
string = flask.render_template("playerLine.html", \
|
|
||||||
playerRank = rank, \
|
|
||||||
playerName = self.name, \
|
|
||||||
playerRating = self.rating, \
|
|
||||||
playerGames = self.games, \
|
|
||||||
playerWinratio = self.winratio)
|
|
||||||
|
|
||||||
return flask.Markup(string)
|
|
||||||
364
server.py
364
server.py
@@ -3,202 +3,114 @@ import flask
|
|||||||
import requests
|
import requests
|
||||||
import argparse
|
import argparse
|
||||||
import datetime
|
import datetime
|
||||||
import flask_caching as fcache
|
|
||||||
import itertools
|
import itertools
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import MapSummary
|
|
||||||
import random
|
import random
|
||||||
import secrets
|
import secrets
|
||||||
import riotwatcher
|
import riotwatcher
|
||||||
import time
|
import time
|
||||||
import statistics
|
import statistics
|
||||||
|
|
||||||
from database import DatabaseConnection
|
|
||||||
import api
|
import api
|
||||||
|
|
||||||
|
from constants import *
|
||||||
|
|
||||||
|
|
||||||
app = flask.Flask("open-leaderboard")
|
app = flask.Flask("open-leaderboard")
|
||||||
|
|
||||||
WATCHER = None
|
WATCHER = None
|
||||||
KEY = None
|
KEY = None
|
||||||
|
|
||||||
|
|
||||||
if os.path.isfile("config.py"):
|
if os.path.isfile("config.py"):
|
||||||
app.config.from_object("config")
|
app.config.from_object("config")
|
||||||
|
|
||||||
cache = fcache.Cache(app, config={'CACHE_TYPE': 'simple'})
|
|
||||||
cache.init_app(app)
|
|
||||||
|
|
||||||
SEGMENT=100
|
SEGMENT=100
|
||||||
SERVERS=list()
|
SERVERS=list()
|
||||||
|
|
||||||
|
from sqlalchemy import Column, Integer, String, Boolean, or_, and_
|
||||||
|
from sqlalchemy.orm import sessionmaker
|
||||||
|
from sqlalchemy.exc import IntegrityError
|
||||||
|
from sqlalchemy.sql import func
|
||||||
|
import sqlalchemy
|
||||||
|
from flask_sqlalchemy import SQLAlchemy
|
||||||
|
|
||||||
|
db = SQLAlchemy(app)
|
||||||
|
|
||||||
def prettifyMinMaxY(computedMin, computedMax):
|
class PlayerInDatabase(db.Model):
|
||||||
if computedMax > 0 and computedMin > 0:
|
__tablename__ = "players"
|
||||||
return (0, 4000)
|
player = Column(String, primary_key=True)
|
||||||
else:
|
rating = Column(Integer)
|
||||||
return (computedMin - 100, 4000)
|
ratingFix = Column(Integer)
|
||||||
|
lastUpdated = Column(Integer)
|
||||||
|
|
||||||
@app.route("/players-online")
|
class Submission(db.Model):
|
||||||
def playersOnline():
|
__tablename__ = "submissions"
|
||||||
'''Calc and return the online players'''
|
ident = Column(String, primary_key=True)
|
||||||
|
submissionId = Column(String)
|
||||||
|
player = Column(String)
|
||||||
|
prioTop = Column(Integer)
|
||||||
|
prioJungle = Column(Integer)
|
||||||
|
prioMid = Column(Integer)
|
||||||
|
prioBot = Column(Integer)
|
||||||
|
prioSupport = Column(Integer)
|
||||||
|
|
||||||
playerTotal = 0
|
def toDict():
|
||||||
error = ""
|
pass
|
||||||
|
|
||||||
for s in SERVERS:
|
def affinityFor(self, posIndex):
|
||||||
try:
|
prio = getattr(self, DATABASE_PRIO_NAMES[posIndex])
|
||||||
with valve.source.a2s.ServerQuerier((args.host, args.port)) as server:
|
return prio
|
||||||
playerTotal += int(server.info()["player_count"])
|
|
||||||
except NoResponseError:
|
|
||||||
error = "Server Unreachable"
|
|
||||||
except Exception as e:
|
|
||||||
error = str(e)
|
|
||||||
|
|
||||||
retDict = { "player_total" : playerTotal, "error" : error }
|
|
||||||
return flask.Response(json.dumps(retDict), 200, mimetype='application/json')
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/round-info")
|
|
||||||
def singleRound():
|
|
||||||
'''Display info about a single round itdentified by it's timestamp'''
|
|
||||||
|
|
||||||
timestamp = flask.request.args.get("id")
|
|
||||||
if not timestamp:
|
|
||||||
return ("ID Missing", 404)
|
|
||||||
if not timestamp.endswith(".0"):
|
|
||||||
timestamp = timestamp + ".0"
|
|
||||||
db = DatabaseConnection(app.config["DB_PATH"])
|
|
||||||
r = db.getRoundByTimestamp(timestamp)
|
|
||||||
if not r:
|
|
||||||
return ("Round not found", 404)
|
|
||||||
elif r.blacklist:
|
|
||||||
return ("Unavailable due to pending GDPR deletion request", 451)
|
|
||||||
r = db.calcRatingChanges(r)
|
|
||||||
|
|
||||||
if not r:
|
|
||||||
return ("", 404)
|
|
||||||
|
|
||||||
r.winners = sorted(r.winners, key=lambda p: p.participation, reverse=True)
|
|
||||||
r.losers = sorted(r.losers, key=lambda p: p.participation, reverse=True)
|
|
||||||
|
|
||||||
return flask.render_template("single_round.html", r=r)
|
|
||||||
|
|
||||||
@app.route("/livegames")
|
|
||||||
def liveGames():
|
|
||||||
'''Display info about a single round itdentified by it's timestamp'''
|
|
||||||
|
|
||||||
db = DatabaseConnection(app.config["DB_PATH"])
|
|
||||||
rounds = db.getLiveGames()
|
|
||||||
return flask.render_template("livegames.html", liveGameRounds=rounds, noRounds=not bool(rounds))
|
|
||||||
|
|
||||||
@app.route("/maps")
|
|
||||||
def maps():
|
|
||||||
'''Show an overview of maps'''
|
|
||||||
|
|
||||||
db = DatabaseConnection(app.config["DB_PATH"])
|
|
||||||
start = datetime.datetime.now() - datetime.timedelta(days=4000)
|
|
||||||
end = datetime.datetime.now()
|
|
||||||
rounds = db.roundsBetweenDates(start, end)
|
|
||||||
distinctMaps = db.distinctMaps()
|
|
||||||
maps = []
|
|
||||||
for mapName in [ tupel[0] for tupel in distinctMaps]:
|
|
||||||
roundsWithMap = list(filter(lambda r: r.mapName == mapName , rounds))
|
|
||||||
maps += [MapSummary.MapSummary(roundsWithMap)]
|
|
||||||
|
|
||||||
allMaps = MapSummary.MapSummary(rounds)
|
|
||||||
allMaps.mapName = "All Maps*"
|
|
||||||
maps += [allMaps]
|
|
||||||
|
|
||||||
|
|
||||||
mapsFiltered = filter(lambda x: x.mapName, maps)
|
|
||||||
return flask.render_template("maps.html", maps=mapsFiltered)
|
|
||||||
|
|
||||||
@app.route("/rounds-by-timestamp")
|
|
||||||
@app.route("/rounds")
|
|
||||||
def rounds():
|
|
||||||
'''Show rounds played on the server'''
|
|
||||||
|
|
||||||
start = flask.request.args.get("start")
|
|
||||||
end = flask.request.args.get("end")
|
|
||||||
|
|
||||||
if not start or not end:
|
|
||||||
start = datetime.datetime.now() - datetime.timedelta(days=365)
|
|
||||||
end = datetime.datetime.now()
|
|
||||||
else:
|
|
||||||
start = datetime.datetime.fromtimestamp(start)
|
|
||||||
end = datetime.datetime.fromtimestamp(end)
|
|
||||||
|
|
||||||
db = DatabaseConnection(app.config["DB_PATH"])
|
|
||||||
rounds = db.roundsBetweenDates(start, end)
|
|
||||||
|
|
||||||
return flask.render_template("rounds.html", rounds=rounds)
|
|
||||||
|
|
||||||
|
|
||||||
# get timestamp
|
|
||||||
# display players
|
|
||||||
# display rating change
|
|
||||||
# display outcome
|
|
||||||
# display map
|
|
||||||
|
|
||||||
class Player:
|
class Player:
|
||||||
def __init__(self, name, prio):
|
def __init__(self, name, prio):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.prio = prio
|
self.prio = prio
|
||||||
|
|
||||||
# TODO
|
|
||||||
submission = dict()
|
|
||||||
@app.route("/role-submission", methods=['GET', 'POST'])
|
@app.route("/role-submission", methods=['GET', 'POST'])
|
||||||
def roleSubmissionTool():
|
def roleSubmissionTool():
|
||||||
positions=["Top", "Jungle", "Mid", "Bottom", "Support" ]
|
|
||||||
|
|
||||||
ident = flask.request.args.get("id")
|
submissionId = flask.request.args.get("id")
|
||||||
|
player = flask.request.args.get("player")
|
||||||
|
|
||||||
if flask.request.method == 'POST':
|
if flask.request.method == 'POST':
|
||||||
|
|
||||||
if not ident in submission:
|
submissionQuery = db.session.query(PlayerInDatabase)
|
||||||
submission.update({ ident : [] })
|
identKey = "{}-{}".format(submissionId, player)
|
||||||
|
submission = submissionQuery.filter(PlayerInDatabase.ident == identKey).first()
|
||||||
tmp = dict()
|
|
||||||
tmp.update({ "name" : flask.request.form["playername"] })
|
|
||||||
for p in positions:
|
|
||||||
tmp.update({ p : flask.request.form["prio_{}".format(p)] })
|
|
||||||
|
|
||||||
existed = False
|
if not submission:
|
||||||
for pl in submission[ident]:
|
submission = Submission(identKey, submissionId, player, -1, -1, -1, -1, -1)
|
||||||
if pl["name"] == tmp["name"]:
|
|
||||||
for p in positions:
|
|
||||||
pl.update({ p : flask.request.form["prio_{}".format(p)] })
|
|
||||||
existed = True
|
|
||||||
break;
|
|
||||||
|
|
||||||
if not existed:
|
for i in range(0, 5):
|
||||||
submission[ident] += [tmp]
|
formKey = "prio_" + POSITIONS_NAMES[i]
|
||||||
|
setattr(submission, DATABASE_PRIO_NAMES[i], flask.request.form[formKey])
|
||||||
|
|
||||||
return flask.redirect("/balance-tool?id={}".format(ident))
|
db.session.merge(submission)
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
return flask.redirect("/balance-tool?id=" + ident)
|
||||||
else:
|
else:
|
||||||
return flask.render_template("role_submission.html",
|
return flask.render_template("role_submission.html", positions=positions, ident=ident)
|
||||||
positions=positions,
|
|
||||||
ident=ident)
|
|
||||||
|
|
||||||
@app.route("/balance-tool-data")
|
@app.route("/balance-tool-data")
|
||||||
def balanceToolData():
|
def balanceToolData():
|
||||||
ident = flask.request.args.get("id")
|
|
||||||
retDict = dict()
|
submissionId = flask.request.args.get("id")
|
||||||
if not ident in submission:
|
submissionsQuery = db.session.query(PlayerInDatabase)
|
||||||
return flask.Response(json.dumps({ "no-data" : False }), 200, mimetype='application/json')
|
submissions = submissionsQuery.filter(PlayerInDatabase.submissionId == submissionId).all()
|
||||||
retDict.update({ "submissions" : submission[ident] })
|
|
||||||
return flask.Response(json.dumps(retDict), 200, mimetype='application/json')
|
if not submissions:
|
||||||
|
return flask.Response(json.dumps({ "no-data" : False }), HTTP_OK, mimetype=TYPE_JSON)
|
||||||
|
|
||||||
|
retDict.update()
|
||||||
|
|
||||||
|
dicts = [ s.toDict() for s in submissions ]
|
||||||
|
return flask.Response(json.dumps({ "submissions" : dicts }), HTTP_OK, mimetype=TYPE_JSON)
|
||||||
|
|
||||||
|
|
||||||
@app.route('/')
|
@app.route('/')
|
||||||
@app.route("/balance-tool", methods=['GET', 'POST'])
|
@app.route("/balance-tool", methods=['GET', 'POST'])
|
||||||
def balanceTool():
|
def balanceTool():
|
||||||
positions=["Top", "Jungle", "Mid", "Bottom", "Support"]
|
|
||||||
|
|
||||||
#db = DatabaseConnection(app.config["DB_PATH"])
|
|
||||||
|
|
||||||
if flask.request.method == 'POST':
|
if flask.request.method == 'POST':
|
||||||
|
|
||||||
@@ -345,9 +257,6 @@ def balanceTool():
|
|||||||
positions=positions,
|
positions=positions,
|
||||||
sides=["left", "right"],
|
sides=["left", "right"],
|
||||||
ident=ident)
|
ident=ident)
|
||||||
@app.route("/get-cache")
|
|
||||||
def getCacheLoc():
|
|
||||||
return (json.dumps(api.getCache()), 200)
|
|
||||||
|
|
||||||
@app.route("/player-api")
|
@app.route("/player-api")
|
||||||
def playerApi():
|
def playerApi():
|
||||||
@@ -365,140 +274,9 @@ def playerApiCache():
|
|||||||
else:
|
else:
|
||||||
return ("Nope", 404)
|
return ("Nope", 404)
|
||||||
|
|
||||||
@app.route("/player")
|
@app.route("/get-cache")
|
||||||
def player():
|
def getCacheLoc():
|
||||||
'''Show Info about Player'''
|
return (json.dumps(api.getCache()), 200)
|
||||||
|
|
||||||
playerId = flask.request.args.get("id")
|
|
||||||
if(not playerId):
|
|
||||||
return ("", 404)
|
|
||||||
|
|
||||||
db = DatabaseConnection(app.config["DB_PATH"])
|
|
||||||
player = db.getPlayerById(playerId)
|
|
||||||
|
|
||||||
if(not player):
|
|
||||||
return ("", 404)
|
|
||||||
|
|
||||||
player.rank = db.getPlayerRank(player)
|
|
||||||
histData = db.getHistoricalForPlayerId(playerId)
|
|
||||||
|
|
||||||
csv_month_year = []
|
|
||||||
csv_ratings = []
|
|
||||||
csv_timestamps = []
|
|
||||||
|
|
||||||
minRating = 3000
|
|
||||||
maxRating = 0
|
|
||||||
|
|
||||||
if histData:
|
|
||||||
datapoints = histData[playerId]
|
|
||||||
if datapoints:
|
|
||||||
|
|
||||||
tickCounter = 10
|
|
||||||
for dpk in datapoints.keys():
|
|
||||||
t = datetime.datetime.fromtimestamp(int(float(dpk)))
|
|
||||||
tsMs = str(int(t.timestamp() * 1000))
|
|
||||||
ratingString = str(int(datapoints[dpk]["mu"]) - 2*int(datapoints[dpk]["sigma"]))
|
|
||||||
ratingAmored = '{ x : ' + tsMs + ', y : ' + ratingString + '}'
|
|
||||||
csv_timestamps += [str(tsMs)]
|
|
||||||
csv_ratings += [ratingAmored]
|
|
||||||
|
|
||||||
tickCounter -= 1
|
|
||||||
if tickCounter <= 0:
|
|
||||||
tickCounter = 10
|
|
||||||
csv_month_year += ['new Date({})'.format(tsMs)]
|
|
||||||
|
|
||||||
minRating = min(minRating, int(ratingString))
|
|
||||||
maxRating = max(maxRating, int(ratingString))
|
|
||||||
|
|
||||||
yMin, yMax = prettifyMinMaxY(minRating, maxRating)
|
|
||||||
|
|
||||||
# change displayed rank to start from 1 :)
|
|
||||||
player.rank += 1
|
|
||||||
|
|
||||||
return flask.render_template("player.html", player=player, CSV_RATINGS=",".join(csv_ratings),
|
|
||||||
CSV_MONTH_YEAR_OF_RATINGS=",".join(csv_month_year),
|
|
||||||
CSV_TIMESTAMPS=csv_timestamps,
|
|
||||||
Y_MIN=yMin, Y_MAX=yMax)
|
|
||||||
|
|
||||||
@app.route('/leaderboard')
|
|
||||||
@cache.cached(timeout=10, query_string=True)
|
|
||||||
def leaderboard():
|
|
||||||
'''Show main leaderboard page with range dependant on parameters'''
|
|
||||||
|
|
||||||
# parse parameters #
|
|
||||||
page = flask.request.args.get("page")
|
|
||||||
playerName = flask.request.args.get("string")
|
|
||||||
db = DatabaseConnection(app.config["DB_PATH"])
|
|
||||||
|
|
||||||
if page:
|
|
||||||
pageInt = int(page)
|
|
||||||
if pageInt < 0:
|
|
||||||
pageInt = 0
|
|
||||||
start = SEGMENT * int(page)
|
|
||||||
else:
|
|
||||||
pageInt = 0
|
|
||||||
start = 0
|
|
||||||
|
|
||||||
# handle find player request #
|
|
||||||
cannotFindPlayer = ""
|
|
||||||
searchName = ""
|
|
||||||
|
|
||||||
playerList = None
|
|
||||||
doNotComputeRank = True
|
|
||||||
if playerName:
|
|
||||||
playersInLeaderboard = db.findPlayerByName(playerName)
|
|
||||||
if not playersInLeaderboard:
|
|
||||||
cannotFindPlayer = flask.Markup("<div class=noPlayerFound>No player of that name</div>")
|
|
||||||
start = 0
|
|
||||||
else:
|
|
||||||
if len(playersInLeaderboard) == 1:
|
|
||||||
rank = playersInLeaderboard[0].rank
|
|
||||||
if(playersInLeaderboard[0].games < 10):
|
|
||||||
return flask.redirect("/player?id={}".format(playersInLeaderboard[0].playerId))
|
|
||||||
searchName = playersInLeaderboard[0].name
|
|
||||||
start = rank - (rank % SEGMENT)
|
|
||||||
else:
|
|
||||||
playerList = playersInLeaderboard
|
|
||||||
for p in playerList:
|
|
||||||
if p.rank == -1:
|
|
||||||
p.rankStr = "N/A"
|
|
||||||
else:
|
|
||||||
p.rankStr = str(p.rank)
|
|
||||||
doNotComputeRank = False
|
|
||||||
|
|
||||||
reachedEnd = False
|
|
||||||
maxEntry = 0
|
|
||||||
if not playerList:
|
|
||||||
# compute range #
|
|
||||||
end = start + SEGMENT
|
|
||||||
maxEntry = db.getTotalPlayers()
|
|
||||||
reachedEnd = False
|
|
||||||
if end > maxEntry:
|
|
||||||
start = maxEntry - ( maxEntry % SEGMENT ) - 1
|
|
||||||
end = maxEntry - 1
|
|
||||||
print(maxEntry)
|
|
||||||
reachedEnd = True
|
|
||||||
|
|
||||||
playerList = db.getRankRange(start, end)
|
|
||||||
|
|
||||||
endOfBoardIndicator = ""
|
|
||||||
if reachedEnd:
|
|
||||||
endOfBoardHtml = "<div id='eof' class=endOfBoardIndicator> - - - End of Board - - - </div>"
|
|
||||||
endOfBoardIndicator = flask.Markup(endOfBoardHtml)
|
|
||||||
|
|
||||||
# fix <100 player start at 0 #
|
|
||||||
if maxEntry <= 100:
|
|
||||||
start = max(start, 0)
|
|
||||||
|
|
||||||
finalResponse = flask.render_template("base.html", playerList=playerList, \
|
|
||||||
doNotComputeRank=doNotComputeRank, \
|
|
||||||
start=start, \
|
|
||||||
endOfBoardIndicator=endOfBoardIndicator, \
|
|
||||||
findPlayer=cannotFindPlayer, \
|
|
||||||
searchName=searchName,
|
|
||||||
nextPageNumber=int(pageInt)+1,
|
|
||||||
prevPageNumber=int(pageInt)-1)
|
|
||||||
return finalResponse
|
|
||||||
|
|
||||||
@app.route('/static/<path:path>')
|
@app.route('/static/<path:path>')
|
||||||
def send_js(path):
|
def send_js(path):
|
||||||
@@ -508,22 +286,22 @@ def send_js(path):
|
|||||||
def init():
|
def init():
|
||||||
|
|
||||||
global WATCHER
|
global WATCHER
|
||||||
|
|
||||||
|
app.config["DB"] = db
|
||||||
|
db.create_all()
|
||||||
|
|
||||||
with open("key.txt","r") as f:
|
with open("key.txt","r") as f:
|
||||||
key = f.read().strip()
|
key = f.read().strip()
|
||||||
WATCHER = riotwatcher.LolWatcher(key)
|
WATCHER = riotwatcher.LolWatcher(key)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(description='Start open-leaderboard', \
|
parser = argparse.ArgumentParser(description='Start open-leaderboard', \
|
||||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||||
parser.add_argument('--interface', default="localhost", \
|
parser.add_argument('--interface', default="localhost")
|
||||||
help='Interface on which flask (this server) will take requests on')
|
parser.add_argument('--port', default="5002")
|
||||||
parser.add_argument('--port', default="5002", \
|
|
||||||
help='Port on which flask (this server) will take requests on')
|
|
||||||
|
|
||||||
parser.add_argument('--skillbird-db', required=False, help='skillbird database (overrides web connection if set)')
|
|
||||||
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
app.config["DB_PATH"] = args.skillbird_db
|
|
||||||
app.config["TEMPLATES_AUTO_RELOAD"] = True
|
app.config["TEMPLATES_AUTO_RELOAD"] = True
|
||||||
app.run(host=args.interface, port=args.port)
|
app.run(host=args.interface, port=args.port)
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
CREATE TABLE players(
|
|
||||||
playerName TEXT PRIMARY KEY,
|
|
||||||
rating INTEGER,
|
|
||||||
lastupdated TEXT
|
|
||||||
);
|
|
||||||
Reference in New Issue
Block a user