import discord from discord.ext import commands import aiohttp from typing import Union class TetoImageView(discord.ui.View): def __init__(self, cog): super().__init__(timeout=180.0) self.cog = cog @discord.ui.button(label="Show Another Image", style=discord.ButtonStyle.primary) async def show_another_image( self, interaction: discord.Interaction, _: discord.ui.Button ): await self.cog.get_teto_image(interaction) class TetoImageCog(commands.Cog): def __init__(self, bot): self.bot = bot self.teto_url = "https://slipstreamm.dev/teto" self.footer_url = "https://slipstreamm.dev/teto-web" async def fetch_teto_image(self): """Fetches a random Teto image and returns the URL.""" async with aiohttp.ClientSession() as session: headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36" } async with session.get( self.teto_url, headers=headers, allow_redirects=False ) as response: if response.status == 302: image_path = response.headers.get("Location") if image_path: return f"https://slipstreamm.dev{image_path}" return None @commands.hybrid_command( name="tetoimage", description="Get a random image of Kasane Teto." ) async def get_teto_image( self, ctx_or_interaction: Union[commands.Context, discord.Interaction] ): """Gets a random image of Kasane Teto.""" # Determine if this is a Context or Interaction is_interaction = isinstance(ctx_or_interaction, discord.Interaction) # Handle typing indicator differently based on object type if is_interaction: await ctx_or_interaction.response.defer(thinking=True) else: async with ctx_or_interaction.typing(): pass try: image_url = await self.fetch_teto_image() if image_url: embed = discord.Embed( title="Random Teto Image", description=f"Website: {self.footer_url}", color=discord.Color.red(), ) if image_url.startswith("http") or image_url.startswith("https"): embed.set_image(url=image_url) view = TetoImageView(self) # Send response differently based on object type if is_interaction: if ctx_or_interaction.response.is_done(): await ctx_or_interaction.followup.send( embed=embed, view=view ) else: await ctx_or_interaction.response.send_message( embed=embed, view=view ) else: await ctx_or_interaction.send(embed=embed, view=view) else: error_msg = "The retrieved URL was not valid." await self._send_error(ctx_or_interaction, error_msg) else: error_msg = "Could not get the image URL from the redirect." await self._send_error(ctx_or_interaction, error_msg) except aiohttp.ClientConnectorError as e: error_msg = f"Could not connect to the image service: {e}" await self._send_error(ctx_or_interaction, error_msg) except Exception as e: error_msg = f"An error occurred: {e}" await self._send_error(ctx_or_interaction, error_msg) async def _send_error(self, ctx_or_interaction, error_msg): """Helper method to send error messages based on context type.""" if isinstance(ctx_or_interaction, discord.Interaction): if ctx_or_interaction.response.is_done(): await ctx_or_interaction.followup.send(error_msg) else: await ctx_or_interaction.response.send_message(error_msg) else: await ctx_or_interaction.send(error_msg) async def setup(bot): await bot.add_cog(TetoImageCog(bot))