Tiny IRC bot for #dotanoobs, prints dota match history to channel and more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

369 lines
16 KiB

from ircutils import bot, events, format
import requests
import simplejson as json
import urllib2, random, re
import HTMLParser
from collections import deque
class DotaMatch:
api_key="4CEC40C492B1AB15EEBA07681E6EDBBD"
hero_data = {}
def __init__(self, channel, user, command, params):
self.channel = channel
self.requester = user
self.command = command
if not params:
self.query = [user]
else:
self.query = params
self.matches = []
self.notice = []
self.steam_id = ''
def get_hero_values(self):
xhr = urllib2.Request("https://api.steampowered.com/IEconDOTA2_570/GetHeroes/v0001/?key="+self.api_key+"&language=en_us")
o = urllib2.build_opener()
f = o.open(xhr)
data = json.load(f)
for hero in data['result']['heroes']:
self.hero_data[hero['id']] = hero
def lookup_player(self, query):
xhr = urllib2.Request("http://api.steampowered.com/ISteamUser/ResolveVanityURL/v0001/?key="+self.api_key+"&vanityurl="+query[0])
o = urllib2.build_opener()
f = o.open(xhr)
data = json.load(f)
if data['response']['success'] == 1:
self.steam_id = data['response']['steamid']
else:
self.steam_id = 'NULL'
def get_latest_match_id(self):
if self.command == "!MATCHBYID":
return True
xhr = urllib2.Request("https://api.steampowered.com/IDOTA2Match_570/GetMatchHistory/V001/?key="+self.api_key+"&account_id="+self.steam_id)
o = urllib2.build_opener()
f = o.open(xhr)
data = json.load(f)
# did we get matches back?
try:
self.matches = data['result']['matches']
return True
except KeyError:
return False
def get_match_info(self):
try:
xhr = urllib2.Request("https://api.steampowered.com/IDOTA2Match_570/GetMatchDetails/V001/?key="+self.api_key+"&match_id="+str(self.matches[0]['match_id']))
o = urllib2.build_opener()
f = o.open(xhr)
data = json.load(f)
except Exception as e:
self.notice.append("Problem connecting to the Dota2 API.")
else:
# get users 32-bit SteamID so we can look them up
sid = int(self.steam_id) - 76561197960265728
p = {}
for player in data['result']['players']:
if player['account_id'] == sid:
p = player
break
if not p:
self.notice.append("Player {} not found in match {}.".format(self.query[0], self.query[1]))
return
hero_id = self.hero_data[p['hero_id']]['localized_name']
kills = p['kills']
deaths = p['deaths']
assists = p['assists']
last_hits = p['last_hits']
gpm = p['gold_per_min']
time = data['result']['duration'] / 60
if( p['player_slot'] & (1<<7) == 0 ):
team = 'Radiant'
else:
team = 'Dire'
if( team is 'Dire' and not bool(data['result']['radiant_win'])):
result = 'Victory!'
elif( team is 'Radiant' and bool(data['result']['radiant_win'])):
result = 'Victory!'
else:
result = 'Defeat!'
# print match info
self.notice.append("Match for \x02{0}\x02 - Hero: \x0311{1}\x03, K/D/A: \x0303{2}/{3}/{4}\x03, Last Hits: \x0306{5}\x03, GPM: \x0308{6}\x03. Game Length: {7} mins. Team: {8} - {9}.".format(self.query[0], hero_id, kills, deaths, assists, last_hits, gpm, time, team, result))
def list_latest_matches(self):
# get users 32-bit SteamID so we can look them up
sid = int(self.steam_id) - 76561197960265728
p = {}
self.notice.append("Recent Matches for " + self.query[0] + ":")
for count, match in enumerate(self.matches):
if count > 3:
break
try:
xhr = urllib2.Request("https://api.steampowered.com/IDOTA2Match_570/GetMatchDetails/V001/?key="+self.api_key+"&match_id="+str(match['match_id']))
o = urllib2.build_opener()
f = o.open(xhr)
data = json.load(f)
except Exception as e:
self.notice.append("There was an error connecting to the Dota2 API.")
else:
for player in data['result']['players']:
if player['account_id'] == sid:
p = player
break
print self.hero_data[p['hero_id']]
hero_id = self.hero_data[p['hero_id']]['localized_name']
kills = p['kills']
deaths = p['deaths']
assists = p['assists']
if( p['player_slot'] & (1<<7) == 0 ):
team = 'Radiant'
else:
team = 'Dire'
if( team is 'Dire' and not bool(data['result']['radiant_win'])):
result = 'Victory!'
elif( team is 'Radiant' and bool(data['result']['radiant_win'])):
result = 'Victory!'
else:
result = 'Defeat!'
self.notice.append(" [\x02{0}\x02]: \x0311{1}\x03 - \x0303{2}/{3}/{4}\x03 - {5}".format(match['match_id'], hero_id, kills, deaths, assists, result))
class DoobBot(bot.SimpleBot):
auth_pool = deque()
actions = ["!MATCH", "!MATCHES", "!MATCHBYID"]
def on_channel_message(self, event):
url = re.search('http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F[0-9a-fA-F]))+', event.message)
channel = event.target
user = event.source
message = event.message.split();
command = message[0].upper()
params = message[1:]
if url:
self.do_printurltitle(channel, user, url.group())
elif command == "!ROLL":
self.do_rolldice(channel, user, params)
elif command == "!BTCX":
self.do_getbtcinfo(channel, user, False, params)
elif command == "!BTC":
self.do_getbtcinfo(channel, user, True, params)
elif command == "!WEATHER":
self.do_getweather(channel, user, params)
elif command == "!REDDITNEWS":
self.do_getnews(channel, user, params)
elif command == "!OW":
self.do_overwatch(channel, user, params)
elif command == "!ABOUT":
self.send_message(channel, "I am DotaBot, I bring info about Dota2 Matches. Ask for a !match. See !help for more.")
elif command == "!HELP":
self.send_message(user, "I am DotaBot - these are my available commands.")
self.send_message(user, "!MATCH <steam_vanity_name> - Get info about users latest match, if no argument passes your IRC nickname.")
self.send_message(user, "!MATCHES <steam_vanity_name> - Get a list of recent matches for the user, if no argument passes your IRC nickname.")
self.send_message(user, "!MATCHBYID <steam_vanity_name> <match_id_#> - Get info about particular match by ID#.")
self.send_message(user, "!ROLL ?D? - Simulate dice rolling (e.g. !roll 1d6 or !roll 5d20)")
self.send_message(user, "!WEATHER <name or zip> - Query wunderground for weather data")
self.send_message(user, "!REDDITNEWS <subreddit> - Pull a new story from <subreddit>, defaults to dota2.")
self.send_message(user, "!DOTANEWS - pulls latest news story about Dota2 from Steamworks.")
self.send_message(user, "!BTC - List current price of BTC in various fiat currencies.")
self.send_message(user, "!BTCX <amount> <currency> - Convert <amount> bitcoins to the local currency of choice.")
self.send_message(user, "Written by binaryatrocity - br4n@atr0phy.net")
elif command in self.actions:
m = DotaMatch(channel, user, command, params)
self.auth_pool.append(m);
self.send_message('NICKSERV', 'STATUS {0}'.format(user))
def on_private_notice(self, event):
if(event.message[0] == "2"):
c = self.auth_pool.popleft()
c.lookup_player(c.query)
if c.steam_id == 'NULL':
self.send_message(c.channel, "Unable to find SteamID for player "+c.query[0])
else:
status = c.get_latest_match_id()
if status:
if c.command == "!MATCHES": c.list_latest_matches()
elif c.command == "!MATCH": c.get_match_info()
elif c.command == "!MATCHBYID":
c.matches.append({'match_id':c.query[1]})
c.get_match_info()
for msg in c.notice:
self.send_message(c.channel, msg)
else:
self.send_message(c.channel, "No matches found for player "+c.query[0])
elif(event.message[0] == "1" or event.message[0] == "0"):
c = self.auth_pool.popleft()
self.send_message(c.channel, "You must be registered with NickServ before requesting match info! '/msg NickServ register HELP' for more info.")
def on_private_message(self, event):
user = event.source
message = event.message.split()
command = message[0].upper()
params = message[1:]
if command.upper() == "SAY":
mstr = ''
for msg in params:
mstr = mstr +' '+ msg
self.send_message(self.user, mstr)
if command.upper() == "QUIT":
self.disconnect(params)
def do_getnews(self, channel, user, params):
if not params:
params.append('dota2')
try:
raw_data = urllib2.Request("http://www.reddit.com/r/"+params[0]+"/new.json?sort=new")
o = urllib2.build_opener()
f = o.open(raw_data)
data = json.load(f)
except urllib2.HTTPError as e:
self.send_message(channel, "There was a problem accessing news.")
except Exception as e:
print e
else:
items = [ x['data'] for x in data['data']['children'] ]
rand = random.randint(0,10)
notice = "News from r/{0}: {1} - [{2}]".format(params[0], items[rand]['title'], items[rand]['url'])
self.send_message(channel, notice)
def do_printurltitle(self, channel, user, url):
try:
html_parser = HTMLParser.HTMLParser()
title = html_parser.unescape(urllib2.urlopen(url, timeout=1).read(10000).split('<title>')[1].split('</title>')[0].strip()).encode('utf-8')
notice = "{}'s URL: {}".format(user, title)
self.send_message(channel, notice)
except urllib2.URLError:
pass
except IndexError:
pass
except Exception as e:
print e
def do_getweather(self, channel, user, params):
try:
raw_data = urllib2.Request("http://api.openweathermap.org/data/2.5/weather?q="+params[0]+"&units=imperial")
o = urllib2.build_opener()
f = o.open(raw_data)
data = json.load(f)
city = data['name']
country = data['sys']['country']
lat, lon = data['coord']['lat'], data['coord']['lon']
condition = data['weather'][0]['main']
temp = data['main']['temp']
humidity = data['main']['humidity']
high = data['main']['temp_max']
low = data['main']['temp_min']
winds = data['wind']['speed']
notice = "Weather for {}, {} ({}, {}): Currently {} at {} degrees with {}% humidity and winds at {} mph. High: {}, Low: {}".format(city, country, lat, lon, condition, temp, humidity, winds, high, low)
self.send_message(channel, notice)
except urllib2.HTTPError as e:
self.send_message(channel, "Unable to find weather for "+params[0])
except urllib2.URLError as e:
self.send_message(channel, "There was a problem accessing weather info.")
except Exception as e:
print e
def do_getbtcinfo(self, channel, user, exch, params):
if not exch:
try:
data = json.load(urllib2.build_opener().open(urllib2.Request("http://blockchain.info/tobtc?currency="+params[1].upper()+"&value="+params[0])))
notice = "{}: Value of {} {} in BTC is \x03{}\x03".format(user, params[0], params[1].upper(), data)
self.send_message(channel, notice)
except Exception:
pass
else:
try:
data = json.load(urllib2.build_opener().open(urllib2.Request("http://blockchain.info/ticker")))
notice = "Current price of BTC: USD[{}], GBP[{}], EUR[{}]".format(data['USD']['last'], data['GBP']['last'], data['EUR']['last'])
self.send_message(channel, notice)
pass
except Exception as e:
print e
def do_rolldice(self, channel, user, params):
try:
dice = params[0].split('d')
rolls = []
for roll in range(0,int(dice[0])):
rolls.append(random.randint(1,int(dice[1])))
except Exception as e:
pass
else:
notice = "Rolls for {}: {!s}. Total of {}".format(user, rolls, sum(rolls))
self.send_message(channel, notice)
def do_overwatch(self, channel, user, params):
ow_url = "https://owapi.net/api/v1/u"
battletag = params[0]
battletag = battletag.replace('#', '-')
print params
try:
print '1'
if params[1].upper() == 'STATS':
api_url = "{}/{}/stats".format(ow_url, battletag)
#data = json.load(urllib2.build_opener(urllib2.HTTPSHandler()).open(urllib2.Request(api_url)))
data = requests.get(api_url)
sd = data.json()['overall_stats']
message = u"{}'s Overwatch Stats: Lvl {} - {} Games ({}W/{}L) for {}% win rate.".format(
user, sd['level'], sd['games'], sd['wins'], sd['losses'], sd['win_rate'])
elif params[1].upper() == 'HEROES':
print '2'
api_url = "{}/{}/heroes".format(ow_url, battletag)
data = json.load(urllib2.build_opener(urllib2.HTTPSHandler()).open(urllib2.Request(api_url)))
print '3'
sd = data['heroes']
print '4'
import pudb; pudb
message = u"{}'s Overwatch Heroes:\r \
{} [{} games, {} kda, {} winrate]\r \
{} [{} games, {} kda, {} winrate]\r \
{} [{} games, {} kda, {} winrate]".format(
user,
sd[0]['name'], sd[0]['games'], sd[0]['kpd'], sd[0]['winrate'],
sd[1]['name'], sd[1]['games'], sd[1]['kpd'], sd[1]['winrate'],
sd[2]['name'], sd[2]['games'], sd[2]['kpd'], sd[2]['winrate']
)
except IndexError as e:
message = '!ow [battletag] [stats/heroes]'
print e
# Send data to channel
self.send_message(channel, message.encode('ascii', 'replace'))
print "message sent"
# Create a new bot, and run it!
if __name__ == "__main__":
doob = DoobBot("MatchBot")
init_match = DotaMatch('#atr0phy', 'SYSTEM', 'START', 'INIT')
init_match.get_hero_values()
doob.connect("irc.oftc.net", channel=['#dotanoobs', '#digital-deception', '#atr0phy'])
doob.start()