summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndré Glüpker <git@wgmd.de>2018-01-26 00:47:54 +0100
committerAndré Glüpker <git@wgmd.de>2018-01-26 00:47:54 +0100
commit98a97bc04365db9becb1038f88e10866a829b280 (patch)
tree9124502891e384f406393651c07be36c721d2c21
parent81cfe943b265e8b9d41ad7d150cca92a537d7d2c (diff)
downloadsteam-98a97bc04365db9becb1038f88e10866a829b280.tar.gz
steam-98a97bc04365db9becb1038f88e10866a829b280.tar.bz2
steam-98a97bc04365db9becb1038f88e10866a829b280.zip
Ask SteamAPI for owned games and gamestats in CSGO.
This is used in Premade Finder to maybe identify Smurfs.
-rw-r--r--SteamAPI.py100
-rwxr-xr-xmain.py9
-rw-r--r--templates/premades_html.jinja157
3 files changed, 189 insertions, 77 deletions
diff --git a/SteamAPI.py b/SteamAPI.py
index 87b5c39..1790989 100644
--- a/SteamAPI.py
+++ b/SteamAPI.py
@@ -193,36 +193,118 @@ class SteamAPI():
return ( jsondata['response']['game_count'], jsondata['response']['games'] )
return None
- def getPlayerGameStats(self, steamid, gameid):
- """Fetch the list of achievements a person achieved in a game
+ def getUserstatsForGame(self, steamid, gameid):
+ """Fetch the available game stats for a player in the specified game.
Args:
steamid: Steamid of the particular user
gameid: Appid of the game we want to check
Returns:
- Tuple with (number of games, gameinfo [appid, name, playtime_2weeks, playtime_forever, icons])
+ dict() with statname and value
"""
if CACHE:
- cache = Caching.readCache('playergamestats', '%s-%s' % (str(steamid), str(gameid)), 24*60*60)
+ cache = Caching.readCache('usergamestats', '%s-%s' % (str(steamid), str(gameid)), 24*60*60)
if cache:
- jsondata = json.loads(cache)
- return jsondata
+ cachedata = json.loads(cache)
+ return cachedata
- url = 'http://api.steampowered.com/ISteamUserStats/GetPlayerAchievements/v0001/?key=%s&steamid=%s&appid=%s' % (self.token, str(steamid), str(gameid))
+ url = 'http://api.steampowered.com/ISteamUserStats/GetUserStatsForGame/v0001/?key=%s&steamid=%s&appid=%s' % (self.token, str(steamid), str(gameid))
try:
response = urlopen(url)
data = response.read().decode('utf-8')
jsondata = json.loads(data)
+ statslist = jsondata['playerstats']['stats']
+ userstats = dict()
+ for stat in statslist:
+ userstats[stat] = statslist[stat]['value']
except HTTPError:
# f.e. profile is private
+ userstats = None
+
+ if userstats:
+ if CACHE:
+ cache = Caching.writeCache('usergamestats', '%s-%s' % (str(steamid), str(gameid)), json.dumps(userstats))
+ return userstats
+ return None
+
+ def getMultipleUserUserstatsForGame(self, steamids, gameid):
+ executor = ThreadPoolExecutor(max_workers=10)
+ futures = dict()
+ for steamid in steamids:
+ futures[steamid] = executor.submit(self.getUserstatsForGame, steamid, gameid)
+
+ result = dict()
+ for steamid in steamids:
+ result[steamid] = futures[steamid].result()
+
+ return result
+
+ def getOwnedGames(self, steamid):
+ """Fetch games owned by a player.
+
+ Args:
+ steamid: Steamid of the particular user
+ Returns:
+ dict() with game_count and games, which contains appid + playtime_forever
+ """
+ if CACHE:
+ cache = Caching.readCache('userownedgames', '%s' % (str(steamid)), 7*24*60*60)
+ if cache:
+ cachedata = json.loads(cache)
+ return cachedata
+
+ url = 'http://api.steampowered.com/IPlayerService/GetOwnedGames/v0001/?key=%s&steamid=%s' % (self.token, str(steamid))
+ try:
+ response = urlopen(url)
+ data = response.read().decode('utf-8')
+ jsondata = json.loads(data)
+ if 'response' in jsondata:
+ jsondata = jsondata['response']
+ except HTTPError:
jsondata = None
- if 'playerstats' in jsondata:
+ if jsondata:
if CACHE:
- cache = Caching.writeCache('playergamestats', '%s-%s' % (str(steamid), str(gameid)), json.dumps(jsondata))
+ cache = Caching.writeCache('userownedgames', '%s' % (str(steamid)), json.dumps(jsondata))
return jsondata
return None
+ def getMultipleUserOwnedGames(self, steamids):
+ executor = ThreadPoolExecutor(max_workers=10)
+ futures = dict()
+ for steamid in steamids:
+ futures[steamid] = executor.submit(self.getOwnedGames, steamid)
+
+ result = dict()
+ for steamid in steamids:
+ result[steamid] = futures[steamid].result()
+
+ return result
+
+ def getDataForPremadefinder(self, steamids):
+ executor = ThreadPoolExecutor(max_workers=20)
+
+ futures = dict()
+ futures['profiles'] = executor.submit(self.getProfiles, steamids)
+ futures['ownedGames'] = dict()
+ futures['userstats'] = dict()
+ futures['friends'] = dict()
+
+ for steamid in steamids:
+ futures['ownedGames'][steamid] = executor.submit(self.getOwnedGames, steamid)
+ futures['userstats'][steamid] = executor.submit(self.getUserstatsForGame, steamid, 730)
+ futures['friends'][steamid] = executor.submit(self.getFriends, steamid)
+
+ profiles = futures['profiles'].result()
+ for steamid in profiles:
+ profiles[steamid]['_friends'] = futures['friends'][steamid].result()
+ profiles[steamid]['_userstats'] = futures['userstats'][steamid].result()
+ profiles[steamid]['_ownedGames'] = futures['ownedGames'][steamid].result()
+ profiles[steamid]['_ownedPlayedGames'] = len([game for game in profiles[steamid]['_ownedGames']['games'] if game['playtime_forever'] > 0])
+
+
+ return profiles
+
if __name__ == "__main__":
# TODO(andre): Maybe run tests here?
print('This is a module.')
diff --git a/main.py b/main.py
index ae6030b..7577d2d 100755
--- a/main.py
+++ b/main.py
@@ -135,7 +135,7 @@ def lobby():
@app.route("/premadefinder", methods=['GET', 'POST'])
def premades():
steamids = []
- profiles = dict()
+ premadedata = dict()
connections = set()
if request.method == 'POST':
@@ -150,12 +150,12 @@ def premades():
)
# Ask steam about profiles
- profiles = steam.getMultipleFriends(steamids)
+ premadedata = steam.getDataForPremadefinder(steamids)
# Add connection between friends.
# Friends are always bidirectional, so we use set and min/max to avoid duplicates
for steamid in steamids:
- for friend in profiles[steamid]['friends']:
+ for friend in premadedata[steamid]['_friends']:
if friend in steamids:
friend_a = min(steamid, friend)
friend_b = max(steamid, friend)
@@ -163,7 +163,8 @@ def premades():
return render_template('premades_html.jinja',
steamids=steamids,
- profiles=profiles,
+ profiles=premadedata,
+ display_time=display_time,
connections=connections
)
diff --git a/templates/premades_html.jinja b/templates/premades_html.jinja
index 8fc4043..565ef21 100644
--- a/templates/premades_html.jinja
+++ b/templates/premades_html.jinja
@@ -1,4 +1,5 @@
-<html><head>
+<html>
+ <head>
<title>CS:GO Premadefinder</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" type="text/css" href="static/style.css" />
@@ -7,97 +8,125 @@
</head>
<body onload="onLoad();">
- <ul id="menu">
- <li class="menu app"><a class="joinbutton" href="lobby">Lobbylinkfinder</a></li>
- </ul>
-
- <div class="form">
- Copy&amp;Paste den Inhalt von 'status' aus der Konsole.<br />
- <form action="premadefinder" method="post">
- <textarea name="statustext" cols="75" rows="10"></textarea><br />
- <input class="joinbutton" type="submit" name="Freunde finden!" />
- </form>
- </div>
+ <ul id="menu">
+ <li class="menu app"><a class="joinbutton" href="lobby">Lobbylinkfinder</a></li>
+ </ul>
+ <div class="form">
+ Copy&amp;Paste den Inhalt von 'status' aus der Konsole.<br />
+ <form action="premadefinder" method="post">
+ <textarea name="statustext" cols="75" rows="10"></textarea><br />
+ <input class="joinbutton" type="submit" value="Premades finden!" />
+ </form>
+ </div>
- {% if steamids %}
-
+ {% if steamids %}
<script type="text/javascript">
- function onLoad(){
- var graph = Viva.Graph.graph();
+ function onLoad() {
+ const graph = Viva.Graph.graph();
{% for steamid in steamids %}
- graph.addNode('{{ steamid }}', {url: '{{ profiles[steamid]['avatarmedium'] }}', name: '{{ profiles[steamid]['personaname']|e }}', link: '{{ profiles[steamid]['profileurl'] }}', friends: {% if profiles[steamid]['communityvisibilitystate'] == 3 %} 'yes' {% else %} 'no' {% endif %}});
+ graph.addNode('{{ steamid }}',
+ {
+ url: "{{ profiles[steamid]['avatarmedium'] }}",
+ name: "{{ profiles[steamid]['personaname']|e }}",
+ details1: "{{ profiles[steamid]['_ownedPlayedGames']|e }}",
+ details2: "{{ profiles[steamid]['_userstats']['total_time_played']|e }}",
+ friends: {% if profiles[steamid]['communityvisibilitystate'] == 3 %} "yes" {% else %} "no" {% endif %}
+ }
+ )
{% endfor %}
+
{% for connection in connections %}
- graph.addLink('{{ connection[0] }}', '{{ connection[1] }}');
+ graph.addLink("{{ connection[0] }}", "{{ connection[1] }}");
{% endfor %}
- var graphics = Viva.Graph.View.svgGraphics();
+ const graphics = Viva.Graph.View.svgGraphics()
graphics.node(
- function(node) {
- if (node.data) {
- var ui = Viva.Graph.svg('g'),
- svgText = Viva.Graph.svg('text')
+ (node) => {
+ if (!node.data) return
+
+ const ui = Viva.Graph.svg('g')
+ ui.append(Viva.Graph.svg('text')
+ .attr('text-anchor', 'middle')
+ .attr('fill', 'rgb(150, 150, 0)')
+ .attr('x', '+16px')
+ .attr('y', '-8px')
+ .text(node.data.name)
+ )
+ ui.append(Viva.Graph.svg('image')
+ .attr('width', 32)
+ .attr('height', 32)
+ .link(node.data.url)
+ )
+ if (node.data.details1) {
+ const col = (node.data.details1 < 10) ? 'rgb(150, 0, 0)' : 'rgb(150, 150, 0)'
+ ui.append(Viva.Graph.svg('text')
.attr('text-anchor', 'middle')
- .attr('fill', 'rgb(150, 150, 0)')
+ .attr('fill', col)
.attr('x', '+16px')
.attr('y', '+48px')
- .text(node.data.name),
- img = Viva.Graph.svg('image')
- .attr('width', 32)
- .attr('height', 32)
- .link(node.data.url),
- border = Viva.Graph.svg('rect')
+ .text(`Steamspiele: ${node.data.details1}`)
+ )
+ }
+ if (node.data.details2) {
+ ui.append(Viva.Graph.svg('text')
+ .attr('text-anchor', 'middle')
+ .attr('fill', 'rgb(150, 150, 0)')
+ .attr('x', '+16px')
+ .attr('y', '+64px')
+ .text(`Spielzeit: ${Math.floor(node.data.details2 / 3600)}h`)
+ )
+ }
+ if (node.data.friends == 'no') {
+ ui.append(Viva.Graph.svg('rect')
.attr('width', 36)
.attr('height', 36)
.attr('x', '-2px')
.attr('y', '-2px')
- .attr('fill', 'red');
- if (node.data.friends == 'no') {
- ui.append(border);
- }
- ui.append(img);
- ui.append(svgText);
- return ui;
+ .attr('fill', 'red')
+ )
}
+ return ui
}
- ).placeNode(
- function(nodeUI, pos){
- // Shift image to let links go to the center:
- nodeUI.attr('transform',
- 'translate(' +
- (pos.x - 16) + ',' + (pos.y - 16) +
- ')');
+ )
+ .placeNode(
+ (nodeUI, pos) => {
+ nodeUI.attr('transform', `translate(${pos.x - 16}, ${pos.y - 16})`)
}
- );
+ )
- var layout = Viva.Graph.Layout.forceDirected(graph, {
- stableThreshold : 0.09,
- springLength : 150,
- springCoeff : 0.0008,
- dragCoeff : 0.05,
- gravity : -1.0
- });
+ const layout = Viva.Graph.Layout.forceDirected(graph,
+ {
+ stableThreshold: 0.09,
+ springLength: 150,
+ springCoeff: 0.0008,
+ dragCoeff: 0.05,
+ gravity: -1.0
+ }
+ )
- var renderer = Viva.Graph.View.renderer(graph, {
- container: document.getElementById('premades'),
- graphics : graphics,
- layout : layout
- });
+ const renderer = Viva.Graph.View.renderer(graph,
+ {
+ container: document.getElementById('premades'),
+ graphics: graphics,
+ layout: layout
+ }
+ )
- renderer.run();
- };
- </script>
+ renderer.run()
+ }
+ </script>
<div id="premades">
</div>
+
<div id="info">
- (Private Profile sind durch eine rote Umrandung gekennzeichnet.)
+ <strong>Steamspiele</strong>: Anzahl von Steamspielen mit Spielzeit. <br \>
+ <strong>Spielzeit</strong>: Die aktive Spielzeit in CSGO. <br \>
+ <strong>Private Profile</strong> sind durch einen roten Rahmen gekennzeichnet. <br \>
</div>
- {% endif %}
+ {% endif %}
</body>
</html>
-
-{# vim: commentstring={#\ %s\ #}