diff options
-rw-r--r-- | SteamAPI.py | 100 | ||||
-rwxr-xr-x | main.py | 9 | ||||
-rw-r--r-- | templates/premades_html.jinja | 157 |
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.') @@ -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&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&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\ #} |