import hashlib import json from pathlib import Path from datetime import datetime, timedelta, timezone import requests import asyncio import nextcord import aiosqlite as sqlite3 from nextcord.ext import commands, application_checks, tasks from nextcord import TextInputStyle, IntegrationType class liveupdate(commands.Cog): def __init__(self, bot: commands.Bot): self.bot = bot self.updatelivegames.start() self.checkspotlightsubscriptions.start() self.checkteamsubscriptions.start() def cog_unload(self): self.updatelivegames.cancel() self.checkspotlightsubscriptions.cancel() self.checkteamsubscriptions.cancel() @nextcord.slash_command( name="spotlightgame", description="Watch the spotlight game", integration_types=[ IntegrationType.guild_install, ], contexts=[ nextcord.InteractionContextType.guild, nextcord.InteractionContextType.private_channel, ], force_global=True, ) async def spotlightwatch(self, interaction: nextcord.Interaction): await interaction.response.defer() game = requests.get("https://mmolb.com/api/spotlight").json() gameid = game["game_id"] data = requests.get(f"https://mmolb.com/api/game/{gameid}").json() await interaction.edit_original_message(content=f"{data["AwayTeamName"]} {data["AwayTeamEmoji"]} **{data["EventLog"][-1]["away_score"]}** vs {data["HomeTeamName"]} {data["HomeTeamEmoji"]} **{data["EventLog"][-1]["home_score"]}**") message = await interaction.original_message() if data["State"] == "Complete": return await self.bot.db.execute(f""" INSERT INTO liveupdate VALUES ({interaction.guild_id}, {interaction.user.id}, {interaction.channel_id}, {message.id}, "{gameid}", {len(data["EventLog"])}) """) await self.bot.db.commit() @nextcord.slash_command(name="subscribe", description="Subscribe to...", integration_types=[ IntegrationType.guild_install, ], contexts=[ nextcord.InteractionContextType.guild, nextcord.InteractionContextType.private_channel, ], force_global=True, default_member_permissions=nextcord.Permissions(manage_channels=True),) async def subscribe(self, interaction: nextcord.Interaction): #This is never called pass @subscribe.subcommand( name="spotlight", description="Subscribe to every spotlight game, sending them in this channel", ) async def spotlightsubscribe(self, interaction: nextcord.Interaction): await interaction.response.defer() game = requests.get("https://mmolb.com/api/spotlight").json() gameid = game["game_id"] data = requests.get(f"https://mmolb.com/api/game/{gameid}").json() await interaction.edit_original_message(content=f"{data["AwayTeamName"]} {data["AwayTeamEmoji"]} **{data["EventLog"][-1]["away_score"]}** vs {data["HomeTeamName"]} {data["HomeTeamEmoji"]} **{data["EventLog"][-1]["home_score"]}**") message = await interaction.original_message() if data["State"] != "Complete": await self.bot.db.execute(f""" INSERT INTO liveupdate VALUES ({interaction.guild_id}, {interaction.user.id}, {interaction.channel_id}, {message.id}, "{gameid}", {len(data["EventLog"])}) """) await self.bot.db.execute(f""" INSERT INTO spotlightsubscriptions VALUES ({interaction.guild_id}, {interaction.channel_id}) """) await self.bot.db.commit() await interaction.followup.send(content="From now on every spotlight game will be sent in this channel", ephemeral=True) @subscribe.subcommand( name="team", description="Subscribe to every game for the specified team, sending them in this channel", ) async def teamsubscribe(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] try: game = requests.get(f"https://mmolb.com/api/game-by-team/{teamid}").json() gameid = game["game_id"] data = requests.get(f"https://mmolb.com/api/game/{gameid}").json() await interaction.edit_original_message(content=f"{data["AwayTeamName"]} {data["AwayTeamEmoji"]} **{data["EventLog"][-1]["away_score"]}** vs {data["HomeTeamName"]} {data["HomeTeamEmoji"]} **{data["EventLog"][-1]["home_score"]}**") message = await interaction.original_message() if data["State"] != "Complete": await self.bot.db.execute(f""" INSERT INTO liveupdate VALUES ({interaction.guild_id}, {interaction.user.id}, {interaction.channel_id}, {message.id}, "{gameid}", {len(data["EventLog"])}) """) except Exception as e: await interaction.edit_original_message(content="This channel is now subscribed to updates") warning = self.bot.get_channel(1365478368555827270) await warning.send(e) print(e) await self.bot.db.execute(f""" INSERT INTO teamsubscriptions VALUES ({interaction.guild_id}, {interaction.channel_id}, "{teamid}") """) await self.bot.db.commit() await interaction.followup.send(content="From now on every game for the specified team will be sent in this channel", ephemeral=True) @teamsubscribe.on_autocomplete("team") async def teamsubscribeac(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) @nextcord.slash_command( name="liveupdates", description="Get live updates on a game", integration_types=[ IntegrationType.guild_install, ], contexts=[ nextcord.InteractionContextType.guild, nextcord.InteractionContextType.private_channel, ], force_global=True, ) async def liveupdatecreate(self, interaction: nextcord.Interaction, gameid: str): data = requests.get(f"https://mmolb.com/api/game/{gameid}").json() await interaction.response.send_message(f"{data["AwayTeamName"]} {data["AwayTeamEmoji"]} **{data["EventLog"][-1]["away_score"]}** vs {data["HomeTeamName"]} {data["HomeTeamEmoji"]} **{data["EventLog"][-1]["home_score"]}**") message = await interaction.original_message() if data["State"] == "Complete": return await self.bot.db.execute(f""" INSERT INTO liveupdate VALUES ({interaction.guild_id}, {interaction.user.id}, {interaction.channel_id}, {message.id}, "{gameid}", {len(data["EventLog"])}) """) await self.bot.db.commit() @nextcord.slash_command(name="unsubscribe", description="Unsubscribe to...", integration_types=[ IntegrationType.guild_install, ], contexts=[ nextcord.InteractionContextType.guild, nextcord.InteractionContextType.private_channel, ], force_global=True, default_member_permissions=nextcord.Permissions(manage_channels=True), ) async def unsubscribe(self, interaction: nextcord.Interaction): #This is never called pass @unsubscribe.subcommand( name="spotlight", description="Unsubscribe to spotlight game updates in this channel", ) async def unsubscribespotlightgame(self, interaction: nextcord.Interaction): await self.bot.db.execute(f""" DELETE from spotlightsubscriptions WHERE channelid = {interaction.channel_id} """) await self.bot.db.commit() await interaction.response.send_message("If existent, it has been removed") @unsubscribe.subcommand( name="team", description="Unsubscribe to team game updates in this channel", ) async def unsubscribeteamgame(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 self.bot.db.execute(f""" DELETE from teamsubscriptions WHERE channelid = ? AND teamid = ? """,(interaction.channel_id,teamid)) await self.bot.db.commit() await interaction.edit_original_message(content="If existent, it has been removed") @unsubscribeteamgame.on_autocomplete("team") async def unsubscribeteamgameac(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) @nextcord.slash_command( name="liveupdatesdelete", description="Delete a subscribed update", integration_types=[ IntegrationType.guild_install, ], contexts=[ nextcord.InteractionContextType.guild, nextcord.InteractionContextType.private_channel, ], force_global=True, ) async def liveupdatedelete(self, interaction: nextcord.Interaction, messageid: str): await interaction.response.defer(ephemeral=True) await self.bot.db.execute(f""" DELETE from liveupdate WHERE messageid = ? """, (int(messageid),)) await self.bot.db.commit() await interaction.edit_original_message(content="stopped updates for message") #TODO This will be a button @tasks.loop(seconds=20.0) async def updatelivegames(self): try: await self.bot.wait_until_ready() print("updating live games") res = await self.bot.db.execute("SELECT serverid,userid,channelid,messageid,gameid,offset FROM liveupdate") res = await res.fetchall() print(res) lastserverid = 0 for [serverid,userid,channelid,messageid,gameid,offset] in res: lastserverid = serverid try: channel = self.bot.get_channel(channelid) message = await channel.fetch_message(messageid) data = requests.get(f"https://mmolb.com/api/game/{gameid}/live?after={offset}").json() if len(data["entries"]) > 0: splitstr = message.content.split("\n") if len(splitstr) > 0: splitstr.pop(0) try: while len(splitstr)>(5-len(data["entries"])): splitstr.pop(0) except IndexError: print("Warning: index error, ignoring") #Not sure why this happens so far but ignorning the error doesn't break anything print(splitstr) basedata = requests.get(f"https://mmolb.com/api/game/{gameid}").json() finalstr = f"{basedata["AwayTeamName"]} {basedata["AwayTeamEmoji"]} **{data["entries"][-1]["away_score"]}** vs {basedata["HomeTeamName"]} {basedata["HomeTeamEmoji"]} **{data["entries"][-1]["home_score"]}**" offsetadd = 0 for i in splitstr: finalstr += f"\n{i}" for i in data["entries"]: finalstr += f"\n{i['message'].replace("", "**").replace("", "**")}" offsetadd += 1 await self.bot.db.execute(f""" UPDATE liveupdate set offset = {offset+offsetadd} WHERE messageid = '{messageid}' """) #Could do this for every meessage subscribed to the game but since the messages go one by one... maybe I should change that await self.bot.db.commit() if i["event"] == "Recordkeeping": await self.bot.db.execute(f""" DELETE from liveupdate WHERE messageid = {messageid} """) await self.bot.db.commit() await message.edit(finalstr) except Exception as e: await self.bot.db.execute(f""" DELETE from liveupdate WHERE messageid = {messageid} """) await self.bot.db.commit() await message.edit(f"An error occoured in this live update\n{e}") warning = self.bot.get_channel(1365478368555827270) await warning.send(e) except nextcord.Forbidden: warning = self.bot.get_channel(1365478368555827270) 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") except Exception as e: warning = self.bot.get_channel(1365478368555827270) await warning.send(e) print(e) @tasks.loop(seconds=120.0) async def checkspotlightsubscriptions(self): try: await self.bot.wait_until_ready() print("refreshing spotlight subscriptions") game = requests.get("https://mmolb.com/api/spotlight").json() gameid = game["game_id"] res = await self.bot.db.execute("SELECT serverid,channelid FROM spotlightsubscriptions") res = await res.fetchall() print(res) for [serverid,channelid] in res: check = await self.bot.db.execute("SELECT serverid,userid,channelid,messageid,gameid,offset FROM liveupdate WHERE channelid = ? AND gameid = ?", (channelid,gameid)) test = await check.fetchone() print(test) if test is None: print("True") data = requests.get(f"https://mmolb.com/api/game/{gameid}").json() channel = self.bot.get_channel(channelid) if data["State"] == "Complete": continue check = await self.bot.db.execute("SELECT serverid,userid,channelid,messageid,gameid,offset FROM liveupdate WHERE channelid = ? AND gameid = ?", (channelid,gameid)) test = await check.fetchone() if test is None: #no idea why it has to have two checks message = await channel.send(content=f"{data["AwayTeamName"]} {data["AwayTeamEmoji"]} **{data["EventLog"][-1]["away_score"]}** vs {data["HomeTeamName"]} {data["HomeTeamEmoji"]} **{data["EventLog"][-1]["home_score"]}**") await self.bot.db.execute(f""" INSERT INTO liveupdate VALUES ({channel.guild.id}, {self.bot.application_id}, {channelid}, {message.id}, "{gameid}", {len(data["EventLog"])}) """) await self.bot.db.commit() else: print("false") except Exception as e: #I know this is bad practice but these loops must be running print(e) return @tasks.loop(seconds=120.0) async def checkteamsubscriptions(self): try: print("refreshing team subscriptions") await self.bot.wait_until_ready() res = await self.bot.db.execute("SELECT serverid,channelid,teamid FROM teamsubscriptions") res = await res.fetchall() print(res) for [serverid,channelid,teamid] in res: game = requests.get(f"https://mmolb.com/api/game-by-team/{teamid}").json() gameid = game["game_id"] check = await self.bot.db.execute("SELECT serverid,userid,channelid,messageid,gameid,offset FROM liveupdate WHERE channelid = ? AND gameid = ?", (channelid,gameid)) test = await check.fetchone() print(test) if test is None: print("True") data = requests.get(f"https://mmolb.com/api/game/{gameid}").json() channel = self.bot.get_channel(channelid) if data["State"] == "Complete": continue check = await self.bot.db.execute("SELECT serverid,userid,channelid,messageid,gameid,offset FROM liveupdate WHERE channelid = ? AND gameid = ?", (channelid,gameid)) test = await check.fetchone() if test is None: #no idea why it has to have two checks message = await channel.send(content=f"{data["AwayTeamName"]} {data["AwayTeamEmoji"]} **{data["EventLog"][-1]["away_score"]}** vs {data["HomeTeamName"]} {data["HomeTeamEmoji"]} **{data["EventLog"][-1]["home_score"]}**") await self.bot.db.execute(f""" INSERT INTO liveupdate VALUES ({channel.guild.id}, {self.bot.application_id}, {channelid}, {message.id}, "{gameid}", {len(data["EventLog"])}) """) await self.bot.db.commit() else: print("false") except Exception as e: #I know this is bad practice but these loops must be running print(e) return def setup(bot: commands.Bot): bot.add_cog(liveupdate(bot))