Compare commits

12 Commits

Author SHA1 Message Date
6491afc272 add: req.txt
Some checks failed
Container Build for open-web-leaderboard / docker (push) Failing after 2s
2024-09-27 05:47:56 +02:00
756b24a447 add: build schedule 1/week 2024-09-27 05:44:39 +02:00
5f7713daaf docu: info about python-valve integration 2024-07-21 23:57:16 +02:00
ee14c3fd7e feat: add build & update to latest python 2024-07-21 23:49:12 +02:00
Yannik Schmidt
c32155fd40 fix typo in variable name 2022-03-07 01:32:57 +01:00
Yannik Schmidt
defcf5671d implement simple medals 2021-07-24 14:17:35 +02:00
2133249947 Merge branch 'master' of github.com:FAUSheppy/open-web-leaderboard 2021-07-24 13:25:42 +02:00
db3d2bb57e remove footer in player display 2021-07-24 13:25:29 +02:00
c5b7963fff improve livegame display 2021-07-24 13:25:20 +02:00
23fa7f9862 fade & whitespace 2021-07-24 13:24:31 +02:00
8f7b1b47ac add cache header to static 2021-07-24 13:23:05 +02:00
bdd7d9bf01 fix server player query 2021-03-25 17:52:32 +01:00
10 changed files with 222 additions and 34 deletions

34
.github/workflows/main.yaml vendored Normal file
View File

@@ -0,0 +1,34 @@
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 Normal file
View File

@@ -0,0 +1,13 @@
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"]

View File

@@ -33,6 +33,7 @@ Players can be blacklisted by name via a *blacklist.json* file in the project ro
}
# 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:
[

2
app.py
View File

@@ -1,3 +1,5 @@
import server
def createApp(envivorment=None, start_response=None):
with server.app.app_context():
server.create_app()
return server.app

93
medals.py Normal file
View File

@@ -0,0 +1,93 @@
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

4
req.txt Normal file
View File

@@ -0,0 +1,4 @@
python-valve
pytz
Flask-Caching
Flask

View File

@@ -1,4 +1,5 @@
#!/usr/bin/python3
import medals
import flask
import requests
import argparse
@@ -9,6 +10,8 @@ import os
import MapSummary
from database import DatabaseConnection
#import valve.source.a2s
#from valve.source import NoResponseError
app = flask.Flask("open-leaderboard")
@@ -39,8 +42,9 @@ def playersOnline():
for s in SERVERS:
try:
with valve.source.a2s.ServerQuerier((args.host, args.port)) as server:
playerTotal += int(server.info()["player_count"])
pass
#with valve.source.a2s.ServerQuerier((s["host"], s["port"])) as server:
# playerTotal += int(server.info()["player_count"])
except NoResponseError:
error = "Server Unreachable"
except Exception as e:
@@ -157,16 +161,29 @@ def player():
minRating = 3000
maxRating = 0
# data for medals #
medalsRatingList = []
if histData:
datapoints = histData[playerId]
if datapoints:
tickCounter = 10
for dpk in datapoints.keys():
# timestamp #
t = datetime.datetime.fromtimestamp(int(float(dpk)))
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 + '}'
csv_timestamps += [str(tsMs)]
csv_ratings += [ratingAmored]
@@ -180,13 +197,15 @@ def player():
yMin, yMax = prettifyMinMaxY(minRating, maxRating)
medalsList = medals.getMedals(medalsRatingList, player.games, player.rating)
# 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)
Y_MIN=yMin, Y_MAX=yMax, medals=medalsList)
@app.route('/leaderboard')
@app.route('/')
@@ -258,11 +277,11 @@ def leaderboard():
if maxEntry <= 100:
start = max(start, 0)
finalResponse = flask.render_template("base.html", playerList=playerList, \
doNotComputeRank=doNotComputeRank, \
start=start, \
endOfBoardIndicator=endOfBoardIndicator, \
findPlayer=cannotFindPlayer, \
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)
@@ -270,27 +289,34 @@ def leaderboard():
@app.route('/static/<path:path>')
def send_js(path):
return send_from_directory('static', path)
@app.before_first_request
def init():
response = send_from_directory('static', path)
response.headers['Cache-Control'] = "max-age=2592000"
return response
def create_app():
global SERVERS
SERVERS_FILE = "servers.json"
if os.path.isfile(SERVERS_FILE):
import valve.source.a2s
from valve.source import NoResponseError
with open(SERVERS_FILE) as f:
SERVERS = json.load(f)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Start open-leaderboard', \
parser = argparse.ArgumentParser(description='Start open-leaderboard',
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=True,
help='skillbird database (overrides web connection if set)')
parser.add_argument('--skillbird-db', required=True, help='skillbird database (overrides web connection if set)')
with app.app_context():
create_app()
args = parser.parse_args()
app.config["DB_PATH"] = args.skillbird_db

View File

@@ -217,7 +217,6 @@ body{
bottom: 0;
left: 0;
height: 30px;
}
.footerLink{
@@ -241,7 +240,6 @@ body{
.footerLink{
font-size: 4vw;
}
.mid{
margin-left: 2.5%;
margin-right: 2.5%;
@@ -258,3 +256,11 @@ body{
font-style: italic;
font-weight: bold;
}
@keyframes fadeIn {
from { opacity: 0.3; }
}
.animate-flicker {
animation: fadeIn 2s alternate;
}

View File

@@ -13,12 +13,16 @@
<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"]
}
@@ -26,7 +30,7 @@
)
}
players()
setInterval(players, 2000)
setInterval(players, 10000)
</script>
</div>
<table id="tableMain" class="table table-striped table-bordered table-sm"

View File

@@ -27,10 +27,15 @@
<canvas id="lineChart">
</canvas>
</div>
<div class="mt-3 medal-container">
{% for m in medals %}
{{ m }}
{% endfor %}
</div>
<p class="mt-5 mb-3">
</p>
</div>
{% include 'footer.html' %}
<!-- {% include 'footer.html' %}-->
<script defer>
var canvas = document.getElementById("lineChart")
var ctx = canvas.getContext('2d');