Compare commits

..

No commits in common. "9d8ad73c51a456520a4c2def344a20d7cb3b5ac8" and "3d5f2e3de433d100cdbf9993455ad036e76765dc" have entirely different histories.

4 changed files with 23 additions and 128 deletions

View file

@ -4,6 +4,5 @@ The bot is user-installable so the commands can either be added to a guild or yo
Invite: https://discord.com/oauth2/authorize?client_id=1365149865444905121 Invite: https://discord.com/oauth2/authorize?client_id=1365149865444905121
# Building # Building
inside the folder inside the folder
`docker build -t mmolbbot .` `docker build . -t mmolbbot`
# Hosting `docker run mmolbbot -e TOKEN=<Token> -e OWNER_GUILD=<guild with management commands>`
`docker run -e TOKEN=<Token> -e OWNER_GUILD=<guild with management commands> -e ERROR_CHANNEL=<error channel id> -e DB_PATH="./mmolb.db" mmolbbot`

6
bot.py
View file

@ -63,7 +63,6 @@ async def on_ready():
await db.commit() await db.commit()
bot.db = db bot.db = db
bot.cur = cur bot.cur = cur
bot.error_channel = int(os.getenv("ERROR_CHANNEL"))
guild_list = [] guild_list = []
async for guild in bot.fetch_guilds(): async for guild in bot.fetch_guilds():
guild_list.append(guild.id) guild_list.append(guild.id)
@ -116,15 +115,14 @@ cog: str = SlashOption(required=False)
) )
@application_checks.is_owner() @application_checks.is_owner()
async def delliveupdates(interaction: nextcord.Interaction, async def delliveupdates(interaction: nextcord.Interaction,
confirm: str = SlashOption(required=False), confirm: str = SlashOption(required=False)
classic: int = SlashOption(required=False)
): ):
if confirm == "yes, do as I say!": if confirm == "yes, do as I say!":
await db.execute(f"""DELETE from liveupdate""") await db.execute(f"""DELETE from liveupdate""")
await db.commit() await db.commit()
await interaction.response.send_message("all gone...") await interaction.response.send_message("all gone...")
else: else:
res = await db.execute("SELECT COUNT (*) from liveupdate WHERE classic = ?",(classic,)) res = await db.execute("SELECT COUNT (*) from liveupdate")
res, = await res.fetchone() res, = await res.fetchone()
await interaction.response.send_message(f"There are currently {res} live updates") await interaction.response.send_message(f"There are currently {res} live updates")

View file

@ -10,7 +10,6 @@ import itertools
import aiosqlite as sqlite3 import aiosqlite as sqlite3
from nextcord.ext import commands, application_checks, tasks from nextcord.ext import commands, application_checks, tasks
from nextcord import TextInputStyle, IntegrationType from nextcord import TextInputStyle, IntegrationType
import re
import timeit import timeit
timings = [] timings = []
@ -87,10 +86,10 @@ async def livegameworker(self,serverid,userid,channelid,messageid,gameid,offset)
#await self.bot.db.commit() #await self.bot.db.commit()
if message: if message:
await message.edit(f"An error occoured in this live update\n{e}") await message.edit(f"An error occoured in this live update\n{e}")
warning = self.bot.get_channel(self.bot.error_channel) warning = self.bot.get_channel(1365478368555827270)
await warning.send(e) await warning.send(e)
except nextcord.Forbidden: except nextcord.Forbidden:
warning = self.bot.get_channel(self.bot.error_channel) warning = self.bot.get_channel(1365478368555827270)
await self.bot.db.execute("DELETE from teamsubscriptions WHERE serverid = ?", (lastserverid,)) await self.bot.db.execute("DELETE from teamsubscriptions WHERE serverid = ?", (lastserverid,))
await self.bot.db.execute("DELETE from liveupdate WHERE serverid = ?", (lastserverid,)) await self.bot.db.execute("DELETE from liveupdate WHERE serverid = ?", (lastserverid,))
await self.bot.db.execute("DELETE from spotlightsubscriptions WHERE serverid = ?", (lastserverid,)) await self.bot.db.execute("DELETE from spotlightsubscriptions WHERE serverid = ?", (lastserverid,))
@ -136,75 +135,16 @@ async def classiclivegameworker(self,serverid,userid,channelid,gameid,offset):
UPDATE liveupdate set offset = {offset+offsetadd} WHERE channelid = '{channelid}' AND gameid = '{gameid}' AND classic = 1 UPDATE liveupdate set offset = {offset+offsetadd} WHERE channelid = '{channelid}' AND gameid = '{gameid}' AND classic = 1
""") """)
except Exception as e: except Exception as e:
warning = self.bot.get_channel(self.bot.error_channel) warning = self.bot.get_channel(1365478368555827270)
await warning.send(e) await warning.send(e)
except nextcord.Forbidden: except nextcord.Forbidden:
warning = self.bot.get_channel(self.bot.error_channel) warning = self.bot.get_channel(1365478368555827270)
await self.bot.db.execute("DELETE from teamsubscriptions WHERE serverid = ?", (lastserverid,)) await self.bot.db.execute("DELETE from teamsubscriptions WHERE serverid = ?", (lastserverid,))
await self.bot.db.execute("DELETE from liveupdate WHERE serverid = ?", (lastserverid,)) await self.bot.db.execute("DELETE from liveupdate WHERE serverid = ?", (lastserverid,))
await self.bot.db.execute("DELETE from spotlightsubscriptions WHERE serverid = ?", (lastserverid,)) await self.bot.db.execute("DELETE from spotlightsubscriptions WHERE serverid = ?", (lastserverid,))
await self.bot.db.commit() await self.bot.db.commit()
await warning.send(f"Deleted {lastserverid} from the database due to 403 error") await warning.send(f"Deleted {lastserverid} from the database due to 403 error")
async def statisticallivegameworker(self,serverid,userid,channelid,gameid,offset):
begin = timeit.default_timer()
lastserverid = serverid
try:
async with aiohttp.ClientSession() as session:
channel = self.bot.get_channel(channelid)
data = await session.get(f"https://mmolb.com/api/game/{gameid}/live?after={offset}")
data = await data.json()
basedata = await session.get(f"https://mmolb.com/api/game/{gameid}")
basedata = await basedata.json()
if basedata["State"] == "Complete":
await self.bot.db.execute(f"""
DELETE from liveupdate WHERE channelid = {channelid} AND gameid = '{gameid}'
""")
if len(data["entries"]) > 0:
finalstr = ""
offsetadd = 0
maysend = False
for i in data["entries"]:
offsetadd += 1
if i["event"] == "InningEnd":
finalstr += f"\n{i['message']} | {basedata["AwayTeamName"]} {basedata["AwayTeamEmoji"]} {data["entries"][-1]["away_score"]} vs {basedata["HomeTeamName"]} {basedata["HomeTeamEmoji"]} {data["entries"][-1]["home_score"]}"
maysend = True
for r in re.findall(r'[A-Za-z éö1-9]*out[A-Za-z éö1-9]*',i['message'],re.IGNORECASE):
finalstr += f"\n🔴 {r}"
maysend = True
if "scores" in i['message'] or "homers" in i['message']:
if data["entries"][-1]["inning_side"] == 1:
finalstr += f"\n{basedata["AwayTeamName"]} {basedata["AwayTeamEmoji"]} {data["entries"][-1]["away_score"]} vs {basedata["HomeTeamName"]} {basedata["HomeTeamEmoji"]} **{data["entries"][-1]["home_score"]}**"
else:
finalstr += f"\n{basedata["AwayTeamName"]} {basedata["AwayTeamEmoji"]} **{data["entries"][-1]["away_score"]}** vs {basedata["HomeTeamName"]} {basedata["HomeTeamEmoji"]} {data["entries"][-1]["home_score"]}"
for r in re.findall(r'(?<=<strong>)([A-Za-z, !.]+)(?=<\/strong>)',i['message'],re.IGNORECASE):
finalstr += f"\n🟢 {r}"
maysend = True
for r in re.findall(r'(?:[A-Za-z éö]*)(?:walks?|steals?|error|signles?|doubles?|triples?|to (?:first|second|third) base)(?:[A-Za-z éö]*)',i['message'],re.IGNORECASE):
finalstr += f"\n👟 {r}"
maysend = True
if i["event"] == "Recordkeeping":
await self.bot.db.execute(f"""
DELETE from liveupdate WHERE channelid = {channelid} AND gameid = '{gameid}'
""")
maysend = True
finalstr += f"{i['message'].replace("<strong>", "**").replace("</strong>", "**")}\n"
if maysend:
await channel.send(finalstr)
await self.bot.db.execute(f"""
UPDATE liveupdate set offset = {offset+offsetadd} WHERE channelid = '{channelid}' AND gameid = '{gameid}' AND classic = 2
""")
except Exception as e:
warning = self.bot.get_channel(self.bot.error_channel)
await warning.send(e)
except nextcord.Forbidden:
warning = self.bot.get_channel(self.bot.error_channel)
await self.bot.db.execute("DELETE from teamsubscriptions WHERE serverid = ?", (lastserverid,))
await self.bot.db.execute("DELETE from liveupdate WHERE serverid = ?", (lastserverid,))
await self.bot.db.execute("DELETE from spotlightsubscriptions WHERE serverid = ?", (lastserverid,))
await self.bot.db.commit()
await warning.send(f"Deleted {lastserverid} from the database due to 403 error")
async def spotlightsubscriptionworker(self,serverid,channelid,classic,gameid,data): async def spotlightsubscriptionworker(self,serverid,channelid,classic,gameid,data):
try: try:
@ -212,8 +152,6 @@ async def spotlightsubscriptionworker(self,serverid,channelid,classic,gameid,dat
test = await check.fetchone() test = await check.fetchone()
if test is None: if test is None:
channel = self.bot.get_channel(channelid) channel = self.bot.get_channel(channelid)
if channel is None:
return
if data["State"] == "Complete": if data["State"] == "Complete":
return return
check = await self.bot.db.execute("SELECT serverid,userid,channelid,messageid,gameid,offset FROM liveupdate WHERE channelid = ? AND gameid = ? AND classic = ?", (channelid,gameid,classic)) check = await self.bot.db.execute("SELECT serverid,userid,channelid,messageid,gameid,offset FROM liveupdate WHERE channelid = ? AND gameid = ? AND classic = ?", (channelid,gameid,classic))
@ -226,7 +164,6 @@ async def spotlightsubscriptionworker(self,serverid,channelid,classic,gameid,dat
({channel.guild.id}, {self.bot.application_id}, {channelid}, {message.id}, "{gameid}", {len(data["EventLog"])}, 0) ({channel.guild.id}, {self.bot.application_id}, {channelid}, {message.id}, "{gameid}", {len(data["EventLog"])}, 0)
""") """)
else: else:
await channel.send(content=f"{data["AwayTeamName"]} {data["AwayTeamEmoji"]} vs {data["HomeTeamName"]} {data["HomeTeamEmoji"]}\n> PLAY BALL")
await self.bot.db.execute(f""" await self.bot.db.execute(f"""
INSERT INTO liveupdate VALUES INSERT INTO liveupdate VALUES
({channel.guild.id}, {self.bot.application_id}, {channelid}, NULL, "{gameid}", {len(data["EventLog"])}, 1) ({channel.guild.id}, {self.bot.application_id}, {channelid}, NULL, "{gameid}", {len(data["EventLog"])}, 1)
@ -235,10 +172,10 @@ async def spotlightsubscriptionworker(self,serverid,channelid,classic,gameid,dat
await self.bot.db.close() await self.bot.db.close()
self.checkspotlightsubscriptions.cancel() self.checkspotlightsubscriptions.cancel()
self.checkteamsubscriptions.cancel() self.checkteamsubscriptions.cancel()
warning = self.bot.get_channel(self.bot.error_channel) warning = self.bot.get_channel(1365478368555827270)
await warning.send(f"<@{self.bot.owner_id}> database is locked!") await warning.send(f"<@{self.bot.owner_id}> database is locked!")
except Exception as e: except Exception as e:
warning = self.bot.get_channel(self.bot.error_channel) warning = self.bot.get_channel(1365478368555827270)
await warning.send(f"Ignoring exception in spotlight check: {e}") await warning.send(f"Ignoring exception in spotlight check: {e}")
print(e) print(e)
return return
@ -268,28 +205,21 @@ async def teamsubscriptionworker(self,serverid,channelid,teamid,classic):
INSERT INTO liveupdate VALUES INSERT INTO liveupdate VALUES
({channel.guild.id}, {self.bot.application_id}, {channelid}, {message.id}, "{gameid}", {len(data["EventLog"])}, 0) ({channel.guild.id}, {self.bot.application_id}, {channelid}, {message.id}, "{gameid}", {len(data["EventLog"])}, 0)
""") """)
elif classic == 1: else:
await channel.send(content=f"{data["AwayTeamName"]} {data["AwayTeamEmoji"]} vs {data["HomeTeamName"]} {data["HomeTeamEmoji"]}\n> PLAY BALL")
await self.bot.db.execute(f""" await self.bot.db.execute(f"""
INSERT INTO liveupdate VALUES INSERT INTO liveupdate VALUES
({channel.guild.id}, {self.bot.application_id}, {channelid}, NULL, "{gameid}", {len(data["EventLog"])}, 1) ({channel.guild.id}, {self.bot.application_id}, {channelid}, NULL, "{gameid}", {len(data["EventLog"])}, 1)
""") """)
else:
await channel.send(content=f"{data["AwayTeamName"]} {data["AwayTeamEmoji"]} vs {data["HomeTeamName"]} {data["HomeTeamEmoji"]}\n🤖 PLAY BALL")
await self.bot.db.execute(f"""
INSERT INTO liveupdate VALUES
({channel.guild.id}, {self.bot.application_id}, {channelid}, NULL, "{gameid}", {len(data["EventLog"])}, 2)
""")
except KeyError: except KeyError:
return return
except sqlite3.OperationalError: except sqlite3.OperationalError:
await self.bot.db.close() await self.bot.db.close()
self.checkspotlightsubscriptions.cancel() self.checkspotlightsubscriptions.cancel()
self.checkteamsubscriptions.cancel() self.checkteamsubscriptions.cancel()
warning = self.bot.get_channel(self.bot.error_channel) warning = self.bot.get_channel(1365478368555827270)
await warning.send(f"<@{self.bot.owner_id}> database is locked!") await warning.send(f"<@{self.bot.owner_id}> database is locked!")
except Exception as e: except Exception as e:
warning = self.bot.get_channel(self.bot.error_channel) warning = self.bot.get_channel(1365478368555827270)
await warning.send(f"Ignoring exception in {teamid}: {e}") await warning.send(f"Ignoring exception in {teamid}: {e}")
print(e) print(e)
return return
@ -309,15 +239,15 @@ async def feedsubscriptionworker(self,serverid,channelid,teamid,offset):
finalstr = "" finalstr = ""
for index in itertools.islice(data, offset, len(data)): for index in itertools.islice(data, offset, len(data)):
finalstr += f"\n{index['emoji']} Season {index['season']} Day {index['day']}: {index['text']}" finalstr += f"\n{index['emoji']} Season {index['season']} Day {index['day']}: {index['text']}"
await channel.send(finalstr)
await self.bot.db.execute(f""" await self.bot.db.execute(f"""
UPDATE feedsubscriptions set offset = {len(data)} WHERE channelid = '{channelid}' AND teamid = '{teamid}' UPDATE feedsubscriptions set offset = {len(data)} WHERE channelid = '{channelid}' AND teamid = '{teamid}'
""") """)
await channel.send(finalstr)
except Exception as e: except Exception as e:
warning = self.bot.get_channel(self.bot.error_channel) warning = self.bot.get_channel(1365478368555827270)
await warning.send(e) await warning.send(e)
except nextcord.Forbidden: except nextcord.Forbidden:
warning = self.bot.get_channel(self.bot.error_channel) warning = self.bot.get_channel(1365478368555827270)
await self.bot.db.execute("DELETE from teamsubscriptions WHERE serverid = ?", (lastserverid,)) await self.bot.db.execute("DELETE from teamsubscriptions WHERE serverid = ?", (lastserverid,))
await self.bot.db.execute("DELETE from liveupdate WHERE serverid = ?", (lastserverid,)) await self.bot.db.execute("DELETE from liveupdate WHERE serverid = ?", (lastserverid,))
await self.bot.db.execute("DELETE from spotlightsubscriptions WHERE serverid = ?", (lastserverid,)) await self.bot.db.execute("DELETE from spotlightsubscriptions WHERE serverid = ?", (lastserverid,))
@ -495,32 +425,6 @@ class liveupdate(commands.Cog):
thanksdiscord = closestteam[:20] thanksdiscord = closestteam[:20]
await interaction.response.send_autocomplete(thanksdiscord) await interaction.response.send_autocomplete(thanksdiscord)
@subscribe.subcommand(
name="statistical",
description="Subscribe to a team using a modified version of classic, will spam the channel",
)
async def statisitcalteamsubscribe(self, interaction: nextcord.Interaction, team: str):
if team not in self.bot.teams_dict:
await interaction.response.send_message("Invalid Team!", ephemeral=True)
await interaction.response.defer()
teamid = self.bot.teams_dict[team]
await interaction.edit_original_message(content="This channel is now subscribed to updates")
await self.bot.db.execute(f"""
INSERT INTO teamsubscriptions VALUES
({interaction.guild_id}, {interaction.channel_id}, "{teamid}", 2)
""")
await self.bot.db.commit()
@statisitcalteamsubscribe.on_autocomplete("team")
async def statisitcalteamsubscribeac(self, interaction: nextcord.Interaction, team: str):
if not team:
thanksdiscord = self.bot.teams_list[:20]
await interaction.response.send_autocomplete(thanksdiscord)
return
closestteam = [name for name in self.bot.teams_list if name.lower().startswith(team.lower())]
thanksdiscord = closestteam[:20]
await interaction.response.send_autocomplete(thanksdiscord)
@subscribe.subcommand( @subscribe.subcommand(
name="feed", name="feed",
description="Subscribe to a team's feed", description="Subscribe to a team's feed",
@ -685,7 +589,7 @@ class liveupdate(commands.Cog):
@tasks.loop(seconds=30.0) @tasks.loop(seconds=30.0)
async def updatelivegames(self): async def updatelivegames(self):
warning = self.bot.get_channel(self.bot.error_channel) warning = self.bot.get_channel(1365478368555827270)
try: try:
begin = timeit.default_timer() begin = timeit.default_timer()
await self.bot.wait_until_ready() await self.bot.wait_until_ready()
@ -695,9 +599,6 @@ class liveupdate(commands.Cog):
res = await self.bot.db.execute("SELECT serverid,userid,channelid,gameid,offset FROM liveupdate WHERE classic = 1") res = await self.bot.db.execute("SELECT serverid,userid,channelid,gameid,offset FROM liveupdate WHERE classic = 1")
res = await res.fetchall() res = await res.fetchall()
worklist = worklist + [classiclivegameworker(self,serverid,userid,channelid,gameid,offset) for [serverid,userid,channelid,gameid,offset] in res] worklist = worklist + [classiclivegameworker(self,serverid,userid,channelid,gameid,offset) for [serverid,userid,channelid,gameid,offset] in res]
res = await self.bot.db.execute("SELECT serverid,userid,channelid,gameid,offset FROM liveupdate WHERE classic = 2")
res = await res.fetchall()
worklist = worklist + [statisticallivegameworker(self,serverid,userid,channelid,gameid,offset) for [serverid,userid,channelid,gameid,offset] in res]
await asyncio.gather(*worklist,return_exceptions=True) await asyncio.gather(*worklist,return_exceptions=True)
await self.bot.db.commit() await self.bot.db.commit()
game = nextcord.Game(f"Broadcasting {len(worklist)} games") game = nextcord.Game(f"Broadcasting {len(worklist)} games")
@ -715,7 +616,7 @@ class liveupdate(commands.Cog):
await warning.send(finalstr) await warning.send(finalstr)
timings.clear() timings.clear()
except Exception as e: except Exception as e:
#warning = self.bot.get_channel(self.bot.error_channel) #warning = self.bot.get_channel(1365478368555827270)
await warning.send(e) await warning.send(e)
print(e) print(e)
@ -732,10 +633,8 @@ class liveupdate(commands.Cog):
game = await game.json() game = await game.json()
gameid = game["game_id"] gameid = game["game_id"]
except KeyError: except KeyError:
game = await session.get("https://mmolb.com/api/superstar-games") game = await session.get("https://mmolb.com/api/event-games")
game = await game.json() game = await game.json()
if game["games"][-1]['status'] == "Scheduled": #The game has been posted to the api but doesn't exist
return
gameid = game["games"][-1]["game_id"] gameid = game["games"][-1]["game_id"]
data = await session.get(f"https://mmolb.com/api/game/{gameid}") data = await session.get(f"https://mmolb.com/api/game/{gameid}")
data = await data.json() data = await data.json()
@ -749,7 +648,7 @@ class liveupdate(commands.Cog):
except Exception as e: except Exception as e:
#I know this is bad practice but these loops must be running #I know this is bad practice but these loops must be running
print(e) print(e)
warning = self.bot.get_channel(self.bot.error_channel) warning = self.bot.get_channel(1365478368555827270)
await warning.send(e) await warning.send(e)
return return
@ -765,7 +664,7 @@ class liveupdate(commands.Cog):
await self.bot.db.commit() await self.bot.db.commit()
except Exception as e: except Exception as e:
#I know this is bad practice but these loops must be running #I know this is bad practice but these loops must be running
warning = self.bot.get_channel(self.bot.error_channel) warning = self.bot.get_channel(1365478368555827270)
await warning.send(e) await warning.send(e)
print(e) print(e)
return return
@ -781,7 +680,7 @@ class liveupdate(commands.Cog):
await self.bot.db.commit() await self.bot.db.commit()
except Exception as e: except Exception as e:
#I know this is bad practice but these loops must be running #I know this is bad practice but these loops must be running
warning = self.bot.get_channel(self.bot.error_channel) warning = self.bot.get_channel(1365478368555827270)
await warning.send(e) await warning.send(e)
print(e) print(e)
return return

View file

@ -294,9 +294,8 @@ class team(commands.Cog):
if i["_id"] == teamid: if i["_id"] == teamid:
break break
color = tuple(int(data["Color"][i:i+2], 16) for i in (0, 2, 4)) color = tuple(int(data["Color"][i:i+2], 16) for i in (0, 2, 4))
embed = nextcord.Embed(title=f"{data["Location"]} {data["Name"]} {data["Emoji"]}",description=f"{"Inactive" if not data['Active'] else "Active"}", colour = nextcord.Color.from_rgb(color[0], color[1], color[2])) embed = nextcord.Embed(title=f"{data["Location"]} {data["Name"]} {data["Emoji"]}", description=f"{data["Motto"]}", colour = nextcord.Color.from_rgb(color[0], color[1], color[2]))
embed.add_field(name="League", value=f"{dict((v,k) for k,v in self.bot.leagues_dict.items())[data["League"]]}", inline=True) embed.add_field(name="League", value=f"{dict((v,k) for k,v in self.bot.leagues_dict.items())[data["League"]]}", inline=True)
embed.add_field(name="Ballpark", value=data['BallparkName'])
embed.add_field(name="Wins", value=f"{data["Record"]["Regular Season"]["Wins"]}", inline=True) embed.add_field(name="Wins", value=f"{data["Record"]["Regular Season"]["Wins"]}", inline=True)
embed.add_field(name="Losses", value=f"{data["Record"]["Regular Season"]["Losses"]}", inline=True) embed.add_field(name="Losses", value=f"{data["Record"]["Regular Season"]["Losses"]}", inline=True)
embed.add_field(name="Run Differential", value=f"{data["Record"]["Regular Season"]["RunDifferential"]}", inline=True) embed.add_field(name="Run Differential", value=f"{data["Record"]["Regular Season"]["RunDifferential"]}", inline=True)