Brandon Cornejo
11 years ago
14 changed files with 352 additions and 92 deletions
-
1.gitignore
-
24app.py
-
27app/__init__.py
-
76app/analytics.py
-
6app/models.py
-
13app/static/css/app.css
-
37app/teamspeak.py
-
10app/templates/edit_event.html
-
8app/templates/layout.html
-
110app/templates/profile.html
-
2app/templates/sidenav.html
-
2app/templates/teamspeak.html
-
26migrations/versions/1c90e0fd276a_.py
-
102run.py
@ -1,24 +0,0 @@ |
|||
#!venv/bin/python |
|||
from flask import Flask |
|||
from flask.ext.script import Manager, Server |
|||
from flask.ext.migrate import Migrate, MigrateCommand |
|||
|
|||
from app import * |
|||
|
|||
SQLALCHEMY_DATABASE_URI = 'mysql://root:$perwePP@localhost/dotanoobs' |
|||
|
|||
migrate = Migrate(app, db) |
|||
manager = Manager(app) |
|||
manager.add_command('db', MigrateCommand) |
|||
|
|||
|
|||
@manager.command |
|||
def admin(name): |
|||
u = models.User.query.filter_by(nickname=name).first() |
|||
if u and not u.admin: |
|||
u.admin = True |
|||
db.session.commit() |
|||
print "User {} has been granted admin access.".format(name) |
|||
|
|||
if __name__ == '__main__': |
|||
manager.run() |
@ -0,0 +1,76 @@ |
|||
import requests |
|||
from time import sleep, mktime |
|||
from bs4 import BeautifulSoup |
|||
from datetime import datetime |
|||
|
|||
from app import app, db, models |
|||
|
|||
MODES_TO_SKIP = ['Ability Draft', 'Greeviling', 'Diretide'] |
|||
|
|||
def collect_match_results(dotabuff_id, num_matches): |
|||
results = [] |
|||
page = 0 |
|||
while True: |
|||
page += 1 |
|||
url = "http://dotabuff.com/players/{}/matches/?page={}".format(dotabuff_id, page) |
|||
data = requests.get(url).text |
|||
soup = BeautifulSoup(data).article.table.tbody |
|||
# Catch last page |
|||
if 'sorry' in soup.tr.td.text.lower(): |
|||
break |
|||
# Parse the matches on current page |
|||
for row in soup.find_all('tr'): |
|||
# Pass over bot matches and other 'inactive' games |
|||
if 'inactive' in row.get('class', ''): continue |
|||
cells = row.find_all('td') |
|||
result_cell = cells[2] |
|||
match_cell = cells[3] |
|||
match_id = int(result_cell.a['href'].split('/')[-1]) |
|||
match_type = match_cell.div.text |
|||
if match_type in MODES_TO_SKIP: continue |
|||
result = True if 'won' in result_cell.a['class'] else False |
|||
dt = datetime.strptime(result_cell.time['datetime'], '%Y-%m-%dT%H:%M:%S+00:00') |
|||
results.append({'match_id':match_id, 'win':result, 'datetime':dt, 'game_mode':match_type}) |
|||
if len(results) > num_matches: |
|||
break |
|||
if len(results) > num_matches: |
|||
break |
|||
sleep(60) |
|||
results.reverse() |
|||
return results |
|||
|
|||
def apply_window(results, window_size=50): |
|||
windows = [] |
|||
# Compute the initial window |
|||
win_rate = 0.00 |
|||
for idx in range(0, window_size): |
|||
win_rate += 1 if results[idx]['win'] else 0 |
|||
win_rate /= window_size |
|||
windows.append(win_rate) |
|||
# From here on, modify based on leave/enter data points |
|||
fractional_change = 1. / window_size |
|||
for idx in range(window_size, len(results)): |
|||
if results[idx-window_size]['win'] == results[idx]['win']: |
|||
pass |
|||
elif results[idx]['win']: |
|||
win_rate += fractional_change |
|||
else: |
|||
win_rate -= fractional_change |
|||
windows.append(win_rate) |
|||
return windows |
|||
|
|||
def calculate_winrates(): |
|||
users_analyzed = 0 |
|||
for user in models.User.query.all(): |
|||
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() |
|||
users_analyzed += 1 |
|||
sleep(60) |
|||
app.logger.info("Calculated win rate numbers for {} doobs.".format(users_analyzed)) |
|||
return users_analyzed |
@ -0,0 +1,26 @@ |
|||
"""empty message |
|||
|
|||
Revision ID: 1c90e0fd276a |
|||
Revises: a6f7dd522b7 |
|||
Create Date: 2014-06-24 19:01:39.358682 |
|||
|
|||
""" |
|||
|
|||
# revision identifiers, used by Alembic. |
|||
revision = '1c90e0fd276a' |
|||
down_revision = 'a6f7dd522b7' |
|||
|
|||
from alembic import op |
|||
import sqlalchemy as sa |
|||
|
|||
|
|||
def upgrade(): |
|||
### commands auto generated by Alembic - please adjust! ### |
|||
op.add_column('user', sa.Column('winrate_data', sa.Json(), nullable=True)) |
|||
### end Alembic commands ### |
|||
|
|||
|
|||
def downgrade(): |
|||
### commands auto generated by Alembic - please adjust! ### |
|||
op.drop_column('user', 'winrate_data') |
|||
### end Alembic commands ### |
@ -0,0 +1,102 @@ |
|||
#!venv/bin/python |
|||
from flask import Flask |
|||
from flask.ext.script import Manager, Server |
|||
from flask.ext.migrate import Migrate, MigrateCommand |
|||
|
|||
from app import app, db, models |
|||
|
|||
#SQLALCHEMY_DATABASE_URI = 'mysql://root:$perwePP@localhost/dotanoobs' |
|||
|
|||
migrate = Migrate(app, db) |
|||
manager = Manager(app) |
|||
manager.add_command('db', MigrateCommand) |
|||
|
|||
def createTeamspeakInstance(): |
|||
import ts3 |
|||
s = ts3.TS3Server(app.config['TS3_HOST'], app.config['TS3_PORT']) |
|||
s.login(app.config['TS3_USERNAME'], app.config['TS3_PASSWORD']) |
|||
s.use(1) |
|||
return s |
|||
|
|||
@manager.command |
|||
def install_cronjobs(): |
|||
from os import path |
|||
from crontab import CronTab |
|||
cron = CronTab(user=True) |
|||
|
|||
# Clear out existing jobs |
|||
cron.remove_all(comment='DOOBSAUTO') |
|||
|
|||
def make_job(job): |
|||
p = path.realpath(__file__) |
|||
c = cron.new(command='{}/venv/bin/python {} {}'.format(path.split(p)[0],\ |
|||
p, job), comment='DOOBSAUTO') |
|||
return c |
|||
|
|||
# Create the jobs |
|||
winrate = make_job('calc_winrates') |
|||
ts3_move_afk = make_job('ts3_move_afk') |
|||
ts3_snapshot = make_job('ts3_snapshot') |
|||
ts3_award_points = make_job('ts3_award_points') |
|||
ts3_process_events = make_job('ts3_process_events') |
|||
|
|||
# Set their frequency to run |
|||
winrate.every(1).day() |
|||
ts3_move_afk.every(app.config['MOVE_AFK_FREQUENCY']).minute() |
|||
ts3_snapshot.every(app.config['SNAPSHOT_FREQUENCY']).hour() |
|||
ts3_award_points.every(app.config['AWARD_POINTS_FREQUENCY']).minute() |
|||
ts3_process_events.every(app.config['PROCESS_EVENTS_FREQUENCY']).hour() |
|||
|
|||
try: |
|||
assert True == winrate.is_valid() |
|||
assert True == ts3_move_afk.is_valid() |
|||
assert True == ts3_snapshot.is_valid() |
|||
assert True == ts3_award_points.is_valid() |
|||
assert True == ts3_process_events.is_valid() |
|||
except AssertionError as e: |
|||
print "Problem installing cronjobs: {}".format(e) |
|||
else: |
|||
cron.write() |
|||
print "Cron jobs written succesfully" |
|||
|
|||
@manager.command |
|||
def admin(name): |
|||
u = models.User.query.filter_by(nickname=name).first() |
|||
if u and not u.admin: |
|||
u.admin = True |
|||
db.session.commit() |
|||
print "User {} has been granted admin access.".format(name) |
|||
|
|||
@manager.command |
|||
def calc_winrates(): |
|||
from app.analytics import calculate_winrates |
|||
tsServer = createTeamspeakInstance() |
|||
calculate_winrates() |
|||
|
|||
@manager.command |
|||
def ts3_move_afk(): |
|||
from app.teamspeak import idle_mover |
|||
tsServer = createTeamspeakInstance() |
|||
idle_mover(tsServer) |
|||
|
|||
@manager.command |
|||
def ts3_snapshot(): |
|||
from app.teamspeak import store_active_data |
|||
tsServer = createTeamspeakInstance() |
|||
store_active_data(tsServer) |
|||
|
|||
@manager.command |
|||
def ts3_award_points(): |
|||
from app.teamspeak import award_idle_ts3_points |
|||
tsServer = createTeamspeakInstance() |
|||
award_idle_ts3_points(tsServer) |
|||
|
|||
@manager.command |
|||
def ts3_process_events(): |
|||
from app.teamspeak import process_ts3_events |
|||
tsServer = createTeamspeakInstance() |
|||
process_ts3_events(tsServer) |
|||
|
|||
|
|||
if __name__ == '__main__': |
|||
manager.run() |
Write
Preview
Loading…
Cancel
Save
Reference in new issue