diff --git a/modules/data/db.py b/modules/data/db.py index 7210e9c..c313e16 100644 --- a/modules/data/db.py +++ b/modules/data/db.py @@ -22,6 +22,14 @@ def initialize_db(): ) ''') + # Followed channels table + cursor.execute(''' + CREATE TABLE IF NOT EXISTS followed_channels ( + twitch_name TEXT PRIMARY KEY, + discord_channel_id INTEGER + ) + ''') + conn.commit() conn.close() diff --git a/modules/social/twitch_module.py b/modules/social/twitch_module.py index f9f041f..64bf3e5 100644 --- a/modules/social/twitch_module.py +++ b/modules/social/twitch_module.py @@ -4,6 +4,8 @@ from twitchAPI.twitch import Twitch from twitchAPI.helper import first import logging import config +import asyncio +from modules.data.db import get_connection logger = logging.getLogger(__name__) @@ -14,12 +16,117 @@ class TwitchModule: self.twitch = Twitch(config.TWITCH_CLIENT_ID, config.TWITCH_CLIENT_SECRET) self.bot.loop.create_task(self.authenticate_twitch()) + self.bot.loop.create_task(self.check_live_streams()) self.add_commands() async def authenticate_twitch(self): - await self.twitch.authenticate_app([]) + await self.twitch.authenticate_app([]) # Authenticate without scopes + + async def check_live_streams(self): + while True: + conn = get_connection() + c = conn.cursor() + c.execute(''' + CREATE TABLE IF NOT EXISTS live_status ( + twitch_name TEXT PRIMARY KEY, + is_live BOOLEAN + ) + ''') + conn.commit() + + c.execute('SELECT twitch_name, discord_channel_id FROM followed_channels') + followed_channels = c.fetchall() + + for twitch_name, discord_channel_id in followed_channels: + try: + user_info = await first(self.twitch.get_users(logins=[twitch_name])) + if not user_info: + continue + + user_id = user_info.id + streams = await first(self.twitch.get_streams(user_id=[user_id])) + is_live = streams is not None + + c.execute('SELECT is_live FROM live_status WHERE twitch_name = ?', (twitch_name,)) + row = c.fetchone() + was_live = row[0] if row else False + + if is_live and not was_live: + channel = self.bot.get_channel(discord_channel_id) + if channel: + embed = discord.Embed( + title=f"{twitch_name} is Live!", + description=( + f"**Title:** {streams.title}\n" + f"**Game:** {streams.game_name}\n" + f"**Viewers:** {streams.viewer_count}" + ), + color=discord.Color.green() + ) + embed.set_thumbnail( + url=streams.thumbnail_url.replace('{width}', '320').replace('{height}', '180') + ) + await channel.send(embed=embed) + + c.execute('INSERT OR REPLACE INTO live_status (twitch_name, is_live) VALUES (?, ?)', (twitch_name, is_live)) + conn.commit() + + except Exception as e: + logger.error(f"Error checking live status for {twitch_name}: {e}", exc_info=True) + + conn.close() + await asyncio.sleep(120) # Check every 2 minutes for testing purposes def add_commands(self): + @app_commands.command( + name="follow_twitch", + description="Follow a Twitch channel to get live alerts" + ) + async def follow_twitch(interaction: discord.Interaction, twitch_name: str, channel: discord.TextChannel = None): + channel = channel or interaction.channel + conn = get_connection() + c = conn.cursor() + c.execute( + 'INSERT OR REPLACE INTO followed_channels (twitch_name, discord_channel_id) VALUES (?, ?)', + (twitch_name, channel.id) + ) + conn.commit() + conn.close() + await interaction.response.send_message( + embed=discord.Embed( + title="Followed Twitch Channel", + description=f"Now following {twitch_name}. Alerts will be sent to {channel.mention}.", + color=discord.Color.green() + ) + ) + logger.info(f"Now following {twitch_name} for alerts in {channel.name}") + + @app_commands.command( + name="unfollow_twitch", + description="Unfollow a Twitch channel" + ) + async def unfollow_twitch(interaction: discord.Interaction, twitch_name: str): + conn = get_connection() + c = conn.cursor() + c.execute( + 'DELETE FROM followed_channels WHERE twitch_name = ?', + (twitch_name,) + ) + c.execute( + 'DELETE FROM live_status WHERE twitch_name = ?', + (twitch_name,) + ) + conn.commit() + conn.close() + await interaction.response.send_message( + embed=discord.Embed( + title="Unfollowed Twitch Channel", + description=f"No longer following {twitch_name}.", + color=discord.Color.red() + ) + ) + logger.info(f"No longer following {twitch_name}") + @app_commands.command( name="twitch_live", description="Check if a Twitch streamer is live" @@ -71,6 +178,8 @@ class TwitchModule: logger.error(f"Error in twitch_live command: {e}", exc_info=True) await interaction.followup.send(f"An error occurred: {e}") + self.bot.tree.add_command(follow_twitch) + self.bot.tree.add_command(unfollow_twitch) self.bot.tree.add_command(twitch_live)