Bugfixes & Hitbox.tv field in User model

This commit is contained in:
Brandon Cornejo 2014-10-04 19:43:54 -05:00
parent 2e68fbdc4c
commit de5e8ad946
7 changed files with 77 additions and 22 deletions

View File

@ -1,7 +1,7 @@
import requests import requests
from time import sleep, mktime from time import sleep, mktime
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
from datetime import datetime from datetime import datetime, timedelta
from app import app, db, models from app import app, db, models
@ -14,10 +14,15 @@ def collect_match_results(dotabuff_id, num_matches):
page += 1 page += 1
url = "http://dotabuff.com/players/{}/matches/?page={}".format(dotabuff_id, page) url = "http://dotabuff.com/players/{}/matches/?page={}".format(dotabuff_id, page)
data = requests.get(url).text data = requests.get(url).text
soup = BeautifulSoup(data).article.table.tbody try:
# Catch last page soup = BeautifulSoup(data).article.table.tbody
if 'sorry' in soup.tr.td.text.lower(): except:
break break
else:
# Catch last page
if 'sorry' in soup.tr.td.text.lower():
break
# Parse the matches on current page # Parse the matches on current page
for row in soup.find_all('tr'): for row in soup.find_all('tr'):
# Pass over bot matches and other 'inactive' games # Pass over bot matches and other 'inactive' games
@ -43,7 +48,7 @@ def apply_window(results, window_size=50):
windows = [] windows = []
# Compute the initial window # Compute the initial window
win_rate = 0.00 win_rate = 0.00
for idx in range(0, window_size): for idx in range(0, window_size-1):
win_rate += 1 if results[idx]['win'] else 0 win_rate += 1 if results[idx]['win'] else 0
win_rate /= window_size win_rate /= window_size
windows.append(win_rate) windows.append(win_rate)
@ -59,18 +64,38 @@ def apply_window(results, window_size=50):
windows.append(win_rate) windows.append(win_rate)
return windows return windows
# Single user alternative for testing/calculating on demand
def calculate_winrate(user_id):
user = models.User.query.get(user_id)
db_id = requests.get("http://dotabuff.com/search?q="+user.steam_id).url.split("/")[-1]
result = collect_match_results(db_id, app.config['ANALYTICS_WINRATE_NUM_MATCHES'])
windowed = apply_window(result, app.config['ANALYTICS_WINRATE_WINDOW'])
date_nums = map(lambda x: mktime(x['datetime'].timetuple()),\
result[app.config['ANALYTICS_WINRATE_WINDOW']-1:])
winrate = {'total_games': len(result), 'data': zip(date_nums, windowed) }
user.winrate_data = winrate
db.session.commit()
def calculate_winrates(): def calculate_winrates():
users_analyzed = 0 users_analyzed = 0
for user in models.User.query.all(): delta = datetime.utcnow() - timedelta(weeks=4)
print "Starting winrate calculation"
for user in models.User.query.filter(models.User.last_seen > delta).all():
print "Begin calculating winrate for {}".format(user.nickname.encode('utf-8'))
db_id = requests.get("http://dotabuff.com/search?q="+user.steam_id).url.split("/")[-1] db_id = requests.get("http://dotabuff.com/search?q="+user.steam_id).url.split("/")[-1]
result = collect_match_results(db_id, app.config['ANALYTICS_WINRATE_NUM_MATCHES']) result = collect_match_results(db_id, app.config['ANALYTICS_WINRATE_NUM_MATCHES'])
windowed = apply_window(result, app.config['ANALYTICS_WINRATE_WINDOW']) if len(result):
date_nums = map(lambda x: mktime(x['datetime'].timetuple()),\ windowed = apply_window(result, app.config['ANALYTICS_WINRATE_WINDOW'])
result[app.config['ANALYTICS_WINRATE_WINDOW']-1:]) date_nums = map(lambda x: mktime(x['datetime'].timetuple()),\
winrate = {'total_games': len(result), 'data': zip(date_nums, windowed) } result[app.config['ANALYTICS_WINRATE_WINDOW']-1:])
user.winrate_data = winrate winrate = {'total_games': len(result), 'data': zip(date_nums, windowed) }
db.session.commit() user.winrate_data = winrate
users_analyzed += 1 db.session.commit()
sleep(60) users_analyzed += 1
print "Finished winrate calculation for {} ({} total games)".format(user.nickname.encode('utf-8'), winrate['total_games'])
sleep(60)
else:
print "DotaBuff unable to access match statistics for {}".format(user.nickname.encode('utf-8'))
app.logger.info("Calculated win rate numbers for {} doobs.".format(users_analyzed)) app.logger.info("Calculated win rate numbers for {} doobs.".format(users_analyzed))
print "Calculated win rate numbers for {} doobs.".format(users_analyzed)
return users_analyzed return users_analyzed

View File

@ -6,6 +6,7 @@ class SettingsForm(Form):
public = BooleanField('public', default=True) public = BooleanField('public', default=True)
logo = BooleanField('biglogo', default=True) logo = BooleanField('biglogo', default=True)
twitch = TextField('twitch') twitch = TextField('twitch')
hitbox = TextField('hitbox')
bio_text = TextAreaField('bio_text') bio_text = TextAreaField('bio_text')
class EnableStatsForm(Form): class EnableStatsForm(Form):

View File

@ -28,8 +28,11 @@ class Json(db.TypeDecorator):
return value return value
def process_result_value(self, value, dialect): def process_result_value(self, value, dialect):
if value is not None: try:
value = json.loads(value) if value is not None:
value = json.loads(value)
except ValueError:
return {}
return value return value
# Mongoness factor - phase 2 # Mongoness factor - phase 2
@ -72,6 +75,7 @@ class User(db.Model):
created = db.Column(db.DateTime) created = db.Column(db.DateTime)
last_seen = db.Column(db.DateTime) last_seen = db.Column(db.DateTime)
twitch = db.Column(db.String(60)) twitch = db.Column(db.String(60))
hitbox = db.Column(db.String(60))
random_heroes = db.Column(MutableDict.as_mutable(Json)) random_heroes = db.Column(MutableDict.as_mutable(Json))
az_completions = db.Column(db.Integer) az_completions = db.Column(db.Integer)
@ -95,6 +99,19 @@ class User(db.Model):
def get_or_create(self, steam_id): def get_or_create(self, steam_id):
return get_or_create_instance(db.session, User, steam_id=steam_id) return get_or_create_instance(db.session, User, steam_id=steam_id)
@classmethod
def get_streaming_users(self):
twitch_streams = []
hitbox_streams = []
for user in User.query.all():
if user.points_from_events + user.points_from_ts3 + user.points_from_forum < 5: continue
if user.twitch:
twitch_streams.append(user.twitch)
if user.hitbox:
hitbox_streams.append(user.hitbox)
return {'twitch': twitch_streams, 'hitbox': hitbox_streams}
def __init__(self, steam_id): def __init__(self, steam_id):
self.steam_id = steam_id self.steam_id = steam_id
self.random_heroes = {'current':None, 'completed':[]} self.random_heroes = {'current':None, 'completed':[]}

View File

@ -361,11 +361,11 @@ def award_idle_ts3_points(server):
if client['cid'] not in exempt_cids: if client['cid'] not in exempt_cids:
try: try:
doob = models.User.query.filter_by(teamspeak_id=client['client_unique_identifier']).first() doob = models.User.query.filter_by(teamspeak_id=client['client_unique_identifier']).first()
if doob:
doob.update_connection()
active_users.add(doob)
except KeyError: except KeyError:
pass pass
if doob:
doob.update_connection()
active_users.add(doob)
doobs = set(models.User.query.filter(models.User.ts3_starttime != None).all()) doobs = set(models.User.query.filter(models.User.ts3_starttime != None).all())
for doob in doobs.intersection(active_users): for doob in doobs.intersection(active_users):
doob.finalize_connection() doob.finalize_connection()

View File

@ -75,7 +75,8 @@ $(document).ready(function() {
// Add the twitch streams // Add the twitch streams
var stream_url = "https://api.twitch.tv/kraken/streams/"; var stream_url = "https://api.twitch.tv/kraken/streams/";
var channels = ["dotanoobs", "bearhugdota", "kreejaffakree", "prettypenguins", "shaneomad"]; // var channels = ["dotanoobs", "bearhugdota", "kreejaffakree", "prettypenguins", "shaneomad"];
var channels = {{ streamers['twitch']|tojson|safe }};
for (var idx in channels) { for (var idx in channels) {
$.getJSON(stream_url+channels[idx]+"?callback=?", function(data) { $.getJSON(stream_url+channels[idx]+"?callback=?", function(data) {
if (data.stream) { if (data.stream) {
@ -107,7 +108,8 @@ $(document).ready(function() {
// Add the hitbox streams // Add the hitbox streams
var stream_url = "http://api.hitbox.tv/media/live/"; var stream_url = "http://api.hitbox.tv/media/live/";
var channels = ["Bandita", "Gibb3d"]; //var channels = ["Bandita", "Gibb3d"];
var channels = {{ streamers['hitbox']|tojson|safe }};
for (var idx in channels) { for (var idx in channels) {
$.getJSON(stream_url+channels[idx], function(data) { $.getJSON(stream_url+channels[idx], function(data) {
var livestream = data.livestream[0]; var livestream = data.livestream[0];

View File

@ -25,6 +25,10 @@
<label class="uk-form-label">Twitch.tv Username:</label> <br/> <label class="uk-form-label">Twitch.tv Username:</label> <br/>
{{ form.twitch(placeholder="e.g. shaneomad") }} {{ form.twitch(placeholder="e.g. shaneomad") }}
</div> </div>
<div class="uk-form-row">
<label class="uk-form-label">Hitbox.tv Username:</label> <br/>
{{ form.hitbox(placeholder="e.g. shaneomad") }}
</div>
<div class="uk-form-row"> <div class="uk-form-row">
<label class="uk-form-label">Biography text:</label><br/> <label class="uk-form-label">Biography text:</label><br/>
{{ form.bio_text(rows=14, class='uk-width-1-1', data=g.user.bio_text, placedholder='What you place here is displayed in your profile when other users view it.') }} {{ form.bio_text(rows=14, class='uk-width-1-1', data=g.user.bio_text, placedholder='What you place here is displayed in your profile when other users view it.') }}

View File

@ -41,7 +41,8 @@ def flash_form_errors(form):
def index(): def index():
active = Event.query.filter(Event.start_time <= datetime.utcnow(), Event.end_time > datetime.utcnow()).all() active = Event.query.filter(Event.start_time <= datetime.utcnow(), Event.end_time > datetime.utcnow()).all()
upcoming = Event.query.filter(Event.start_time > datetime.utcnow()).limit(2).all() upcoming = Event.query.filter(Event.start_time > datetime.utcnow()).limit(2).all()
return render_template("index.html", active_events=active, upcoming_events=upcoming) channels = User.get_streaming_users()
return render_template("index.html", active_events=active, upcoming_events=upcoming, streamers=channels)
@app.route('/login') @app.route('/login')
@oid.loginhandler @oid.loginhandler
@ -79,6 +80,11 @@ def teamspeak():
def friends(): def friends():
return render_template('friends.html') return render_template('friends.html')
# Stream pages
@app.route('/shaneomad')
def twitch_shaneomad():
return render_template('potatr.html', twitch_id=app.config.TWITCH_CLIENT_ID)
# User profile page # User profile page
@app.route('/user/<int:userid>') @app.route('/user/<int:userid>')
def user_profile(userid): def user_profile(userid):