mirror of
https://github.com/FAUSheppy/open-web-leaderboard.git
synced 2025-12-10 08:58:33 +01:00
Compare commits
32 Commits
6491afc272
...
ese-custom
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5d98016040 | ||
|
|
6a2ff6a72f | ||
|
|
ee61d1bb63 | ||
|
|
5c8191f4cf | ||
|
|
5dc1d16447 | ||
|
|
eb967900d0 | ||
|
|
bcb460bc24 | ||
|
|
02be6031a2 | ||
| a8da2b71bc | |||
| 7f8af681dd | |||
| 25ea0e03b5 | |||
| 7f845cc17c | |||
| 6a5b150cb8 | |||
| 82680cc0db | |||
| bdd24d68fa | |||
| cab9dceab7 | |||
| ead1a05c2e | |||
| 77e58305da | |||
| 9cdee90a7f | |||
| 0a1675c637 | |||
| f6ce5a9533 | |||
| 8f8eba81fa | |||
| 3a028607b4 | |||
| ca8dfb5208 | |||
|
|
3df3ade848 | ||
| 2ce48a7147 | |||
| 590763c613 | |||
| 5b8ab6fa78 | |||
| 1641332661 | |||
| bf31cb59e8 | |||
| a52bd66aed | |||
| 54f02c978a |
34
.github/workflows/main.yaml
vendored
34
.github/workflows/main.yaml
vendored
@@ -1,34 +0,0 @@
|
|||||||
name: Container Build for open-web-leaderboard
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- "master"
|
|
||||||
schedule:
|
|
||||||
- cron: "0 2 * * 0"
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
docker:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
environment:
|
|
||||||
name: prod
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
-
|
|
||||||
name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
-
|
|
||||||
name: Login to Docker Registry
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
registry: ${{ secrets.REGISTRY }}
|
|
||||||
username: ${{ secrets.REGISTRY_USER }}
|
|
||||||
password: ${{ secrets.REGISTRY_PASS }}
|
|
||||||
-
|
|
||||||
name: open-web-leaderboard
|
|
||||||
uses: docker/build-push-action@v3
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
platforms: linux/amd64
|
|
||||||
push: true
|
|
||||||
tags: "${{ secrets.REGISTRY }}/atlantishq/open-web-leaderboard:latest"
|
|
||||||
13
Dockerfile
13
Dockerfile
@@ -1,13 +0,0 @@
|
|||||||
FROM alpine
|
|
||||||
|
|
||||||
RUN apk add --no-cache py3-pip
|
|
||||||
RUN python3 -m pip install --no-cache-dir --break-system-packages waitress
|
|
||||||
COPY req.txt .
|
|
||||||
RUN python3 -m pip install --no-cache-dir --break-system-packages -r req.txt
|
|
||||||
|
|
||||||
RUN mkdir /app
|
|
||||||
WORKDIR /app
|
|
||||||
COPY ./ .
|
|
||||||
|
|
||||||
ENTRYPOINT ["waitress-serve"]
|
|
||||||
CMD ["--host", "0.0.0.0", "--port", "5000", "--call", "app:createApp"]
|
|
||||||
@@ -33,7 +33,6 @@ Players can be blacklisted by name via a *blacklist.json* file in the project ro
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Adding servers for player count live info
|
# Adding servers for player count live info
|
||||||
**THIS FEATURE IS DISABLED BECAUSE py-valve DOES NOT SUPPORT PYTHON>3.9**
|
|
||||||
Source-Servers can be added via the *servers.json*-file:
|
Source-Servers can be added via the *servers.json*-file:
|
||||||
|
|
||||||
[
|
[
|
||||||
|
|||||||
10
Round.py
10
Round.py
@@ -36,12 +36,12 @@ class Round:
|
|||||||
self.blacklist = True
|
self.blacklist = True
|
||||||
|
|
||||||
|
|
||||||
if winnerSide == 2:
|
if winnerSide == 1:
|
||||||
self.winnerSideString = "Security"
|
self.winnerSideString = "Red"
|
||||||
self.loserSideString = "Insurgent"
|
self.loserSideString = "Blue"
|
||||||
else:
|
else:
|
||||||
self.winnerSideString = "Insurgent"
|
self.winnerSideString = "Blue"
|
||||||
self.loserSideString = "Security"
|
self.loserSideString = "Red"
|
||||||
if mapName:
|
if mapName:
|
||||||
self.mapName = mapName
|
self.mapName = mapName
|
||||||
else:
|
else:
|
||||||
|
|||||||
113
api.py
Normal file
113
api.py
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import riotwatcher
|
||||||
|
import json
|
||||||
|
import argparse
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
from jinja2 import Environment, FileSystemLoader
|
||||||
|
import requests
|
||||||
|
import datetime as dt
|
||||||
|
import sqlite3
|
||||||
|
|
||||||
|
REGION = "euw1"
|
||||||
|
DEFAULT_RATING = 1200
|
||||||
|
|
||||||
|
def tierToNumber(tier):
|
||||||
|
ratingmap = { 'CHALLENGER' : 4500,
|
||||||
|
'GRANDMASTER': 4000,
|
||||||
|
'MASTER' : 3500,
|
||||||
|
'DIAMOND' : 3000,
|
||||||
|
'PLATINUM' : 2500,
|
||||||
|
'GOLD' : 1500,
|
||||||
|
'SILVER' : 1000,
|
||||||
|
'BRONZE' : 500,
|
||||||
|
'IRON' : 0 }
|
||||||
|
return ratingmap[tier]
|
||||||
|
|
||||||
|
def divisionToNumber(division):
|
||||||
|
divisionmap = { "I" : 300,
|
||||||
|
"II" : 200,
|
||||||
|
"III" : 100,
|
||||||
|
"IV" : 0 }
|
||||||
|
return divisionmap[division]
|
||||||
|
|
||||||
|
DATABASE = "rating_cache.sqlite"
|
||||||
|
def checkPlayerKnown(playerName):
|
||||||
|
conn = sqlite3.connect(DATABASE)
|
||||||
|
cursor = conn.cursor()
|
||||||
|
backlog = dt.datetime.now() - dt.timedelta(days=7)
|
||||||
|
query = '''SELECT * from players where playerName = ? LIMIT 1;'''
|
||||||
|
cursor.execute(query, (playerName,))
|
||||||
|
try:
|
||||||
|
playerName, rating, lastUpdated = cursor.fetchone()
|
||||||
|
except TypeError:
|
||||||
|
print("sqlite cache '{}' not found".format(playerName))
|
||||||
|
return None
|
||||||
|
conn.close()
|
||||||
|
return (playerName, rating, lastUpdated)
|
||||||
|
|
||||||
|
def addToDB(playerName, rating):
|
||||||
|
|
||||||
|
conn = sqlite3.connect(DATABASE)
|
||||||
|
cursor = conn.cursor()
|
||||||
|
cursor.execute("INSERT INTO players VALUES(?,?,?);",(
|
||||||
|
playerName,
|
||||||
|
rating,
|
||||||
|
dt.datetime.now().timestamp()))
|
||||||
|
conn.commit()
|
||||||
|
print("Added {}".format(playerName))
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
|
def getPlayerRatingFromApi(playerName, WATCHER):
|
||||||
|
|
||||||
|
if not playerName:
|
||||||
|
return DEFAULT_RATING
|
||||||
|
|
||||||
|
tupel = checkPlayerKnown(playerName)
|
||||||
|
if tupel:
|
||||||
|
return tupel[1]
|
||||||
|
|
||||||
|
while(True):
|
||||||
|
try:
|
||||||
|
pTmp = WATCHER.summoner.by_name(REGION, playerName)
|
||||||
|
except requests.exceptions.HTTPError as e:
|
||||||
|
# not found #
|
||||||
|
if e.response.status_code == 404:
|
||||||
|
addToDB(playerName, DEFAULT_RATING)
|
||||||
|
return DEFAULT_RATING
|
||||||
|
# rate limit
|
||||||
|
elif e.response.status_code == 429:
|
||||||
|
print("Ratelimit reached")
|
||||||
|
#time.sleep(120)
|
||||||
|
#continue
|
||||||
|
return DEFAULT_RATING
|
||||||
|
else:
|
||||||
|
raise e
|
||||||
|
if not pTmp:
|
||||||
|
addToDB(playerName, 0)
|
||||||
|
return DEFAULT_RATING
|
||||||
|
|
||||||
|
computed = DEFAULT_RATING
|
||||||
|
|
||||||
|
try:
|
||||||
|
pInfo = WATCHER.league.by_summoner(REGION, pTmp["id"])
|
||||||
|
except requests.exceptions.HTTPError as e:
|
||||||
|
if e.response.status_code == 429:
|
||||||
|
print("Ratelimit reached")
|
||||||
|
return DEFAULT_RATING
|
||||||
|
#time.sleep(120)
|
||||||
|
#continue
|
||||||
|
else:
|
||||||
|
raise e
|
||||||
|
|
||||||
|
for queue in pInfo:
|
||||||
|
if queue["queueType"] != "RANKED_SOLO_5x5":
|
||||||
|
continue
|
||||||
|
computed = tierToNumber(queue["tier"]) + divisionToNumber(queue["rank"]) + \
|
||||||
|
int(queue["leaguePoints"])
|
||||||
|
print(computed)
|
||||||
|
|
||||||
|
addToDB(playerName, computed)
|
||||||
|
return computed
|
||||||
2
app.py
2
app.py
@@ -1,5 +1,3 @@
|
|||||||
import server
|
import server
|
||||||
def createApp(envivorment=None, start_response=None):
|
def createApp(envivorment=None, start_response=None):
|
||||||
with server.app.app_context():
|
|
||||||
server.create_app()
|
|
||||||
return server.app
|
return server.app
|
||||||
|
|||||||
19
database.py
19
database.py
@@ -31,7 +31,7 @@ class DatabaseConnection:
|
|||||||
'''Get the total number of players in the database'''
|
'''Get the total number of players in the database'''
|
||||||
|
|
||||||
cursor = self.connPlayers.cursor()
|
cursor = self.connPlayers.cursor()
|
||||||
cursor.execute("SELECT Count(*) FROM players where games >= 10 and not lastgame is null")
|
cursor.execute("SELECT Count(*) FROM players")
|
||||||
count = cursor.fetchone()[0]
|
count = cursor.fetchone()[0]
|
||||||
return count
|
return count
|
||||||
|
|
||||||
@@ -79,8 +79,8 @@ class DatabaseConnection:
|
|||||||
|
|
||||||
cursor = self.connPlayers.cursor()
|
cursor = self.connPlayers.cursor()
|
||||||
limit = end - start
|
limit = end - start
|
||||||
sqlQuery = '''Select * FROM players where games >= 10
|
print(limit, start)
|
||||||
and not lastgame is null
|
sqlQuery = '''Select * FROM players where games >= 1
|
||||||
ORDER BY (mu - 2*sigma) DESC LIMIT ? OFFSET ?'''
|
ORDER BY (mu - 2*sigma) DESC LIMIT ? OFFSET ?'''
|
||||||
cursor.execute(sqlQuery, (limit, start))
|
cursor.execute(sqlQuery, (limit, start))
|
||||||
rows = cursor.fetchall()
|
rows = cursor.fetchall()
|
||||||
@@ -121,11 +121,8 @@ class DatabaseConnection:
|
|||||||
can't and shouldn't be used to identify a player'''
|
can't and shouldn't be used to identify a player'''
|
||||||
|
|
||||||
cursor = self.connPlayers.cursor()
|
cursor = self.connPlayers.cursor()
|
||||||
if(player.games < 10):
|
cursor.execute('''SELECT COUNT(*) from players
|
||||||
return -1
|
where (mu-2*sigma) > (?-2*?);''',
|
||||||
cursor.execute('''SELECT COUNT(*) from players where games >= 10
|
|
||||||
and not lastgame is null
|
|
||||||
and (mu-2*sigma) > (?-2*?);''',
|
|
||||||
(player.mu, player.sigma))
|
(player.mu, player.sigma))
|
||||||
rank = cursor.fetchone()[0]
|
rank = cursor.fetchone()[0]
|
||||||
return rank
|
return rank
|
||||||
@@ -181,9 +178,9 @@ class DatabaseConnection:
|
|||||||
WHERE timestamp < ? AND id = ?''',
|
WHERE timestamp < ? AND id = ?''',
|
||||||
(roundObj.startTime.timestamp(), p.playerId))
|
(roundObj.startTime.timestamp(), p.playerId))
|
||||||
|
|
||||||
if(cursorHist.fetchone()[0] < 10):
|
#if(cursorHist.fetchone()[0] < 10):
|
||||||
p.ratingChangeString = "Placements"
|
# p.ratingChangeString = "Placements"
|
||||||
continue
|
# continue
|
||||||
|
|
||||||
cursorHist.execute('''SELECT mu,sima FROM playerHistoricalData
|
cursorHist.execute('''SELECT mu,sima FROM playerHistoricalData
|
||||||
WHERE timestamp < ? AND id = ? order by timestamp DESC LIMIT 1 ''',
|
WHERE timestamp < ? AND id = ? order by timestamp DESC LIMIT 1 ''',
|
||||||
|
|||||||
93
medals.py
93
medals.py
@@ -1,93 +0,0 @@
|
|||||||
import flask
|
|
||||||
|
|
||||||
medalDict = { "games-played-1" : { "name" : "Tourist",
|
|
||||||
"text" : "Played {} games on this server",
|
|
||||||
"color" : "white",
|
|
||||||
"text-color" : "black" },
|
|
||||||
|
|
||||||
"games-played-2" : { "name" : "Enlisted",
|
|
||||||
"text" : "Played {} games on this server",
|
|
||||||
"color": "green",
|
|
||||||
"text-color" : "white" },
|
|
||||||
|
|
||||||
"games-played-3" : { "name" : "Veteran",
|
|
||||||
"text" : "Played {} games on this server",
|
|
||||||
"color" : "yellow",
|
|
||||||
"text-color" : "black" },
|
|
||||||
|
|
||||||
"rating-cur-1" : { "name" : "Slightly skilled",
|
|
||||||
"text" : "Rated above 1500",
|
|
||||||
"color" : "beige",
|
|
||||||
"text-color" : "black" },
|
|
||||||
|
|
||||||
"rating-2k-1" : { "name" : "Contender",
|
|
||||||
"text" : "Played {} games above 2000 rating",
|
|
||||||
"color" : "coral",
|
|
||||||
"text-color" : "black" },
|
|
||||||
"rating-2k-2" : { "name" : "Known Contender",
|
|
||||||
"text" : "Played {} games above 2000 rating",
|
|
||||||
"color" : "lightgreen",
|
|
||||||
"text-color" : "black" },
|
|
||||||
|
|
||||||
"rating-3k-1" : { "name" : "Epic",
|
|
||||||
"text" : "Played {} games above 3000 rating",
|
|
||||||
"color" : "lightblue",
|
|
||||||
"text-color" : "black" },
|
|
||||||
"rating-3k-2" : { "name" : "Legend",
|
|
||||||
"text" : "Played {} games above 3000 rating",
|
|
||||||
"color" : "orange",
|
|
||||||
"text-color" : "black" },
|
|
||||||
"rating-3k-3" : { "name" : "All Along The Watchtower",
|
|
||||||
"text" : "Played {} games above 3000 rating",
|
|
||||||
"color" : "red",
|
|
||||||
"text-color" : "black" },
|
|
||||||
}
|
|
||||||
|
|
||||||
def medalGen(medal, formatInsert=None):
|
|
||||||
'''Gen HTML for metal'''
|
|
||||||
html = '\
|
|
||||||
<div style="background-color: {bg} !important; color: {color} !important;"\
|
|
||||||
class="btn btn-secondary"\
|
|
||||||
data-toggle="tooltip" data-placement="top" title="{tooltip}">\
|
|
||||||
{text}\
|
|
||||||
</div>\
|
|
||||||
'
|
|
||||||
tmp = html.format(bg=medal["color"], tooltip=medal["text"], text=medal["name"],
|
|
||||||
color=medal["text-color"])
|
|
||||||
if formatInsert:
|
|
||||||
tmp = tmp.format(formatInsert)
|
|
||||||
return flask.Markup(tmp)
|
|
||||||
|
|
||||||
def getMedals(ratingList, gamesPlayed, currentRating):
|
|
||||||
'''Get Medals this player should have'''
|
|
||||||
medals = []
|
|
||||||
|
|
||||||
if gamesPlayed > 500:
|
|
||||||
medals += [medalGen(medalDict["games-played-3"], gamesPlayed)]
|
|
||||||
elif gamesPlayed > 100:
|
|
||||||
medals += [medalGen(medalDict["games-played-2"], gamesPlayed)]
|
|
||||||
elif gamesPlayed > 50:
|
|
||||||
medals += [medalGen(medalDict["games-played-1"], gamesPlayed)]
|
|
||||||
|
|
||||||
games2k = len(list(filter(lambda x: x > 2000, ratingList)))
|
|
||||||
games3k = len(list(filter(lambda x: x > 3000, ratingList)))
|
|
||||||
|
|
||||||
if games2k > 100:
|
|
||||||
medals += [medalGen(medalDict["rating-2k-2"], games2k)]
|
|
||||||
elif games2k > 0:
|
|
||||||
medals += [medalGen(medalDict["rating-2k-1"], games2k)]
|
|
||||||
|
|
||||||
if games3k > 200:
|
|
||||||
medals += [medalGen(medalDict["rating-3k-3"], games3k)]
|
|
||||||
|
|
||||||
if games3k > 50:
|
|
||||||
medals += [medalGen(medalDict["rating-3k-2"], games3k)]
|
|
||||||
elif games3k > 5:
|
|
||||||
medals += [medalGen(medalDict["rating-3k-1"], games3k)]
|
|
||||||
|
|
||||||
if currentRating > 1500:
|
|
||||||
medals += [medalGen(medalDict["rating-cur-1"])]
|
|
||||||
|
|
||||||
return medals
|
|
||||||
|
|
||||||
|
|
||||||
BIN
rounds.sqlite
BIN
rounds.sqlite
Binary file not shown.
50
rounds/2021-04-26-round-01.json
Normal file
50
rounds/2021-04-26-round-01.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"map": "SR",
|
||||||
|
"winner-side": "1",
|
||||||
|
"winners": [
|
||||||
|
{
|
||||||
|
"playerId": "Phirop",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "xXxMarethyuxXx",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "iTrash",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "JuckF Bierhuhn",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "ENTAC",
|
||||||
|
"isFake": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"losers": [
|
||||||
|
{
|
||||||
|
"playerId": "TryhardYordle",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "ChessGM lbfxd",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "TheSlapstick",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "Vyne",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "ESE Felix",
|
||||||
|
"isFake": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"duration": 1456,
|
||||||
|
"startTime": "2021-04-25T22:00+02:00"
|
||||||
|
}
|
||||||
50
rounds/2021-04-26-round-02.json
Normal file
50
rounds/2021-04-26-round-02.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"map": "SR",
|
||||||
|
"winner-side": "0",
|
||||||
|
"winners": [
|
||||||
|
{
|
||||||
|
"playerId": "ESE Felix",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "Vyne",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "ESE Kniveless",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "JuckF Bierhuhn",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "ENTAC",
|
||||||
|
"isFake": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"losers": [
|
||||||
|
{
|
||||||
|
"playerId": "TryhardYordle",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "TheSlapstick",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "xXxMarethyuxXx",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "ChessGM lbfxd",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "Phirop",
|
||||||
|
"isFake": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"duration": 1932,
|
||||||
|
"startTime": "2021-04-25T21:00+02:00"
|
||||||
|
}
|
||||||
50
rounds/2021-04-26-round-03.json
Normal file
50
rounds/2021-04-26-round-03.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"map": "SR",
|
||||||
|
"winner-side": "1",
|
||||||
|
"winners": [
|
||||||
|
{
|
||||||
|
"playerId": "Phirop",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "Vyne",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "ESE Felix",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "ChessGM lbfxd",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "TheSlapstick",
|
||||||
|
"isFake": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"losers": [
|
||||||
|
{
|
||||||
|
"playerId": "ENTAC",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "xXxMarethyuxXx",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "ESE Kniveless",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "JuckF Bierhuhn",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "TryhardYordle",
|
||||||
|
"isFake": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"duration": 2017,
|
||||||
|
"startTime": "2021-04-25T20:00+02:00"
|
||||||
|
}
|
||||||
71
rounds/2021-05-24-round-01.json
Normal file
71
rounds/2021-05-24-round-01.json
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
{
|
||||||
|
"map" : "SR",
|
||||||
|
"winner-side" : 1,
|
||||||
|
"winners" : [
|
||||||
|
{
|
||||||
|
"playerId" : "TryhardYordle",
|
||||||
|
"playerName" : "TryhardYordle",
|
||||||
|
"isFake" : false,
|
||||||
|
"activeTime" : 1971
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId" : "ESE Schmohi",
|
||||||
|
"playerName" : "ESE Schmohi",
|
||||||
|
"isFake" : false,
|
||||||
|
"activeTime" : 1971
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId" : "Area 522",
|
||||||
|
"playerName" : "Area 522",
|
||||||
|
"isFake" : false,
|
||||||
|
"activeTime" : 1971
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId" : "iTrash",
|
||||||
|
"playerName" : "iTrash",
|
||||||
|
"isFake" : false,
|
||||||
|
"activeTime" : 1971
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId" : "Téa Jay",
|
||||||
|
"playerName" : "Téa Jay",
|
||||||
|
"isFake" : false,
|
||||||
|
"activeTime" : 1971
|
||||||
|
}
|
||||||
|
|
||||||
|
],
|
||||||
|
"losers" : [
|
||||||
|
{
|
||||||
|
"playerId" : "Phirop",
|
||||||
|
"playerName" : "Phirop",
|
||||||
|
"isFake" : false,
|
||||||
|
"activeTime" : 1971
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId" : "ENTAC",
|
||||||
|
"playerName" : "ENTAC",
|
||||||
|
"isFake" : false,
|
||||||
|
"activeTime" : 1971
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId" : "BoringBookCover",
|
||||||
|
"playerName" : "BoringBookCover",
|
||||||
|
"isFake" : false,
|
||||||
|
"activeTime" : 1971
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId" : "ESE Litzuck",
|
||||||
|
"playerName" : "ESE Litzuck",
|
||||||
|
"isFake" : false,
|
||||||
|
"activeTime" : 1971
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId" : "ESE MarsUltor",
|
||||||
|
"playerName" : "ESE MarsUltor",
|
||||||
|
"isFake" : false,
|
||||||
|
"activeTime" : 1971
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"duration" : 1971,
|
||||||
|
"startTime" : "2021-05-24T20:00+02:00"
|
||||||
|
}
|
||||||
72
rounds/2021-05-31-round-01.json
Normal file
72
rounds/2021-05-31-round-01.json
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
{
|
||||||
|
"map" : "SR",
|
||||||
|
"winner-side" : 0,
|
||||||
|
"winners" : [
|
||||||
|
{
|
||||||
|
"playerId" : "Vyne",
|
||||||
|
"playerName" : "Vyne",
|
||||||
|
"isFake" : false,
|
||||||
|
"activeTime" : 1927
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId" : "ESE Kniveless",
|
||||||
|
"playerName" : "ESE Kniveless",
|
||||||
|
"isFake" : false,
|
||||||
|
"activeTime" : 1927
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId" : "ESE Vinnie",
|
||||||
|
"playerName" : "ESE Vinnie",
|
||||||
|
"isFake" : false,
|
||||||
|
"activeTime" : 1927
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId" : "ESE Litzuck",
|
||||||
|
"playerName" : "ESE Litzuck",
|
||||||
|
"isFake" : false,
|
||||||
|
"activeTime" : 1927
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId" : "ESE MarsUltor",
|
||||||
|
"playerName" : "ESE MarsUltor",
|
||||||
|
"isFake" : false,
|
||||||
|
"activeTime" : 1927
|
||||||
|
}
|
||||||
|
|
||||||
|
],
|
||||||
|
"losers" : [
|
||||||
|
{
|
||||||
|
"playerId" : "ESE Schmohi",
|
||||||
|
"playerName" : "ESE Schmohi",
|
||||||
|
"isFake" : false,
|
||||||
|
"activeTime" : 1927
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId" : "ESE Nemesis",
|
||||||
|
"playerName" : "ESE Nemesis",
|
||||||
|
"isFake" : false,
|
||||||
|
"activeTime" : 1927
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId" : "ENTAC",
|
||||||
|
"playerName" : "ENTAC",
|
||||||
|
"isFake" : false,
|
||||||
|
"activeTime" : 1927
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId" : "Area 522",
|
||||||
|
"playerName" : "Area 552",
|
||||||
|
"isFake" : false,
|
||||||
|
"activeTime" : 1927
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId" : "Subsidiary",
|
||||||
|
"playerName" : "Subsidiary",
|
||||||
|
"isFake" : false,
|
||||||
|
"activeTime" : 1927
|
||||||
|
}
|
||||||
|
|
||||||
|
],
|
||||||
|
"duration" : 1927,
|
||||||
|
"startTime" : "2021-05-31T20:00+02:00"
|
||||||
|
}
|
||||||
72
rounds/2021-05-31-round-02.json
Normal file
72
rounds/2021-05-31-round-02.json
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
{
|
||||||
|
"map" : "SR",
|
||||||
|
"winner-side" : 1,
|
||||||
|
"winners" : [
|
||||||
|
{
|
||||||
|
"playerId" : "Vyne",
|
||||||
|
"playerName" : "Vyne",
|
||||||
|
"isFake" : false,
|
||||||
|
"activeTime" : 1864
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId" : "ESE Kniveless",
|
||||||
|
"playerName" : "ESE Kniveless",
|
||||||
|
"isFake" : false,
|
||||||
|
"activeTime" : 1864
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId" : "ESE Vinnie",
|
||||||
|
"playerName" : "ESE Vinnie",
|
||||||
|
"isFake" : false,
|
||||||
|
"activeTime" : 1864
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId" : "ESE Litzuck",
|
||||||
|
"playerName" : "ESE Litzuck",
|
||||||
|
"isFake" : false,
|
||||||
|
"activeTime" : 1864
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId" : "ESE MarsUltor",
|
||||||
|
"playerName" : "ESE MarsUltor",
|
||||||
|
"isFake" : false,
|
||||||
|
"activeTime" : 1864
|
||||||
|
}
|
||||||
|
|
||||||
|
],
|
||||||
|
"losers" : [
|
||||||
|
{
|
||||||
|
"playerId" : "Muchlove the One",
|
||||||
|
"playerName" : "Muchlove the One",
|
||||||
|
"isFake" : false,
|
||||||
|
"activeTime" : 1864
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId" : "ESE Nemesis",
|
||||||
|
"playerName" : "ESE Nemesis",
|
||||||
|
"isFake" : false,
|
||||||
|
"activeTime" : 1864
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId" : "ENTAC",
|
||||||
|
"playerName" : "ENTAC",
|
||||||
|
"isFake" : false,
|
||||||
|
"activeTime" : 1864
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId" : "Area 522",
|
||||||
|
"playerName" : "Area 552",
|
||||||
|
"isFake" : false,
|
||||||
|
"activeTime" : 1864
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId" : "Subsidiary",
|
||||||
|
"playerName" : "Subsidiary",
|
||||||
|
"isFake" : false,
|
||||||
|
"activeTime" : 1864
|
||||||
|
}
|
||||||
|
|
||||||
|
],
|
||||||
|
"duration" : 1864,
|
||||||
|
"startTime" : "2021-05-31T21:00+02:00"
|
||||||
|
}
|
||||||
71
rounds/2021-05-31-round-03.json
Normal file
71
rounds/2021-05-31-round-03.json
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
{
|
||||||
|
"map" : "SR",
|
||||||
|
"winner-side" : 0,
|
||||||
|
"winners" : [
|
||||||
|
{
|
||||||
|
"playerId" : "Vyne",
|
||||||
|
"playerName" : "Vyne",
|
||||||
|
"isFake" : false,
|
||||||
|
"activeTime" : 1450
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId" : "ESE Kniveless",
|
||||||
|
"playerName" : "ESE Kniveless",
|
||||||
|
"isFake" : false,
|
||||||
|
"activeTime" : 1450
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId" : "Muchlove the One",
|
||||||
|
"playerName" : "Muchlove the One",
|
||||||
|
"isFake" : false,
|
||||||
|
"activeTime" : 1450
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId" : "ESE Litzuck",
|
||||||
|
"playerName" : "ESE Litzuck",
|
||||||
|
"isFake" : false,
|
||||||
|
"activeTime" : 1450
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId" : "ENTAC",
|
||||||
|
"playerName" : "ENTAC",
|
||||||
|
"isFake" : false,
|
||||||
|
"activeTime" : 1450
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"losers" : [
|
||||||
|
{
|
||||||
|
"playerId" : "ESE MarsUltor",
|
||||||
|
"playerName" : "ESE MarsUltor",
|
||||||
|
"isFake" : false,
|
||||||
|
"activeTime" : 1450
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId" : "ESE Nemesis",
|
||||||
|
"playerName" : "ESE Nemesis",
|
||||||
|
"isFake" : false,
|
||||||
|
"activeTime" : 1450
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId" : "Area 522",
|
||||||
|
"playerName" : "Area 552",
|
||||||
|
"isFake" : false,
|
||||||
|
"activeTime" : 1450
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId" : "Takki",
|
||||||
|
"playerName" : "Takki",
|
||||||
|
"isFake" : false,
|
||||||
|
"activeTime" : 1450
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId" : "ESE Vinnie",
|
||||||
|
"playerName" : "ESE Vinnie",
|
||||||
|
"isFake" : false,
|
||||||
|
"activeTime" : 1450
|
||||||
|
}
|
||||||
|
|
||||||
|
],
|
||||||
|
"duration" : 1450,
|
||||||
|
"startTime" : "2021-05-31T23:00+02:00"
|
||||||
|
}
|
||||||
50
rounds/2021-06-07-round-01.json
Normal file
50
rounds/2021-06-07-round-01.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"map": "SR",
|
||||||
|
"winner-side": "0",
|
||||||
|
"winners": [
|
||||||
|
{
|
||||||
|
"playerId": "Phirop",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "ENTAC",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "Victor Lustig",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "TSo",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "ESE MarsUltor",
|
||||||
|
"isFake": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"losers": [
|
||||||
|
{
|
||||||
|
"playerId": "Téa Jay",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "Heinz sama",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "Area 522",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "Byndeskanzler",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "ESE Schmohi",
|
||||||
|
"isFake": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"duration": 2019,
|
||||||
|
"startTime": "2021-06-07T20:00+02:00"
|
||||||
|
}
|
||||||
50
rounds/2021-07-05-round-01.json
Normal file
50
rounds/2021-07-05-round-01.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"map": "SR",
|
||||||
|
"winner-side": "1",
|
||||||
|
"winners": [
|
||||||
|
{
|
||||||
|
"playerId": "ESE TomTom",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "Byndeskanzler",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "Area 522",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "Heinz sama",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "Téa Jay",
|
||||||
|
"isFake": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"losers": [
|
||||||
|
{
|
||||||
|
"playerId": "Phirop",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "lbfxd",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "Victor Lustig",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "ESE MarsUltor",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "ENTAC",
|
||||||
|
"isFake": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"duration": 1978,
|
||||||
|
"startTime": "2021-07-05T20:00+02:00"
|
||||||
|
}
|
||||||
50
rounds/2021-07-05-round-02.json
Normal file
50
rounds/2021-07-05-round-02.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"map": "SR",
|
||||||
|
"winner-side": "1",
|
||||||
|
"winners": [
|
||||||
|
{
|
||||||
|
"playerId": "ESE TomTom",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "ENTAC",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "Area 522",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "Heinz sama",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "Téa Jay",
|
||||||
|
"isFake": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"losers": [
|
||||||
|
{
|
||||||
|
"playerId": "Phirop",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "lbfxd",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "Victor Lustig",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "ESE MarsUltor",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "Byndeskanzler",
|
||||||
|
"isFake": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"duration": 1978,
|
||||||
|
"startTime": "2021-07-05T21:00+02:00"
|
||||||
|
}
|
||||||
50
rounds/2021-07-05-round-03.json
Normal file
50
rounds/2021-07-05-round-03.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"map": "SR",
|
||||||
|
"winner-side": "0",
|
||||||
|
"winners": [
|
||||||
|
{
|
||||||
|
"playerId": "Phirop",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "ENTAC",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "Heinz sama",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "Victor Lustig",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "ESE MarsUltor",
|
||||||
|
"isFake": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"losers": [
|
||||||
|
{
|
||||||
|
"playerId": "Area 522",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "lbfxd",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "Téa Jay",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "Byndeskanzler",
|
||||||
|
"isFake": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerId": "ESE TomTom",
|
||||||
|
"isFake": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"duration": 1804,
|
||||||
|
"startTime": "2021-07-05T22:00+02:00"
|
||||||
|
}
|
||||||
7
rounds/all.sh
Normal file
7
rounds/all.sh
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
curl -X POST -H "Content-Type: application/json" -d @2021-04-26-round-01.json http://localhost:10010/submitt-round
|
||||||
|
curl -X POST -H "Content-Type: application/json" -d @2021-04-26-round-02.json http://localhost:10010/submitt-round
|
||||||
|
curl -X POST -H "Content-Type: application/json" -d @2021-04-26-round-03.json http://localhost:10010/submitt-round
|
||||||
|
curl -X POST -H "Content-Type: application/json" -d @2021-05-24-round-01.json http://localhost:10010/submitt-round
|
||||||
|
curl -X POST -H "Content-Type: application/json" -d @2021-05-31-round-01.json http://localhost:10010/submitt-round
|
||||||
|
curl -X POST -H "Content-Type: application/json" -d @2021-05-31-round-02.json http://localhost:10010/submitt-round
|
||||||
|
curl -X POST -H "Content-Type: application/json" -d @2021-05-31-round-03.json http://localhost:10010/submitt-round
|
||||||
13
rounds/data
Normal file
13
rounds/data
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
1
|
||||||
|
24:16
|
||||||
|
TryhardYordle
|
||||||
|
ChessGM lbfxd
|
||||||
|
TheSlapstick
|
||||||
|
Vyne
|
||||||
|
ESE Felix
|
||||||
|
Phirop
|
||||||
|
xXxMarethyuxXx
|
||||||
|
iTrash
|
||||||
|
JuckF Bierhuhn
|
||||||
|
ENTAC
|
||||||
|
2021-04-25T22:00+02:00
|
||||||
44
rounds/gen.py
Executable file
44
rounds/gen.py
Executable file
@@ -0,0 +1,44 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
winnerside = input("Winnerseide (0/1 , 0=bue, 1=red): ")
|
||||||
|
duration = input("Duration: ")
|
||||||
|
duration = int(duration.split(":")[0])*60+int(duration.split(":")[1])
|
||||||
|
|
||||||
|
print("Blue Team")
|
||||||
|
blueTeam = []
|
||||||
|
for i in range(5):
|
||||||
|
pname = input("Name: ")
|
||||||
|
p = dict()
|
||||||
|
p.update({"playerId" : pname})
|
||||||
|
p.update({"isFake" : False})
|
||||||
|
blueTeam += [p]
|
||||||
|
|
||||||
|
print("Red Team")
|
||||||
|
redTeam = []
|
||||||
|
for i in range(5):
|
||||||
|
pname = input("Name: ")
|
||||||
|
p = dict()
|
||||||
|
p.update({"playerId" : pname})
|
||||||
|
p.update({"isFake" : False})
|
||||||
|
redTeam += [p]
|
||||||
|
|
||||||
|
if winnerside == 0:
|
||||||
|
winners = blueTeam
|
||||||
|
losers = redTeam
|
||||||
|
else:
|
||||||
|
winners = redTeam
|
||||||
|
losers = blueTeam
|
||||||
|
|
||||||
|
startTime = input("Start Time: ")
|
||||||
|
|
||||||
|
retDict = {}
|
||||||
|
retDict.update({ "map" : "SR" })
|
||||||
|
retDict.update({ "winner-side" : winnerside })
|
||||||
|
retDict.update({ "winners" : winners})
|
||||||
|
retDict.update({ "losers" : losers})
|
||||||
|
retDict.update({ "duration" : duration })
|
||||||
|
retDict.update({ "startTime" : startTime})
|
||||||
|
|
||||||
|
import json
|
||||||
|
print()
|
||||||
|
print(json.dumps(retDict, indent=4, sort_keys=False))
|
||||||
308
server.py
308
server.py
@@ -1,21 +1,29 @@
|
|||||||
#!/usr/bin/python3
|
#!/usr/bin/python3
|
||||||
import medals
|
|
||||||
import flask
|
import flask
|
||||||
import requests
|
import requests
|
||||||
import argparse
|
import argparse
|
||||||
import datetime
|
import datetime
|
||||||
import flask_caching as fcache
|
import flask_caching as fcache
|
||||||
|
import itertools
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import MapSummary
|
import MapSummary
|
||||||
|
import random
|
||||||
|
import secrets
|
||||||
|
import riotwatcher
|
||||||
|
import time
|
||||||
|
import statistics
|
||||||
|
|
||||||
from database import DatabaseConnection
|
from database import DatabaseConnection
|
||||||
#import valve.source.a2s
|
import api
|
||||||
#from valve.source import NoResponseError
|
|
||||||
|
|
||||||
|
|
||||||
app = flask.Flask("open-leaderboard")
|
app = flask.Flask("open-leaderboard")
|
||||||
|
|
||||||
|
WATCHER = 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")
|
||||||
|
|
||||||
@@ -42,9 +50,8 @@ def playersOnline():
|
|||||||
|
|
||||||
for s in SERVERS:
|
for s in SERVERS:
|
||||||
try:
|
try:
|
||||||
pass
|
with valve.source.a2s.ServerQuerier((args.host, args.port)) as server:
|
||||||
#with valve.source.a2s.ServerQuerier((s["host"], s["port"])) as server:
|
playerTotal += int(server.info()["player_count"])
|
||||||
# playerTotal += int(server.info()["player_count"])
|
|
||||||
except NoResponseError:
|
except NoResponseError:
|
||||||
error = "Server Unreachable"
|
error = "Server Unreachable"
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -119,7 +126,7 @@ def rounds():
|
|||||||
end = flask.request.args.get("end")
|
end = flask.request.args.get("end")
|
||||||
|
|
||||||
if not start or not end:
|
if not start or not end:
|
||||||
start = datetime.datetime.now() - datetime.timedelta(days=7)
|
start = datetime.datetime.now() - datetime.timedelta(days=365)
|
||||||
end = datetime.datetime.now()
|
end = datetime.datetime.now()
|
||||||
else:
|
else:
|
||||||
start = datetime.datetime.fromtimestamp(start)
|
start = datetime.datetime.fromtimestamp(start)
|
||||||
@@ -137,6 +144,227 @@ def rounds():
|
|||||||
# display outcome
|
# display outcome
|
||||||
# display map
|
# display map
|
||||||
|
|
||||||
|
class Player:
|
||||||
|
def __init__(self, name, prio):
|
||||||
|
self.name = name
|
||||||
|
self.prio = prio
|
||||||
|
|
||||||
|
# TODO
|
||||||
|
submission = dict()
|
||||||
|
@app.route("/role-submission", methods=['GET', 'POST'])
|
||||||
|
def roleSubmissionTool():
|
||||||
|
positions=["Top", "Jungle", "Mid", "Bottom", "Support" ]
|
||||||
|
|
||||||
|
ident = flask.request.args.get("id")
|
||||||
|
if flask.request.method == 'POST':
|
||||||
|
|
||||||
|
if not ident in submission:
|
||||||
|
submission.update({ ident : [] })
|
||||||
|
|
||||||
|
tmp = dict()
|
||||||
|
tmp.update({ "name" : flask.request.form["playername"] })
|
||||||
|
for p in positions:
|
||||||
|
tmp.update({ p : flask.request.form["prio_{}".format(p)] })
|
||||||
|
|
||||||
|
existed = False
|
||||||
|
for pl in submission[ident]:
|
||||||
|
if pl["name"] == tmp["name"]:
|
||||||
|
for p in positions:
|
||||||
|
pl.update({ p : flask.request.form["prio_{}".format(p)] })
|
||||||
|
existed = True
|
||||||
|
break;
|
||||||
|
|
||||||
|
if not existed:
|
||||||
|
submission[ident] += [tmp]
|
||||||
|
|
||||||
|
return flask.redirect("/balance-tool?id={}".format(ident))
|
||||||
|
else:
|
||||||
|
return flask.render_template("role_submission.html",
|
||||||
|
positions=positions,
|
||||||
|
ident=ident)
|
||||||
|
|
||||||
|
@app.route("/balance-tool-data")
|
||||||
|
def balanceToolData():
|
||||||
|
ident = flask.request.args.get("id")
|
||||||
|
retDict = dict()
|
||||||
|
if not ident in submission:
|
||||||
|
return flask.Response(json.dumps({ "no-data" : False }), 200, mimetype='application/json')
|
||||||
|
retDict.update({ "submissions" : submission[ident] })
|
||||||
|
return flask.Response(json.dumps(retDict), 200, mimetype='application/json')
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/')
|
||||||
|
@app.route("/balance-tool", methods=['GET', 'POST'])
|
||||||
|
def balanceTool():
|
||||||
|
positions=["Top", "Jungle", "Mid", "Bottom", "Support"]
|
||||||
|
|
||||||
|
#db = DatabaseConnection(app.config["DB_PATH"])
|
||||||
|
|
||||||
|
if flask.request.method == 'POST':
|
||||||
|
|
||||||
|
players = []
|
||||||
|
threshold = 0.7
|
||||||
|
for k,v in flask.request.json.items():
|
||||||
|
if k == "acceptable-solution-threshold":
|
||||||
|
threshold = v
|
||||||
|
continue
|
||||||
|
for i in range(5):
|
||||||
|
if v[i] in positions:
|
||||||
|
v[i] = 5
|
||||||
|
else:
|
||||||
|
v[i] = int(v[i])
|
||||||
|
p = Player(k, v)
|
||||||
|
players += [p]
|
||||||
|
|
||||||
|
# theoretical minnimum #
|
||||||
|
theoMin = sum([ min(p.prio) for p in players ])
|
||||||
|
|
||||||
|
permutations = itertools.permutations(players)
|
||||||
|
|
||||||
|
best = 100
|
||||||
|
bestOption = None
|
||||||
|
alternateOptions = []
|
||||||
|
alternateOptionsAboveThreshold = []
|
||||||
|
for option in permutations:
|
||||||
|
|
||||||
|
cur = 0
|
||||||
|
|
||||||
|
for i in range(len(option)):
|
||||||
|
cur += option[i].prio[i%5]
|
||||||
|
|
||||||
|
if theoMin/cur > threshold:
|
||||||
|
alternateOptionsAboveThreshold.append(list(option))
|
||||||
|
|
||||||
|
qualityCur = int(theoMin/cur*100)
|
||||||
|
if cur < best:
|
||||||
|
best = cur
|
||||||
|
bestOption = list(option)
|
||||||
|
alternateOptions = []
|
||||||
|
alternateOptions.append(list(option))
|
||||||
|
print("Option Found Quality: {}%".format(str(qualityCur)))
|
||||||
|
elif cur == best or qualityCur > threshold*100:
|
||||||
|
alternateOptions.append(list(option))
|
||||||
|
|
||||||
|
alternateOptions += alternateOptionsAboveThreshold
|
||||||
|
retDict = { "left" : {}, "right" : {} }
|
||||||
|
bestOption = list(bestOption)
|
||||||
|
if len(bestOption) < 10:
|
||||||
|
for x in range(10-len(bestOption)):
|
||||||
|
bestOption += [Player("", [0,0,0,0,0])]
|
||||||
|
for o in alternateOptions:
|
||||||
|
for x in range(10-len(o)):
|
||||||
|
o += [Player("", [0,0,0,0,0])]
|
||||||
|
|
||||||
|
# fix options with rating #
|
||||||
|
bestOptionWithRating = None
|
||||||
|
bestOptionRatings = None
|
||||||
|
|
||||||
|
# alternate options rundown positional diff #
|
||||||
|
posCurrDiff = 100000
|
||||||
|
for o in alternateOptions:
|
||||||
|
firstHalf = o[:5]
|
||||||
|
secondHalf = o[5:]
|
||||||
|
|
||||||
|
firstHalfVal = [0, 0, 0, 0, 0]
|
||||||
|
secondHalfVal = [0, 0, 0, 0, 0]
|
||||||
|
|
||||||
|
countFirstHalf = 0
|
||||||
|
for pil in firstHalf:
|
||||||
|
if pil:
|
||||||
|
firstHalfVal[countFirstHalf] = api.getPlayerRatingFromApi(pil.name, WATCHER)
|
||||||
|
#print(pil.name, firstHalfVal[countFirstHalf])
|
||||||
|
countFirstHalf += 1
|
||||||
|
|
||||||
|
countSecondHalf = 0
|
||||||
|
for pil in secondHalf:
|
||||||
|
if pil:
|
||||||
|
secondHalfVal[countSecondHalf] = api.getPlayerRatingFromApi(pil.name, WATCHER)
|
||||||
|
#print(pil.name, secondHalfVal[countSecondHalf])
|
||||||
|
countSecondHalf += 1
|
||||||
|
|
||||||
|
posDiff = abs(statistics.median(firstHalfVal) - statistics.median(secondHalfVal))
|
||||||
|
|
||||||
|
# check if posdiff is better #
|
||||||
|
if posDiff < posCurrDiff:
|
||||||
|
bestOptionWithRating = o
|
||||||
|
bestOptionRatings = firstHalfVal + secondHalfVal
|
||||||
|
qualityRatings = -1
|
||||||
|
|
||||||
|
# find the best permutation of this solution #
|
||||||
|
for i in range(0,5):
|
||||||
|
teamDiff = abs(sum(firstHalfVal) - sum(secondHalfVal))
|
||||||
|
|
||||||
|
# first flip
|
||||||
|
tmp = firstHalfVal[i]
|
||||||
|
firstHalfVal[i] = secondHalfVal[i]
|
||||||
|
secondHalfVal[i] = tmp
|
||||||
|
teamDiffNew = abs(sum(firstHalfVal) - sum(secondHalfVal))
|
||||||
|
|
||||||
|
# if new is not better #
|
||||||
|
if not (teamDiffNew < teamDiff):
|
||||||
|
# flip it back #
|
||||||
|
tmp = firstHalfVal[i]
|
||||||
|
firstHalfVal[i] = secondHalfVal[i]
|
||||||
|
secondHalfVal[i] = tmp
|
||||||
|
# else flip the names too #
|
||||||
|
else:
|
||||||
|
tmp = firstHalf[i]
|
||||||
|
firstHalf[i] = secondHalf[i]
|
||||||
|
secondHalf[i] = tmp
|
||||||
|
# and reset the option #
|
||||||
|
bestOptionWithRating = firstHalf + secondHalf
|
||||||
|
bestOptionRatings = firstHalfVal + secondHalfVal
|
||||||
|
qualityRatings = min(sum(firstHalfVal)/sum(secondHalfVal),
|
||||||
|
sum(secondHalfVal)/sum(firstHalfVal))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
for i in range(5):
|
||||||
|
retDict["left"].update( { positions[i] : bestOptionWithRating[i].name })
|
||||||
|
retDict["right"].update({ positions[i] : bestOptionWithRating[i+5].name })
|
||||||
|
|
||||||
|
import sys
|
||||||
|
print(flask.request.json, file=sys.stderr)
|
||||||
|
print(retDict, file=sys.stderr)
|
||||||
|
renderContent = flask.render_template("balance_response_partial.html", d=retDict,
|
||||||
|
reqJson=flask.request.json,
|
||||||
|
positions=positions,
|
||||||
|
ratings=bestOptionRatings,
|
||||||
|
qualityPositions=int(theoMin/best*100),
|
||||||
|
qualityRatings=int(qualityRatings*100))
|
||||||
|
return flask.Response(
|
||||||
|
json.dumps({ "content": renderContent }), 200, mimetype='application/json')
|
||||||
|
else:
|
||||||
|
givenIdent = flask.request.args.get("id")
|
||||||
|
if givenIdent:
|
||||||
|
ident = givenIdent
|
||||||
|
else:
|
||||||
|
ident = secrets.token_urlsafe(16)
|
||||||
|
return flask.redirect("/balance-tool?id={}".format(ident))
|
||||||
|
return flask.render_template("json_builder.html",
|
||||||
|
positions=positions,
|
||||||
|
sides=["left", "right"],
|
||||||
|
ident=ident)
|
||||||
|
@app.route("/get-cache")
|
||||||
|
def getCacheLoc():
|
||||||
|
return (json.dumps(api.getCache()), 200)
|
||||||
|
|
||||||
|
@app.route("/player-api")
|
||||||
|
def playerApi():
|
||||||
|
result = api.getPlayerRatingFromApi(flask.request.args.get("id"), WATCHER)
|
||||||
|
if result:
|
||||||
|
return ("OK", 200)
|
||||||
|
else:
|
||||||
|
return ("Nope", 404)
|
||||||
|
|
||||||
|
@app.route("/player-api-cache")
|
||||||
|
def playerApiCache():
|
||||||
|
result = api.checkPlayerKnown(flask.request.args.get("id"))
|
||||||
|
if result and result[1] != 0:
|
||||||
|
return ("OK", 200)
|
||||||
|
else:
|
||||||
|
return ("Nope", 404)
|
||||||
|
|
||||||
@app.route("/player")
|
@app.route("/player")
|
||||||
def player():
|
def player():
|
||||||
'''Show Info about Player'''
|
'''Show Info about Player'''
|
||||||
@@ -161,29 +389,16 @@ def player():
|
|||||||
minRating = 3000
|
minRating = 3000
|
||||||
maxRating = 0
|
maxRating = 0
|
||||||
|
|
||||||
# data for medals #
|
|
||||||
medalsRatingList = []
|
|
||||||
|
|
||||||
if histData:
|
if histData:
|
||||||
datapoints = histData[playerId]
|
datapoints = histData[playerId]
|
||||||
if datapoints:
|
if datapoints:
|
||||||
|
|
||||||
tickCounter = 10
|
tickCounter = 10
|
||||||
for dpk in datapoints.keys():
|
for dpk in datapoints.keys():
|
||||||
|
|
||||||
# timestamp #
|
|
||||||
t = datetime.datetime.fromtimestamp(int(float(dpk)))
|
t = datetime.datetime.fromtimestamp(int(float(dpk)))
|
||||||
tsMs = str(int(t.timestamp() * 1000))
|
tsMs = str(int(t.timestamp() * 1000))
|
||||||
|
ratingString = str(int(datapoints[dpk]["mu"]) - 2*int(datapoints[dpk]["sigma"]))
|
||||||
computedRating = int(datapoints[dpk]["mu"]) - 2*int(datapoints[dpk]["sigma"])
|
|
||||||
|
|
||||||
# for medals #
|
|
||||||
medalsRatingList += [computedRating]
|
|
||||||
|
|
||||||
# for moment js #
|
|
||||||
ratingString = str(computedRating)
|
|
||||||
ratingAmored = '{ x : ' + tsMs + ', y : ' + ratingString + '}'
|
ratingAmored = '{ x : ' + tsMs + ', y : ' + ratingString + '}'
|
||||||
|
|
||||||
csv_timestamps += [str(tsMs)]
|
csv_timestamps += [str(tsMs)]
|
||||||
csv_ratings += [ratingAmored]
|
csv_ratings += [ratingAmored]
|
||||||
|
|
||||||
@@ -197,19 +412,16 @@ def player():
|
|||||||
|
|
||||||
yMin, yMax = prettifyMinMaxY(minRating, maxRating)
|
yMin, yMax = prettifyMinMaxY(minRating, maxRating)
|
||||||
|
|
||||||
medalsList = medals.getMedals(medalsRatingList, player.games, player.rating)
|
|
||||||
|
|
||||||
# change displayed rank to start from 1 :)
|
# change displayed rank to start from 1 :)
|
||||||
player.rank += 1
|
player.rank += 1
|
||||||
|
|
||||||
return flask.render_template("player.html", player=player, CSV_RATINGS=",".join(csv_ratings),
|
return flask.render_template("player.html", player=player, CSV_RATINGS=",".join(csv_ratings),
|
||||||
CSV_MONTH_YEAR_OF_RATINGS=",".join(csv_month_year),
|
CSV_MONTH_YEAR_OF_RATINGS=",".join(csv_month_year),
|
||||||
CSV_TIMESTAMPS=csv_timestamps,
|
CSV_TIMESTAMPS=csv_timestamps,
|
||||||
Y_MIN=yMin, Y_MAX=yMax, medals=medalsList)
|
Y_MIN=yMin, Y_MAX=yMax)
|
||||||
|
|
||||||
@app.route('/leaderboard')
|
@app.route('/leaderboard')
|
||||||
@app.route('/')
|
@cache.cached(timeout=10, query_string=True)
|
||||||
@cache.cached(timeout=600, query_string=True)
|
|
||||||
def leaderboard():
|
def leaderboard():
|
||||||
'''Show main leaderboard page with range dependant on parameters'''
|
'''Show main leaderboard page with range dependant on parameters'''
|
||||||
|
|
||||||
@@ -264,6 +476,7 @@ def leaderboard():
|
|||||||
if end > maxEntry:
|
if end > maxEntry:
|
||||||
start = maxEntry - ( maxEntry % SEGMENT ) - 1
|
start = maxEntry - ( maxEntry % SEGMENT ) - 1
|
||||||
end = maxEntry - 1
|
end = maxEntry - 1
|
||||||
|
print(maxEntry)
|
||||||
reachedEnd = True
|
reachedEnd = True
|
||||||
|
|
||||||
playerList = db.getRankRange(start, end)
|
playerList = db.getRankRange(start, end)
|
||||||
@@ -277,11 +490,11 @@ def leaderboard():
|
|||||||
if maxEntry <= 100:
|
if maxEntry <= 100:
|
||||||
start = max(start, 0)
|
start = max(start, 0)
|
||||||
|
|
||||||
finalResponse = flask.render_template("base.html", playerList=playerList,
|
finalResponse = flask.render_template("base.html", playerList=playerList, \
|
||||||
doNotComputeRank=doNotComputeRank,
|
doNotComputeRank=doNotComputeRank, \
|
||||||
start=start,
|
start=start, \
|
||||||
endOfBoardIndicator=endOfBoardIndicator,
|
endOfBoardIndicator=endOfBoardIndicator, \
|
||||||
findPlayer=cannotFindPlayer,
|
findPlayer=cannotFindPlayer, \
|
||||||
searchName=searchName,
|
searchName=searchName,
|
||||||
nextPageNumber=int(pageInt)+1,
|
nextPageNumber=int(pageInt)+1,
|
||||||
prevPageNumber=int(pageInt)-1)
|
prevPageNumber=int(pageInt)-1)
|
||||||
@@ -289,35 +502,28 @@ def leaderboard():
|
|||||||
|
|
||||||
@app.route('/static/<path:path>')
|
@app.route('/static/<path:path>')
|
||||||
def send_js(path):
|
def send_js(path):
|
||||||
|
return send_from_directory('static', path)
|
||||||
|
|
||||||
response = send_from_directory('static', path)
|
@app.before_first_request
|
||||||
response.headers['Cache-Control'] = "max-age=2592000"
|
def init():
|
||||||
return response
|
|
||||||
|
|
||||||
|
global WATCHER
|
||||||
def create_app():
|
with open("key.txt","r") as f:
|
||||||
|
key = f.read().strip()
|
||||||
global SERVERS
|
WATCHER = riotwatcher.LolWatcher(key)
|
||||||
|
|
||||||
SERVERS_FILE = "servers.json"
|
|
||||||
if os.path.isfile(SERVERS_FILE):
|
|
||||||
with open(SERVERS_FILE) as f:
|
|
||||||
SERVERS = json.load(f)
|
|
||||||
|
|
||||||
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')
|
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')
|
help='Port on which flask (this server) will take requests on')
|
||||||
parser.add_argument('--skillbird-db', required=True,
|
|
||||||
help='skillbird database (overrides web connection if set)')
|
|
||||||
|
|
||||||
with app.app_context():
|
parser.add_argument('--skillbird-db', required=False, help='skillbird database (overrides web connection if set)')
|
||||||
create_app()
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
app.config["DB_PATH"] = args.skillbird_db
|
app.config["DB_PATH"] = args.skillbird_db
|
||||||
|
app.config["TEMPLATES_AUTO_RELOAD"] = True
|
||||||
app.run(host=args.interface, port=args.port)
|
app.run(host=args.interface, port=args.port)
|
||||||
|
|||||||
5
sqlite.init
Normal file
5
sqlite.init
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
CREATE TABLE players(
|
||||||
|
playerName TEXT PRIMARY KEY,
|
||||||
|
rating INTEGER,
|
||||||
|
lastupdated TEXT
|
||||||
|
);
|
||||||
300
static/balance.js
Normal file
300
static/balance.js
Normal file
@@ -0,0 +1,300 @@
|
|||||||
|
positions = [ "Top", "Jungle", "Mid", "Bottom", "Support" ]
|
||||||
|
acceptedParser = [ "top", "jungle", "mid", "sup" , "bot", "adc", "support", "bottom", "*" ]
|
||||||
|
sides = [ "left", "right"]
|
||||||
|
|
||||||
|
var checkPlayerFunc = function checkPlayer() {
|
||||||
|
if(this.value == ""){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
url = "/player-api-cache?id=" + this.value
|
||||||
|
fetch(url).then(r => {
|
||||||
|
if(r.status == 200){
|
||||||
|
this.style.background = "#74bb74"
|
||||||
|
}else{
|
||||||
|
this.style.background = "#d25252"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var checkPlayerApiFunc = function checkPlayer() {
|
||||||
|
if(this.value == ""){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
url = "/player-api?id=" + this.value
|
||||||
|
fetch(url).then(r => {
|
||||||
|
if(r.status == 200){
|
||||||
|
this.style.background = "#74bb74"
|
||||||
|
}else{
|
||||||
|
//this.style.background = "#d25252"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var fastPosChangedFunc = function fastPosChanged() {
|
||||||
|
|
||||||
|
accepted = [ "top", "jungle", "mid", "sup" , "bot" ]
|
||||||
|
uniqArr = []
|
||||||
|
prioArray = [5, 5, 5, 5, 5]
|
||||||
|
|
||||||
|
/* commence cleanup */
|
||||||
|
clean = this.value.replaceAll(" ", "").toLocaleLowerCase()
|
||||||
|
clean = clean.replace("support", "sup")
|
||||||
|
clean = clean.replace("adc", "bot")
|
||||||
|
clean = clean.replace("bottom", "bot")
|
||||||
|
|
||||||
|
retVal = true
|
||||||
|
if(clean.includes("<")){
|
||||||
|
console.log("Not accepted (includes <)")
|
||||||
|
retVal = false
|
||||||
|
}
|
||||||
|
|
||||||
|
list = clean.split(">")
|
||||||
|
cur = 1
|
||||||
|
list.forEach(el => {
|
||||||
|
if(el.includes("=")){
|
||||||
|
listEq = el.split("=")
|
||||||
|
listEq.forEach(sub => {
|
||||||
|
if(accepted.includes(sub) && !uniqArr.includes(sub)){
|
||||||
|
prioArray[accepted.indexOf(sub)] = cur
|
||||||
|
uniqArr += [sub]
|
||||||
|
}else{
|
||||||
|
console.log("Not accepted (=): " + sub)
|
||||||
|
retVal = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
cur++
|
||||||
|
}else{
|
||||||
|
if(accepted.includes(el) && !uniqArr.includes(el)){
|
||||||
|
prioArray[accepted.indexOf(el)] = cur
|
||||||
|
uniqArr += [el]
|
||||||
|
cur++
|
||||||
|
}else{
|
||||||
|
console.log("Not accepted (>): " + el)
|
||||||
|
retVal = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
for(i = 0; i<5; i++){
|
||||||
|
arr = this.id.split("-")
|
||||||
|
pNr = arr[arr.length-1]
|
||||||
|
side = this.id.includes("left") ? "left" : "right"
|
||||||
|
|
||||||
|
roleSubmission = document.getElementById("fastpos-submission")
|
||||||
|
if(roleSubmission){
|
||||||
|
string = "prio_" + accepted[i]
|
||||||
|
}else {
|
||||||
|
string = "prio-" + side + "-" + accepted[i] + "-" + pNr
|
||||||
|
}
|
||||||
|
|
||||||
|
string = string.replace("top","Top")
|
||||||
|
string = string.replace("jungle","Jungle")
|
||||||
|
string = string.replace("mid","Mid")
|
||||||
|
string = string.replace("sup","Support")
|
||||||
|
string = string.replace("bot","Bottom")
|
||||||
|
|
||||||
|
selector = document.getElementById(string)
|
||||||
|
selector.value = prioArray[i]
|
||||||
|
selector.style.background = "lightblue"
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allow some basic shit */
|
||||||
|
if(clean == "*" || clean == ""){
|
||||||
|
retVal = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if(retVal){
|
||||||
|
this.style.background = "#74bb74"
|
||||||
|
}else{
|
||||||
|
this.style.background = "#d25252"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function balance(){
|
||||||
|
|
||||||
|
cont = document.getElementById("response-container")
|
||||||
|
cont.innerHTML = ""
|
||||||
|
cont.style.color = "black";
|
||||||
|
sides = ["left", "right"]
|
||||||
|
|
||||||
|
blue = [ "", "", "", "", ""]
|
||||||
|
red = [ "", "", "", "", ""]
|
||||||
|
|
||||||
|
dictToBeSorted = {
|
||||||
|
0 : [],
|
||||||
|
1 : [],
|
||||||
|
2 : [],
|
||||||
|
3 : [],
|
||||||
|
4 : []
|
||||||
|
}
|
||||||
|
filler = []
|
||||||
|
impossible = []
|
||||||
|
|
||||||
|
dictAll = {}
|
||||||
|
for(sid = 0; sid < 2; sid++){
|
||||||
|
for(id = 0; id < 5; id++){
|
||||||
|
|
||||||
|
var pname = "undef"
|
||||||
|
var prioList = [5, 5, 5, 5, 5]
|
||||||
|
|
||||||
|
stringPid = `playername-${sides[sid]}-${id}`
|
||||||
|
pnameObj = document.getElementById(stringPid)
|
||||||
|
pname = pnameObj.value
|
||||||
|
for(acc = 0; acc < 5; acc++){
|
||||||
|
stringSelectorId = `prio-${sides[sid]}-${positions[acc]}-${id}`
|
||||||
|
selObj = document.getElementById(stringSelectorId)
|
||||||
|
prioList[acc] = selObj.value
|
||||||
|
}
|
||||||
|
|
||||||
|
dictAll[pname] = prioList
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
prioBalanceCheckbox = document.getElementById("prio-balance")
|
||||||
|
if(prioBalanceCheckbox.checked){
|
||||||
|
dictAll["acceptable-solution-threshold"] = 0.5
|
||||||
|
}else{
|
||||||
|
dictAll["acceptable-solution-threshold"] = 0.7
|
||||||
|
}
|
||||||
|
jsonData = JSON.stringify(dictAll, null, 4);
|
||||||
|
|
||||||
|
/* transmitt */
|
||||||
|
spinner = document.getElementById("loading")
|
||||||
|
spinner.style.display = "block";
|
||||||
|
fetch(window.location.href, {
|
||||||
|
method: 'post',
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json, text/plain, */*',
|
||||||
|
'Content-Type': 'application/json' },
|
||||||
|
body: jsonData
|
||||||
|
}).then(r => r.json()).then(j => {
|
||||||
|
spinner.style.display = "none";
|
||||||
|
cont.innerHTML = j["content"]
|
||||||
|
}).catch(err => {
|
||||||
|
spinner.style.display = "none";
|
||||||
|
cont.style.color = "red";
|
||||||
|
cont.innerHTML = "Error - request failed."
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseMultiline(){
|
||||||
|
|
||||||
|
var names = []
|
||||||
|
var prioStrings = []
|
||||||
|
|
||||||
|
field = document.getElementById("multi-line-copy")
|
||||||
|
lines = field.value.split("\n")
|
||||||
|
lines.forEach(l => {
|
||||||
|
|
||||||
|
lowestIndex = 100
|
||||||
|
|
||||||
|
acceptedParser.forEach( p => {
|
||||||
|
i = l.indexOf(" " + p)
|
||||||
|
if(i >= 3 && i < lowestIndex){
|
||||||
|
lowestIndex = i
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if(lowestIndex != 100){
|
||||||
|
name = l.substring(0, lowestIndex)
|
||||||
|
prioStr = l.substring(lowestIndex)
|
||||||
|
names.push(name)
|
||||||
|
prioStrings.push(prioStr)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
count = 0
|
||||||
|
sides.forEach(s => {
|
||||||
|
for(i = 0; i<5; i++){
|
||||||
|
|
||||||
|
pObjField = document.getElementById("playername-" + s + "-" + i)
|
||||||
|
prObjField = document.getElementById("check-" + s + "-fastpos-" + i)
|
||||||
|
|
||||||
|
if(count >= names.length){
|
||||||
|
pObjField.value = ""
|
||||||
|
prObjField.value = ""
|
||||||
|
}else{
|
||||||
|
pObjField.value = names[count]
|
||||||
|
prObjField.value = prioStrings[count]
|
||||||
|
}
|
||||||
|
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const inputEvent = new Event("input")
|
||||||
|
fastPosFields.forEach(el => el.dispatchEvent(inputEvent))
|
||||||
|
balance()
|
||||||
|
}
|
||||||
|
|
||||||
|
function queryForPlayerData(){
|
||||||
|
ident = document.getElementById("ident-field").innerHTML
|
||||||
|
fetch("/balance-tool-data?id=" + ident).then(r => r.json()).then(j => {
|
||||||
|
if("no-data" in j){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
j["submissions"].forEach(el => {
|
||||||
|
console.log(el)
|
||||||
|
breakToSubmissions = false
|
||||||
|
for(sid = 0; sid < 2; sid++){
|
||||||
|
if(breakToSubmissions){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for(id = 0; id < 5; id++){
|
||||||
|
stringPid = `playername-${sides[sid]}-${id}`
|
||||||
|
pnameObj = document.getElementById(stringPid)
|
||||||
|
if(pnameObj.value == "" || pnameObj.value == el["name"]){
|
||||||
|
pnameObj.value = el["name"]
|
||||||
|
for(acc = 0; acc < 5; acc++){
|
||||||
|
stringSelectorId = `prio-${sides[sid]}-${positions[acc]}-${id}`
|
||||||
|
selObj = document.getElementById(stringSelectorId)
|
||||||
|
selObj.value = el[positions[acc]]
|
||||||
|
}
|
||||||
|
breakToSubmissions = true
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function copy() {
|
||||||
|
|
||||||
|
ident = document.getElementById("ident-field").innerHTML
|
||||||
|
path = "/role-submission?id="
|
||||||
|
copyText = window.location.protocol + "//" + window.location.hostname + path + ident
|
||||||
|
|
||||||
|
navigator.clipboard.writeText(copyText)
|
||||||
|
document.getElementById("copyLink").innerHTML = "Copied!"
|
||||||
|
setTimeout(() => {
|
||||||
|
document.getElementById("copyLink").innerHTML = "Copy Submission Link" }, 500);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fastPosFields = document.getElementsByClassName("fastpos")
|
||||||
|
playerNameFields = document.getElementsByClassName("pname")
|
||||||
|
|
||||||
|
playerNameFields.forEach(el => el.addEventListener('input', checkPlayerFunc));
|
||||||
|
playerNameFields.forEach(el => el.addEventListener('focus', checkPlayerFunc));
|
||||||
|
|
||||||
|
fastPosFields.forEach(el => el.addEventListener('input', fastPosChangedFunc));
|
||||||
|
//fastPosFields.forEach(el => el.addEventListener('focus', fastPosChangedFunc));
|
||||||
|
|
||||||
|
fastposSubmission = document.getElementById("fastpos-submission")
|
||||||
|
if(fastposSubmission){
|
||||||
|
fastposSubmission.addEventListener("input", fastPosChangedFunc)
|
||||||
|
fastposSubmission.addEventListener("focus", fastPosChangedFunc)
|
||||||
|
}
|
||||||
|
setInterval(queryForPlayerData(), 3000)
|
||||||
|
|
||||||
|
formContainer = document.getElementById("form-container")
|
||||||
|
if(formContainer){
|
||||||
|
//formContainer.reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetAll(){
|
||||||
|
formContainer = document.getElementById("form-container")
|
||||||
|
formContainer.reset()
|
||||||
|
}
|
||||||
@@ -8,6 +8,12 @@ body{
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.border-special{
|
||||||
|
border-style: outset;
|
||||||
|
border-width: 0.2px;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
.top-bar{
|
.top-bar{
|
||||||
background-color: orange;
|
background-color: orange;
|
||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
@@ -217,6 +223,7 @@ body{
|
|||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.footerLink{
|
.footerLink{
|
||||||
@@ -240,6 +247,7 @@ body{
|
|||||||
.footerLink{
|
.footerLink{
|
||||||
font-size: 4vw;
|
font-size: 4vw;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mid{
|
.mid{
|
||||||
margin-left: 2.5%;
|
margin-left: 2.5%;
|
||||||
margin-right: 2.5%;
|
margin-right: 2.5%;
|
||||||
@@ -256,11 +264,3 @@ body{
|
|||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes fadeIn {
|
|
||||||
from { opacity: 0.3; }
|
|
||||||
}
|
|
||||||
|
|
||||||
.animate-flicker {
|
|
||||||
animation: fadeIn 2s alternate;
|
|
||||||
}
|
|
||||||
|
|||||||
41
templates/balance_response_partial.html
Normal file
41
templates/balance_response_partial.html
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
<div class="my-3">
|
||||||
|
<h3> Suggestion </h3>
|
||||||
|
<p>Postion Wishes: {{ qualityPositions }}% fullfilled /
|
||||||
|
Teambalance: {{ qualityRatings }}% </p>
|
||||||
|
</div>
|
||||||
|
{% for x in range(5) %}
|
||||||
|
<div class="row">
|
||||||
|
{% set leftP = d["left"][positions[x]] %}
|
||||||
|
{% set rightP = d["right"][positions[x]] %}
|
||||||
|
<div class="col-sm">
|
||||||
|
{{ positions[x] }}
|
||||||
|
</div>
|
||||||
|
<div class="col-sm"
|
||||||
|
{% if reqJson.get(leftP) and reqJson.get(leftP)[x] | int >= 4 %}
|
||||||
|
style="background: red;"
|
||||||
|
{% endif %}>
|
||||||
|
{{ leftP }} ({{ ratings[x] }})
|
||||||
|
</div>
|
||||||
|
<div class="col-sm"
|
||||||
|
{% if reqJson.get(rightP) and reqJson.get(rightP)[x] | int >= 4 %}
|
||||||
|
style="background: red;"
|
||||||
|
{% endif %}>
|
||||||
|
{{ rightP }} ({{ ratings[x+5] }})
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
<div class="mt-3">
|
||||||
|
<h3>For copying into Lobby:</h3>
|
||||||
|
<div class="mt-2">
|
||||||
|
<div class="row">
|
||||||
|
<textarea style="padding-left: 10px !important; padding-top: 10px !important" rows="16" cols= 100>
|
||||||
|
Left Side Team
|
||||||
|
{% for x in range(5) %}
|
||||||
|
{% set leftP = d["left"][positions[x]] %}{{ leftP }} left team {{ positions[x] }}{% endfor %}
|
||||||
|
|
||||||
|
Right Side Team
|
||||||
|
{% for x in range(5) %}
|
||||||
|
{% set rightP = d["right"][positions[x]] %}{{ rightP }} right team {{ positions[x] }}{% endfor %}
|
||||||
|
</textarea>
|
||||||
|
</div>
|
||||||
@@ -10,29 +10,6 @@
|
|||||||
{% include 'navbar_leaderboard.html' %}
|
{% include 'navbar_leaderboard.html' %}
|
||||||
|
|
||||||
<div class="container mt-3 mb-3" role="main">
|
<div class="container mt-3 mb-3" role="main">
|
||||||
<div id="playerDisplay" class="playerDisplay mb-3 mt-2">
|
|
||||||
<script>
|
|
||||||
function players(){
|
|
||||||
//document.getElementById("playerDisplay").classList.remove("animate-flicker")
|
|
||||||
fetch("/players-online").then(
|
|
||||||
response => response.json()
|
|
||||||
).then(
|
|
||||||
data => {
|
|
||||||
if(data["error"] == ""){
|
|
||||||
document.getElementById("playerDisplay").innerHTML = "Players Online: " + data["player_total"]
|
|
||||||
if(parseInt(data["player_total"]) == 0){
|
|
||||||
//document.getElementById("playerDisplay").classList.add("animate-flicker")
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
document.getElementById("playerDisplay").innerHTML = "Players Online: (error)" + data["error"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
players()
|
|
||||||
setInterval(players, 10000)
|
|
||||||
</script>
|
|
||||||
</div>
|
|
||||||
<table id="tableMain" class="table table-striped table-bordered table-sm"
|
<table id="tableMain" class="table table-striped table-bordered table-sm"
|
||||||
cellspacing="0">
|
cellspacing="0">
|
||||||
<thead>
|
<thead>
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<div class="footer-copyright text-center py-3 bg-dark" role="contentinfo">
|
<div class="footer-copyright text-center py-3 bg-dark" role="contentinfo">
|
||||||
<a style="color: rgba(255,255,255,.5);"
|
<a style="color: rgba(255,255,255,.5);"
|
||||||
class="footerLink" href="https://blog.atlantishq.de/about">Impressum/Legal</a>
|
class="footerLink" href="https://atlantishq.de/impressum">Impressum/Legal</a>
|
||||||
<a style="color: rgba(255,255,255,.5);"
|
<a style="color: rgba(255,255,255,.5);"
|
||||||
class="footerLink mid" href="steam://connect/athq.de/:27026">
|
class="footerLink mid" href="https://esports-erlangen.de">
|
||||||
Join the Server!</a>
|
ESE Website</a>
|
||||||
<a style="color: rgba(255,255,255,.5);"
|
<a style="color: rgba(255,255,255,.5);"
|
||||||
class="footerLink" href="https://github.com/FAUSheppy/skillbird">Star on GitHub</a>
|
class="footerLink" href="https://github.com/FAUSheppy/skillbird">Star on GitHub</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
150
templates/json_builder.html
Normal file
150
templates/json_builder.html
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<title>Balance and Submission Tool</title>
|
||||||
|
<meta name="Description" content="Sheppy is awesome?">
|
||||||
|
<script defer src="/static/balance.js"></script>
|
||||||
|
{% include 'default_head_content.html' %}
|
||||||
|
</head>
|
||||||
|
<body class="bg-special">
|
||||||
|
{% include 'navbar.html' %}
|
||||||
|
<div id="ident-field" style="display: none;">{{ ident }}</div>
|
||||||
|
<div class="container mt-3 mb-3" role="main">
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm">
|
||||||
|
<h1>Balance Tool</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<button type="button" class="mb-3 btn btn-secondary" onclick="balance()">
|
||||||
|
Find Teams
|
||||||
|
</button>
|
||||||
|
</br>
|
||||||
|
<button id="copyLink" type="button"
|
||||||
|
class="mb-3 btn btn-secondary" onclick="copy()">
|
||||||
|
Copy Submission Link
|
||||||
|
</button>
|
||||||
|
<button type="button"
|
||||||
|
class="mb-3 btn btn-secondary" onclick="queryForPlayerData()">
|
||||||
|
Check Submissions
|
||||||
|
</button>
|
||||||
|
</br>
|
||||||
|
{% if True %}
|
||||||
|
<button class="btn btn-primary" type="button" data-toggle="collapse"
|
||||||
|
data-target="#hilfe" aria-expanded="false"
|
||||||
|
aria-controls="hilfe">
|
||||||
|
Hilfe Anzeigen
|
||||||
|
</button>
|
||||||
|
<button type="button"
|
||||||
|
class="mb-3 btn btn-secondary" onclick="resetAll()">
|
||||||
|
Reset all
|
||||||
|
</button></br>
|
||||||
|
|
||||||
|
<div style="display: none;" class="form-check mt-3">
|
||||||
|
<input class="form-check-input" type="checkbox" value=""
|
||||||
|
id="prio-balance">
|
||||||
|
<label class="form-check-label" for="flexCheckChecked">
|
||||||
|
Prioritize balance over positional preferences
|
||||||
|
<p style="color: red;">(experimental, slow af)</p>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="hilfe" class="collapse mt-5 border-special">
|
||||||
|
<h4>Priorität</h4>
|
||||||
|
<p>
|
||||||
|
1 = höchste Priorität
|
||||||
|
5 = niedrigste Priorität
|
||||||
|
</p>
|
||||||
|
<hr class="my-3">
|
||||||
|
<h4>Fast Position</h4>
|
||||||
|
<p>
|
||||||
|
<b>Positionen können in den Kurzschreibweisen: top, mid, bot, jungle, support mit "=" und ">" angegeben werden. Zum Beispiel:</b></br></br>
|
||||||
|
top > mid > top = adc</br>
|
||||||
|
mid = top > bot</br>
|
||||||
|
support > jungle</br>
|
||||||
|
etc..</br>
|
||||||
|
</p>
|
||||||
|
<hr class="my-3">
|
||||||
|
<h4>Submission Link</h4>
|
||||||
|
<p>
|
||||||
|
Mit diesem Link können Spieler eine Positionspräferenz selbst übermitteln, einfach diesen Link in den Chat pasten.
|
||||||
|
</p>
|
||||||
|
<hr class="my-3">
|
||||||
|
<h4>Find Teams</h4>
|
||||||
|
<p>
|
||||||
|
Sobald alle eingetragen sind einmal auf "Find Teams" klicken und auf den Vorschlag warten.
|
||||||
|
</p>
|
||||||
|
<hr class="my-3">
|
||||||
|
<h4>Multiline Input</h4>
|
||||||
|
<p>
|
||||||
|
Jeder Kann seine Rollen im Schnellformat in den Chat schreiben, in das Feld unten kopieren und Button drücken (überschreibt existierende Einträge).
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="spinner-border" id="loading" style="display: none;" role="status">
|
||||||
|
<span class="sr-only">Loading...</span>
|
||||||
|
</div>
|
||||||
|
<div id="response-container" class="mt-3 mb-3">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
|
||||||
|
<form id="form-container" class="row">
|
||||||
|
{% for side in sides %}
|
||||||
|
<div class="col-sm">
|
||||||
|
{% for field in range(5) %}
|
||||||
|
<div id="{{ side }}-{{ field }}" class="row mt-2 mb-2">
|
||||||
|
<div class="col-sm">
|
||||||
|
|
||||||
|
<!-- player name field -->
|
||||||
|
<input class="form-control pname" type="text" placeholder="Player"
|
||||||
|
id="playername-{{ side }}-{{ field }}">
|
||||||
|
|
||||||
|
<!-- fast postition slection field -->
|
||||||
|
<input class="form-control fastpos" type="text"
|
||||||
|
placeholder="top > mid = bot"
|
||||||
|
id="check-{{ side }}-fastpos-{{ field }}">
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="col-sm">
|
||||||
|
<!-- checkboxes for pos -->
|
||||||
|
{% for pos in positions %}
|
||||||
|
<select id="prio-{{ side }}-{{ pos }}-{{ field }}"
|
||||||
|
class="form-select">
|
||||||
|
<option selected>{{ pos }}</option>
|
||||||
|
<option value="1">1</option>
|
||||||
|
<option value="2">2</option>
|
||||||
|
<option value="3">3</option>
|
||||||
|
<option value="4">4</option>
|
||||||
|
<option value="5">5</option>
|
||||||
|
</select>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</form>
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<textarea type="text" id="multi-line-copy" rows="10"
|
||||||
|
placeholder="Have everybody write their roles in the form of 'top > mid = sup = jungle >adc' in the chat and then copy it in here and hit 'Use Multiline Input' :)"
|
||||||
|
class="form-control md-textarea"></textarea>
|
||||||
|
<button type="button" class="mb-3 btn btn-secondary" onclick="parseMultiline()">
|
||||||
|
Use Multiline Input..
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
</div>
|
||||||
|
{% include 'footer.html' %}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -10,28 +10,13 @@
|
|||||||
<!-- left side -->
|
<!-- left side -->
|
||||||
<ul class="navbar-nav mr-auto">
|
<ul class="navbar-nav mr-auto">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/">Leaderboard</a>
|
<a class="nav-link" href="/">New Balance</a>
|
||||||
</li>
|
</li>
|
||||||
|
<!--
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/rounds">Rounds</a>
|
<a class="nav-link" href="/rounds">Rounds</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
-->
|
||||||
<a class="nav-link" href="/maps">Maps</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<ul class="navbar-nav right">
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="steam://connect/athq.de/:27026">Server 1</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item mr-4">
|
|
||||||
<a class="nav-link" href="steam://connect/athq.de/:27015">Server 2</a>
|
|
||||||
</li>
|
|
||||||
<!--
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="navbar-brand hover-to-75 patreon" style="position: unset !important;" href="https://www.patreon.com/erlangen_sheppy">Support me
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
-->
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|||||||
@@ -18,10 +18,8 @@
|
|||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a id="button-forward" class="nav-link" href="/?page={{ nextPageNumber }}">Forward</a>
|
<a id="button-forward" class="nav-link" href="/?page={{ nextPageNumber }}">Forward</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" {% if not gameInProgress %} style="opacity: 0.5" {% endif %}>
|
<li class="nav-item">
|
||||||
<a id="button-forward" class="nav-link" href="/livegames">Livegames
|
<a id="button-forward" class="nav-link" href="/balance-tool">Balance Tool</a>
|
||||||
<div style="font-size: small; color: red; opacity: 1; float: right; margin-left: 10px;">(experimental)</div>
|
|
||||||
</a>
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<ul class="navbar-nav">
|
<ul class="navbar-nav">
|
||||||
@@ -33,15 +31,12 @@
|
|||||||
<li class="nav-item right mr-2">
|
<li class="nav-item right mr-2">
|
||||||
<a class="nav-link" href="/rounds">Rounds</a>
|
<a class="nav-link" href="/rounds">Rounds</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item right mr-2">
|
|
||||||
<a class="nav-link" href="/maps">Maps</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item right">
|
<li class="nav-item right">
|
||||||
<input id="getPlayer" type="text" aria-label="search for player" class="mt-1"
|
<input id="getPlayer" type="text" aria-label="search for player" class="mt-1"
|
||||||
placeholder="search player...">
|
placeholder="search player...">
|
||||||
</li>
|
</li>
|
||||||
{{ findPlayer }}
|
{{ findPlayer }}
|
||||||
<!--- <li class="nav-item right">
|
<!-- <li class="nav-item right">
|
||||||
<input id="gotoRank" type="number" aria-label="goto rank"
|
<input id="gotoRank" type="number" aria-label="goto rank"
|
||||||
placeholder="goto rank...">
|
placeholder="goto rank...">
|
||||||
</li> -->
|
</li> -->
|
||||||
|
|||||||
@@ -14,28 +14,17 @@
|
|||||||
</h1>
|
</h1>
|
||||||
<h3>
|
<h3>
|
||||||
Rating: <i>{{ player.rating }}</i> <br>
|
Rating: <i>{{ player.rating }}</i> <br>
|
||||||
{% if player.rank == 0 %}
|
|
||||||
<i><small>Missing {{ 10 - player.games }} placement games!</small></i>
|
|
||||||
{% elif not player.lastGame %}
|
|
||||||
<i><small>Must play a game again before being assigned a rank!</small></i>
|
|
||||||
{% else %}
|
|
||||||
Rank: {{ player.rank }}
|
Rank: {{ player.rank }}
|
||||||
{%endif%}
|
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="plot-container">
|
<div class="plot-container">
|
||||||
<canvas id="lineChart">
|
<canvas id="lineChart">
|
||||||
</canvas>
|
</canvas>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-3 medal-container">
|
|
||||||
{% for m in medals %}
|
|
||||||
{{ m }}
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
<p class="mt-5 mb-3">
|
<p class="mt-5 mb-3">
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<!-- {% include 'footer.html' %}-->
|
{% include 'footer.html' %}
|
||||||
<script defer>
|
<script defer>
|
||||||
var canvas = document.getElementById("lineChart")
|
var canvas = document.getElementById("lineChart")
|
||||||
var ctx = canvas.getContext('2d');
|
var ctx = canvas.getContext('2d');
|
||||||
|
|||||||
70
templates/role_submission.html
Normal file
70
templates/role_submission.html
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<title>Balance and Submission Tool</title>
|
||||||
|
<meta name="Description" content="Sheppy is awesome?">
|
||||||
|
<script defer src="/static/balance.js"></script>
|
||||||
|
{% include 'default_head_content.html' %}
|
||||||
|
</head>
|
||||||
|
<body class="bg-special">
|
||||||
|
{% include 'navbar.html' %}
|
||||||
|
<div class="container mt-3 mb-3" role="main">
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm">
|
||||||
|
<h1>Role Preference Submission Tool</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- player name field -->
|
||||||
|
<form action="/role-submission?id={{ ident }}" method="POST">
|
||||||
|
<p style="color: red; font-weight: bold"> PLEASE USE YOUR _CORRECTLY SPELLED_ LoL-NAME!!</p>
|
||||||
|
<input class="form-control pname m-3" type="text" placeholder="Player"
|
||||||
|
name="playername" id="playername">
|
||||||
|
|
||||||
|
<!-- fast postition slection field -->
|
||||||
|
<input class="form-control fastpos m-3" type="text"
|
||||||
|
placeholder="Fast Position Input"
|
||||||
|
id="fastpos-submission">
|
||||||
|
|
||||||
|
<div class="col-sm m-3" style="min-width: 300px;">
|
||||||
|
<!-- checkboxes for pos -->
|
||||||
|
{% for pos in positions %}
|
||||||
|
<div>
|
||||||
|
<label style="min-width: 100px;"
|
||||||
|
for="prio_{{ pos }}">{{ pos }}</label>
|
||||||
|
<select name="prio_{{ pos }}" id="prio_{{ pos }}"
|
||||||
|
class="form-select ml-3 mr-3">
|
||||||
|
<option value="1">1</option>
|
||||||
|
<option value="2">2</option>
|
||||||
|
<option value="3">3</option>
|
||||||
|
<option value="4">4</option>
|
||||||
|
<option value="5">5</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<input type="submit" value="Submit">
|
||||||
|
|
||||||
|
<div class="mt-5">
|
||||||
|
<h4>Priorität</h4>
|
||||||
|
<p>
|
||||||
|
1 = höchste </br>
|
||||||
|
5 = niedrigste </br>
|
||||||
|
</p>
|
||||||
|
<hr class="my-3">
|
||||||
|
<h4>Fast-Position</h4>
|
||||||
|
<p>
|
||||||
|
<b>Positionen können in den Kurzschreibweisen: top, mid, bot, jungle, support mit "=" und ">" angegeben werden. Zum Beispiel:</b></br></br>
|
||||||
|
top > mid > top = adc</br>
|
||||||
|
mid = top > bot</br>
|
||||||
|
support > jungle</br>
|
||||||
|
etc..</br>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{% include 'footer.html' %}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -41,9 +41,6 @@
|
|||||||
<div class="col-sm" style="overflow: hidden;">
|
<div class="col-sm" style="overflow: hidden;">
|
||||||
<a href="/player?id={{ p.playerId }}">{{ p.name }}</a>
|
<a href="/player?id={{ p.playerId }}">{{ p.name }}</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm">
|
|
||||||
{{ p.participation }}%
|
|
||||||
</div>
|
|
||||||
<div class="col-sm">
|
<div class="col-sm">
|
||||||
{% if not r.invalid %}
|
{% if not r.invalid %}
|
||||||
<small style="color: green;">
|
<small style="color: green;">
|
||||||
@@ -60,9 +57,6 @@
|
|||||||
<div class="col-sm" style="overflow: hidden;">
|
<div class="col-sm" style="overflow: hidden;">
|
||||||
<a href="/player?id={{ p.playerId }}">{{ p.name }}</a>
|
<a href="/player?id={{ p.playerId }}">{{ p.name }}</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm">
|
|
||||||
{{ p.participation }}%
|
|
||||||
</div>
|
|
||||||
<div class="col-sm">
|
<div class="col-sm">
|
||||||
{% if not r.invalid %}
|
{% if not r.invalid %}
|
||||||
<small style="color: red;">
|
<small style="color: red;">
|
||||||
|
|||||||
Reference in New Issue
Block a user