1
Fork 0
mirror of https://github.com/RYGhub/royalnet.git synced 2024-11-27 13:34:28 +00:00
royalnet/main.py

382 lines
16 KiB
Python
Raw Normal View History

2016-08-12 13:55:59 +00:00
import asyncio
import discord
2016-08-12 15:23:45 +00:00
import json
2016-11-08 18:37:39 +00:00
import opendota
2017-01-09 07:37:09 +00:00
import overwatch
import league
2016-08-12 19:08:36 +00:00
import strings as s
2016-08-13 12:19:41 +00:00
import telegram
2016-08-16 20:16:22 +00:00
import bs4
2017-01-09 07:37:09 +00:00
import brawlhalla
2017-02-07 21:24:49 +00:00
import osu
2016-08-12 15:48:35 +00:00
loop = asyncio.get_event_loop()
2016-08-12 15:23:45 +00:00
d_client = discord.Client()
2016-08-13 13:36:08 +00:00
discord_is_ready = False
# When Discord is ready, set discord_is_ready to True
@d_client.event
async def on_ready():
global discord_is_ready
discord_is_ready = True
2016-08-12 15:23:45 +00:00
# Get player database from the db.json file
file = open("db.json")
db = json.load(file)
file.close()
2016-08-12 13:55:59 +00:00
2016-08-12 14:01:05 +00:00
# Get the discord bot token from "discordtoken.txt"
2016-08-12 19:08:36 +00:00
file = open("discordtoken.txt", "r")
token = file.read()
file.close()
2016-08-12 15:23:45 +00:00
2017-02-09 13:52:16 +00:00
def save_db():
2017-02-09 14:31:44 +00:00
"""Save the current db object to the db.json file."""
2017-02-09 13:52:16 +00:00
f = open("db.json", "w")
json.dump(db, f)
f.close()
del f
2016-11-02 13:45:41 +00:00
async def overwatch_status_change(timeout):
2017-02-09 14:31:44 +00:00
"""Check for Overwatch levelups and rank changes."""
2016-08-12 17:21:43 +00:00
while True:
2016-08-13 13:36:08 +00:00
if discord_is_ready:
2016-08-13 13:52:11 +00:00
print("[Overwatch] Starting check...")
2016-08-13 13:36:08 +00:00
# Update data for every player in list
for player in db:
if "overwatch" in db[player]:
2016-08-13 18:03:47 +00:00
try:
r = await overwatch.get_player_data(**db[player]["overwatch"])
except overwatch.NotFoundException:
print("[Overwatch] Player not found.")
except Exception:
# If some other error occours, skip the player
print("[Overwatch] Request returned an unhandled exception.")
2016-08-13 18:03:47 +00:00
else:
2016-11-02 13:45:41 +00:00
# Check for levelups
level = r["data"]["level"]
try:
oldlevel = db[player]["overwatch"]["level"]
except KeyError:
oldlevel = 0
if level > oldlevel:
2016-08-13 18:03:47 +00:00
# Send the message
loop.create_task(send_event(eventmsg=s.overwatch_level_up, player=player, level=level))
2016-08-13 18:03:47 +00:00
# Update database
db[player]["overwatch"]["level"] = level
2017-02-09 14:37:01 +00:00
save_db()
2016-11-02 13:45:41 +00:00
# Check for rank changes
rank = r["data"]["competitive"]["rank"]
if rank is not None:
rank = int(rank)
try:
oldrank = int(db[player]["overwatch"]["rank"])
except KeyError:
oldrank = 0
if rank != oldrank:
2016-11-02 13:45:41 +00:00
# Send the message
2017-01-09 07:37:09 +00:00
loop.create_task(send_event(eventmsg=s.overwatch_rank_change,
player=player, change=overwatch.format_rankchange(rank-oldrank),
2017-01-09 07:37:09 +00:00
rank=rank, medal=overwatch.url_to_medal(r["data"]["competitive"]["rank_img"])))
2016-11-02 13:45:41 +00:00
# Update database
db[player]["overwatch"]["rank"] = rank
2017-02-09 13:52:16 +00:00
save_db()
2016-08-13 18:03:47 +00:00
finally:
2017-02-09 14:38:30 +00:00
await asyncio.sleep(1)
2016-08-13 13:52:11 +00:00
print("[Overwatch] Check completed successfully.")
2016-08-13 13:36:08 +00:00
# Wait for the timeout
await asyncio.sleep(timeout)
else:
await asyncio.sleep(1)
2017-02-09 14:31:44 +00:00
2016-08-13 13:36:08 +00:00
async def league_rank_change(timeout):
2017-02-09 14:31:44 +00:00
"""Check for League of Legends solo-duo ranked status changes."""
2016-08-13 13:36:08 +00:00
while True:
if discord_is_ready:
2016-08-13 18:03:47 +00:00
print("[League] Starting check for rank changes...")
2016-08-13 13:36:08 +00:00
# Update data for every player in list
for player in db:
if "league" in db[player]:
try:
r = await league.get_player_rank(**db[player]["league"])
except league.NoRankedGamesCompletedException:
# If the player has no ranked games completed, skip him
pass
2016-08-13 13:56:27 +00:00
except league.RateLimitException:
# If you've been ratelimited, skip the player and notify the console.
print("[League] Request rejected for rate limit.")
except Exception:
# If some other error occours, skip the player
print("[League] Request returned an unhandled exception.")
2016-08-13 13:36:08 +00:00
else:
# Convert tier into a number
tier_number = league.ranklist.index(r["tier"])
roman_number = league.roman.index(r["entries"][0]["division"]) # Potrebbe non funzionare
try:
old_tier_number = db[player]["league"]["tier"]
old_roman_number = db[player]["league"]["division"]
except KeyError:
# Bronze VI?
old_tier_number = 0
old_roman_number = 5
2016-08-13 13:36:08 +00:00
# Check for tier changes
if tier_number != old_tier_number or roman_number != old_roman_number:
2016-08-13 14:23:58 +00:00
# Send the message
loop.create_task(send_event(eventmsg=s.league_rank_up, player=player, tier=s.league_tier_list[tier_number], division=s.league_roman_list[roman_number],
oldtier=s.league_tier_list[old_tier_number], olddivision=s.league_roman_list[old_roman_number]))
2016-08-13 13:36:08 +00:00
# Update database
db[player]["league"]["tier"] = tier_number
db[player]["league"]["division"] = roman_number
2017-02-09 13:52:16 +00:00
save_db()
2016-08-13 13:57:38 +00:00
finally:
2016-08-13 13:52:11 +00:00
# Prevent getting ratelimited by Riot
2016-08-13 18:03:47 +00:00
await asyncio.sleep(2)
print("[League] Rank check completed.")
# Wait for the timeout
await asyncio.sleep(timeout)
else:
await asyncio.sleep(1)
2017-02-09 14:31:44 +00:00
2016-08-13 18:03:47 +00:00
async def league_level_up(timeout):
"""Check for League of Legends profile level ups and name changes."""
2016-08-13 18:03:47 +00:00
while True:
if discord_is_ready:
print("[League] Starting check for level changes...")
# Update data for every player in list
for player in db:
if "league" in db[player]:
try:
r = await league.get_player_info(**db[player]["league"])
except league.RateLimitException:
# If you've been ratelimited, skip the player and notify the console.
print("[League] Request rejected for rate limit.")
except Exception:
# If some other error occours, skip the player
print("[League] Request returned an unhandled exception.")
2016-08-13 18:03:47 +00:00
else:
# Update summoner name
name = r["name"]
db[player]["league"]["name"] = name
2016-08-13 18:03:47 +00:00
# Check for level changes
level = r["summonerLevel"]
try:
old_level = db[player]["league"]["level"]
except KeyError:
old_level = 0
if level > old_level:
2016-08-13 18:03:47 +00:00
# Send the message
loop.create_task(send_event(eventmsg=s.league_level_up, player=player, level=level))
2016-08-13 18:03:47 +00:00
# Update database
db[player]["league"]["level"] = level
save_db()
2016-08-13 18:03:47 +00:00
finally:
# Prevent getting ratelimited by Riot
await asyncio.sleep(2)
print("[League] Level check completed.")
2016-08-13 13:36:08 +00:00
# Wait for the timeout
await asyncio.sleep(timeout)
else:
await asyncio.sleep(1)
2016-08-12 17:21:43 +00:00
2017-02-09 14:31:44 +00:00
2016-08-16 20:16:22 +00:00
async def brawlhalla_update_mmr(timeout):
2017-02-09 14:31:44 +00:00
"""Check for Brawlhalla MMR changes."""
2016-08-16 20:16:22 +00:00
while True:
if discord_is_ready:
print("[Brawlhalla] Starting check for mmr changes...")
# Update mmr for every player in list
for player in db:
if "brawlhalla" in db[player]:
try:
r = await brawlhalla.get_leaderboard_for(db[player]["brawlhalla"]["username"])
2016-08-17 21:46:58 +00:00
except None:
2016-08-16 20:16:22 +00:00
print("[Brawlhalla] Request returned an unhandled exception.")
else:
# Parse the page
2016-08-17 21:46:58 +00:00
bs = bs4.BeautifulSoup(r.text, "html.parser")
2016-08-16 20:16:22 +00:00
# Divide the page into rows
rows = bs.find_all("tr")
# Find the row containing the rank
for row in rows:
# Skip header rows
2016-08-17 21:46:58 +00:00
if row.has_attr('id') and row['id'] == "rheader":
2016-08-16 20:16:22 +00:00
continue
# Check if the row belongs to the correct player
# (Brawlhalla searches aren't case sensitive)
2016-08-17 21:46:58 +00:00
columns = list(row.children)
for column in columns:
2016-08-16 20:16:22 +00:00
# Find the player name column
2016-08-17 21:46:58 +00:00
if column.has_attr('class') and column['class'][0] == "pnameleft":
2016-08-16 20:16:22 +00:00
# Check if the name matches the parameter
if column.string == db[player]["brawlhalla"]["username"]:
break
else:
continue
# Get the current mmr
2016-08-17 21:46:58 +00:00
mmr = int(list(row.children)[7].string)
2016-11-08 14:20:46 +00:00
try:
old_mmr = db[player]["brawlhalla"]["mmr"]
except KeyError:
old_mmr = 0
2016-08-16 20:16:22 +00:00
# Compare the mmr with the value saved in the database
2016-11-08 14:20:46 +00:00
if mmr != old_mmr:
2016-08-16 20:16:22 +00:00
# Send a message
2016-11-08 18:37:39 +00:00
loop.create_task(send_event(s.brawlhalla_new_mmr, player=player, mmr=mmr, oldmmr=old_mmr))
2016-08-16 20:16:22 +00:00
# Update database
db[player]["brawlhalla"]["mmr"] = mmr
2017-02-09 13:52:16 +00:00
save_db()
2016-08-16 20:16:22 +00:00
break
finally:
await asyncio.sleep(1)
2016-08-17 21:46:58 +00:00
print("[Brawlhalla] Request returned an unhandled exception.")
2016-08-17 18:26:20 +00:00
await asyncio.sleep(timeout)
else:
await asyncio.sleep(1)
2016-08-16 20:16:22 +00:00
2017-02-09 14:31:44 +00:00
2016-11-08 18:37:39 +00:00
async def opendota_last_match(timeout):
2017-02-09 14:31:44 +00:00
"""Check for new played Dota 2 matches using the OpenDota API."""
2016-11-08 18:37:39 +00:00
while True:
if discord_is_ready:
print("[OpenDota] Starting last match check...")
# Check for new dota match for every player in the database
for player in db:
try:
# TODO: Se uno non ha mai giocato a dota, cosa succede? Aggiungere handling
2016-11-08 20:07:23 +00:00
r = await opendota.get_latest_match(db[player]["steam"]["steamid"])
2016-11-08 18:37:39 +00:00
except KeyError:
continue
else:
try:
old_last = db[player]["dota"]["lastmatch"]
except KeyError:
old_last = 0
last = r["match_id"]
if last > old_last:
2016-12-19 18:56:37 +00:00
# Get player team
# 0 if radiant
# 1 if dire
team = r["player_slot"] & 0b10000000 >> 7
# Get victory status
victory = (bool(team) == r["radiant_win"])
# Prepare format map
f = {
"k": r["kills"],
"d": r["deaths"],
"a": r["assists"],
"player": player,
"result": s.won if victory else s.lost,
"hero": opendota.get_hero_name(r["hero_id"])
}
2016-11-08 18:37:39 +00:00
# Send a message
2016-12-19 18:56:37 +00:00
loop.create_task(send_event(s.dota_new_match, **f))
2016-11-08 18:37:39 +00:00
# Update database
2016-12-19 18:56:37 +00:00
try:
db[player]["dota"]["lastmatch"] = last
except KeyError:
db[player]["dota"] = {
"lastmatch": last
}
2017-02-09 13:52:16 +00:00
save_db()
2016-11-08 18:37:39 +00:00
finally:
await asyncio.sleep(2)
print("[OpenDota] Check successful.")
await asyncio.sleep(timeout)
else:
await asyncio.sleep(1)
2017-02-07 21:24:49 +00:00
async def osu_pp(timeout):
2017-02-09 14:31:44 +00:00
"""Check for changes in Osu! pp."""
2017-02-07 21:24:49 +00:00
while True:
if discord_is_ready:
print("[Osu!] Starting pp check...")
for mode in range(0, 4):
for player in db:
try:
r = await osu.get_user(db[player]["osu"]["id"], mode)
except KeyError:
continue
else:
if r["pp_raw"] is not None:
pp = float(r["pp_raw"])
else:
pp = 0
if pp != 0:
try:
old = db[player]["osu"][str(mode)]
except KeyError:
old = 0
if pp != old:
db[player]["osu"][str(mode)] = pp
f = {
"player": player,
"mode": s.osu_modes[mode],
"pp": int(pp),
"change": int(pp - old)
}
loop.create_task(send_event(s.osu_pp_change, **f))
else:
db[player]["osu"][str(mode)] = 0.0
2017-02-09 13:52:16 +00:00
save_db()
2017-02-07 21:24:49 +00:00
finally:
2017-02-07 21:27:50 +00:00
await asyncio.sleep(5)
2017-02-07 21:24:49 +00:00
print("[Osu!] Check successful.")
await asyncio.sleep(timeout)
else:
2017-02-07 21:27:50 +00:00
await asyncio.sleep(1)
2017-02-07 21:24:49 +00:00
2016-08-13 14:23:58 +00:00
async def send_event(eventmsg: str, player: str, **kwargs):
2017-02-09 14:31:44 +00:00
"""Send a message about a new event on both Telegram and Discord"""
2016-08-13 14:23:58 +00:00
# Create arguments dict
mapping = kwargs.copy()
mapping["eventmsg"] = None
# Discord
# The user id is the player argument; convert that into a mention
mapping["player"] = "<@" + player + ">"
# Format the event message
msg = eventmsg.format(**mapping)
# Send the message
loop.create_task(d_client.send_message(d_client.get_channel("213655027842154508"), msg))
# Telegram
# Find the matching Telegram username inside the db
mapping["player"] = "@" + db[player]["telegram"]["username"]
# Convert the Discord Markdown to Telegram Markdown
msg = eventmsg.replace("**", "*")
# Format the event message
msg = msg.format(**mapping)
# Send the message
loop.create_task(telegram.send_message(msg, -2141322))
2017-02-07 21:26:53 +00:00
loop.create_task(overwatch_status_change(900))
print("[Overwatch] Added level up check to the queue.")
2017-02-07 21:24:49 +00:00
2017-02-07 21:26:53 +00:00
loop.create_task(league_rank_change(900))
print("[League] Added rank change check to the queue.")
2016-08-13 13:52:11 +00:00
2017-02-07 21:26:53 +00:00
loop.create_task(league_level_up(900))
print("[League] Added level change check to the queue.")
2016-08-12 20:53:12 +00:00
2017-02-07 21:24:49 +00:00
#loop.create_task(brawlhalla_update_mmr(7200))
#print("[Brawlhalla] Added mmr change check to the queue.")
2016-08-13 18:03:47 +00:00
2017-02-07 21:24:49 +00:00
#loop.create_task(opendota_last_match(600))
#print("[OpenDota] Added last match check to the queue.")
2016-08-17 18:26:20 +00:00
2017-02-07 21:26:53 +00:00
loop.create_task(osu_pp(1800))
2017-02-07 21:24:49 +00:00
print("[Osu!] Added pp change check to the queue.")
2016-08-17 18:26:20 +00:00
2017-02-09 13:52:16 +00:00
# Run until ^C
2016-08-12 20:53:12 +00:00
try:
loop.run_until_complete(d_client.start(token))
except KeyboardInterrupt:
loop.run_until_complete(d_client.logout())
finally:
loop.close()