feat: feed subscriptions

This commit is contained in:
insert 2025-07-16 01:04:13 -04:00
parent edaccdc684
commit 3d5f2e3de4
Signed by: insert
GPG key ID: A70775C389ACF105
2 changed files with 112 additions and 0 deletions

5
bot.py
View file

@ -21,6 +21,7 @@ class Bot(commands.Bot):
await cur.execute("DELETE from teamsubscriptions WHERE serverid = ?", (guild.id,)) await cur.execute("DELETE from teamsubscriptions WHERE serverid = ?", (guild.id,))
await cur.execute("DELETE from liveupdate WHERE serverid = ?", (guild.id,)) await cur.execute("DELETE from liveupdate WHERE serverid = ?", (guild.id,))
await cur.execute("DELETE from spotlightsubscriptions WHERE serverid = ?", (guild.id,)) await cur.execute("DELETE from spotlightsubscriptions WHERE serverid = ?", (guild.id,))
await cur.execute("DELETE from feedsubscriptions WHERE serverid = ?", (guild.id,))
await db.commit() await db.commit()
load_dotenv() load_dotenv()
@ -49,6 +50,10 @@ async def on_ready():
if await res.fetchone() is None: if await res.fetchone() is None:
await cur.execute("CREATE TABLE teamsubscriptions(serverid INTEGER, channelid INTEGER NOT NULL, teamid TEXT, classic INTEGER NOT NULL)") await cur.execute("CREATE TABLE teamsubscriptions(serverid INTEGER, channelid INTEGER NOT NULL, teamid TEXT, classic INTEGER NOT NULL)")
await db.commit() await db.commit()
res = await cur.execute("SELECT name FROM sqlite_master WHERE name='feedsubscriptions'")
if await res.fetchone() is None:
await cur.execute("CREATE TABLE feedsubscriptions(serverid INTEGER, channelid INTEGER NOT NULL, teamid TEXT, offset INTEGER)")
await db.commit()
#await cur.execute("ALTER TABLE liveupdate ADD classic INTEGER NOT NULL DEFAULT 0") #await cur.execute("ALTER TABLE liveupdate ADD classic INTEGER NOT NULL DEFAULT 0")
#await cur.execute("ALTER TABLE spotlightsubscriptions ADD classic INTEGER NOT NULL DEFAULT 0") #await cur.execute("ALTER TABLE spotlightsubscriptions ADD classic INTEGER NOT NULL DEFAULT 0")
#await cur.execute("ALTER TABLE teamsubscriptions ADD classic INTEGER NOT NULL DEFAULT 0") #await cur.execute("ALTER TABLE teamsubscriptions ADD classic INTEGER NOT NULL DEFAULT 0")

View file

@ -6,6 +6,7 @@ import requests
import asyncio import asyncio
import nextcord import nextcord
import aiohttp import aiohttp
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
@ -191,6 +192,8 @@ async def teamsubscriptionworker(self,serverid,channelid,teamid,classic):
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()
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))
@ -221,6 +224,36 @@ async def teamsubscriptionworker(self,serverid,channelid,teamid,classic):
print(e) print(e)
return return
async def feedsubscriptionworker(self,serverid,channelid,teamid,offset):
begin = timeit.default_timer()
lastserverid = serverid
try:
async with aiohttp.ClientSession() as session:
channel = self.bot.get_channel(channelid)
if channel is None:
return
data = await session.get(f"https://mmolb.com/api/team/{teamid}")
data = await data.json()
data = data['Feed']
if len(data) > offset:
finalstr = ""
for index in itertools.islice(data, offset, len(data)):
finalstr += f"\n{index['emoji']} Season {index['season']} Day {index['day']}: {index['text']}"
await channel.send(finalstr)
await self.bot.db.execute(f"""
UPDATE feedsubscriptions set offset = {len(data)} WHERE channelid = '{channelid}' AND teamid = '{teamid}'
""")
except Exception as 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.execute("DELETE from feedsubscriptions WHERE serverid = ?", (lastserverid,))
await self.bot.db.commit()
await warning.send(f"Deleted {lastserverid} from the database due to 403 error")
class liveupdate(commands.Cog): class liveupdate(commands.Cog):
@ -228,6 +261,7 @@ class liveupdate(commands.Cog):
def __init__(self, bot: commands.Bot): def __init__(self, bot: commands.Bot):
self.bot = bot self.bot = bot
self.updatelivegames.start() self.updatelivegames.start()
self.checkfeedsubscriptions.start()
self.checkspotlightsubscriptions.start() self.checkspotlightsubscriptions.start()
self.checkteamsubscriptions.start() self.checkteamsubscriptions.start()
@ -235,6 +269,7 @@ class liveupdate(commands.Cog):
self.updatelivegames.cancel() self.updatelivegames.cancel()
self.checkspotlightsubscriptions.cancel() self.checkspotlightsubscriptions.cancel()
self.checkteamsubscriptions.cancel() self.checkteamsubscriptions.cancel()
self.checkfeedsubscriptions.cancel()
@nextcord.slash_command( @nextcord.slash_command(
name="spotlightgame", name="spotlightgame",
@ -390,6 +425,36 @@ 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="feed",
description="Subscribe to a team's feed",
)
async def feedsubscribe(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]
async with aiohttp.ClientSession() as session:
data = await session.get(f"https://mmolb.com/api/team/{teamid}")
data = await data.json()
offset = len(data['Feed'])
await self.bot.db.execute(f"""
INSERT INTO feedsubscriptions VALUES
({interaction.guild_id}, {interaction.channel_id}, "{teamid}", {offset})
""")
await self.bot.db.commit()
await interaction.edit_original_message(content="This channel is now subscribed to feed updates")
@feedsubscribe.on_autocomplete("team")
async def feedsubscribeac(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( @nextcord.slash_command(
name="watch", name="watch",
description="Get live updates on a game", description="Get live updates on a game",
@ -474,6 +539,32 @@ class liveupdate(commands.Cog):
thanksdiscord = closestteam[:20] thanksdiscord = closestteam[:20]
await interaction.response.send_autocomplete(thanksdiscord) await interaction.response.send_autocomplete(thanksdiscord)
@unsubscribe.subcommand(
name="feed",
description="Unsubscribe to team feed updates in this channel",
)
async def unsubscribefeed(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 feedsubscriptions 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")
@unsubscribefeed.on_autocomplete("team")
async def unsubscribefeedac(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( @nextcord.slash_command(
name="liveupdatesdelete", name="liveupdatesdelete",
description="DEBUG: Delete a subscribed update", description="DEBUG: Delete a subscribed update",
@ -578,5 +669,21 @@ class liveupdate(commands.Cog):
print(e) print(e)
return return
@tasks.loop(seconds=120.0)
async def checkfeedsubscriptions(self):
try:
await self.bot.wait_until_ready()
res = await self.bot.db.execute("SELECT serverid,channelid,teamid,offset FROM feedsubscriptions")
res = await res.fetchall()
worklist = [feedsubscriptionworker(self,serverid,channelid,teamid,offset) for [serverid,channelid,teamid,offset] in res]
await asyncio.gather(*worklist,return_exceptions=True)
await self.bot.db.commit()
except Exception as e:
#I know this is bad practice but these loops must be running
warning = self.bot.get_channel(1365478368555827270)
await warning.send(e)
print(e)
return
def setup(bot: commands.Bot): def setup(bot: commands.Bot):
bot.add_cog(liveupdate(bot)) bot.add_cog(liveupdate(bot))