diff --git a/cogs/gelbooru_watcher_base_cog.py b/cogs/gelbooru_watcher_base_cog.py index 1e8e6f1..2df4e45 100644 --- a/cogs/gelbooru_watcher_base_cog.py +++ b/cogs/gelbooru_watcher_base_cog.py @@ -405,28 +405,43 @@ class GelbooruWatcherBaseCog(commands.Cog, abc.ABC, metaclass=GelbooruWatcherMet post_url = self.post_url_template.format(random_result["id"]) return (f"<{post_url}>\n{random_result['file_url']}", all_results) - class GelbooruButtons(View): + class GelbooruButtons(ui.LayoutView): def __init__(self, cog: 'GelbooruWatcherBaseCog', tags: str, all_results: list, hidden: bool = False): super().__init__(timeout=300) self.cog = cog self.tags = tags self.all_results = all_results self.hidden = hidden - self.current_index = 0 # For browse view state if we merge browse buttons here + self.current_index = 0 + + self.container = ui.Container() + self.add_item(self.container) + if self.all_results: + self._update_container(random.choice(self.all_results)) + + def _update_container(self, result: dict): + self.container.clear_items() + gallery = ui.MediaGallery() + gallery.add_item(media=result["file_url"]) + self.container.add_item(gallery) + self.container.add_item( + ui.TextDisplay(f"{self.cog.cog_name} result for tags `{self.tags}`:") + ) + post_url = self.cog.post_url_template.format(result["id"]) + self.container.add_item(ui.TextDisplay(post_url)) @discord.ui.button(label="New Random", style=discord.ButtonStyle.primary) async def new_random(self, interaction: discord.Interaction, button: Button): random_result = random.choice(self.all_results) - post_url = self.cog.post_url_template.format(random_result["id"]) - content = f"<{post_url}>\n{random_result['file_url']}" - await interaction.response.edit_message(content=content, view=self) + self._update_container(random_result) + await interaction.response.edit_message(content="", view=self) @discord.ui.button(label="Random In New Message", style=discord.ButtonStyle.success) async def new_message(self, interaction: discord.Interaction, button: Button): random_result = random.choice(self.all_results) - post_url = self.cog.post_url_template.format(random_result["id"]) - content = f"<{post_url}>\n{random_result['file_url']}" - await interaction.response.send_message(content, view=self, ephemeral=self.hidden) + new_view = self.cog.GelbooruButtons(self.cog, self.tags, self.all_results, self.hidden) + new_view._update_container(random_result) + await interaction.response.send_message(content="", view=new_view, ephemeral=self.hidden) @discord.ui.button(label="Browse Results", style=discord.ButtonStyle.secondary) async def browse_results(self, interaction: discord.Interaction, button: Button): @@ -434,14 +449,8 @@ class GelbooruWatcherBaseCog(commands.Cog, abc.ABC, metaclass=GelbooruWatcherMet await interaction.response.send_message("No results to browse.", ephemeral=True) return self.current_index = 0 - result = self.all_results[self.current_index] - post_url = self.cog.post_url_template.format(result["id"]) - content = ( - f"Result 1/{len(self.all_results)}:\n" - f"{result['file_url']}\n{post_url}" - ) view = self.cog.BrowseView(self.cog, self.tags, self.all_results, self.hidden, self.current_index) - await interaction.response.edit_message(content=content, view=view) + await interaction.response.edit_message(content="", view=view) @discord.ui.button(label="Pin", style=discord.ButtonStyle.danger) async def pin_message(self, interaction: discord.Interaction, button: Button): @@ -452,7 +461,7 @@ class GelbooruWatcherBaseCog(commands.Cog, abc.ABC, metaclass=GelbooruWatcherMet except discord.Forbidden: await interaction.response.send_message("I don't have permission to pin messages.", ephemeral=True) except discord.HTTPException as e: await interaction.response.send_message(f"Failed to pin: {e}", ephemeral=True) - class BrowseView(View): + class BrowseView(ui.LayoutView): def __init__(self, cog: 'GelbooruWatcherBaseCog', tags: str, all_results: list, hidden: bool = False, current_index: int = 0): super().__init__(timeout=300) self.cog = cog @@ -461,14 +470,25 @@ class GelbooruWatcherBaseCog(commands.Cog, abc.ABC, metaclass=GelbooruWatcherMet self.hidden = hidden self.current_index = current_index - async def _update_message(self, interaction: discord.Interaction): + self.container = ui.Container() + self.add_item(self.container) + if self.all_results: + self._refresh_container() + + def _refresh_container(self): + self.container.clear_items() result = self.all_results[self.current_index] + gallery = ui.MediaGallery() + gallery.add_item(media=result["file_url"]) + self.container.add_item(gallery) + idx_label = f"Result {self.current_index + 1}/{len(self.all_results)} for tags `{self.tags}`:" + self.container.add_item(ui.TextDisplay(idx_label)) post_url = self.cog.post_url_template.format(result["id"]) - content = ( - f"Result {self.current_index + 1}/{len(self.all_results)}:\n" - f"{result['file_url']}\n{post_url}" - ) - await interaction.response.edit_message(content=content, view=self) + self.container.add_item(ui.TextDisplay(post_url)) + + async def _update_message(self, interaction: discord.Interaction): + self._refresh_container() + await interaction.response.edit_message(content="", view=self) @discord.ui.button(label="First", style=discord.ButtonStyle.secondary, emoji="⏪") async def first(self, interaction: discord.Interaction, button: Button): @@ -497,15 +517,8 @@ class GelbooruWatcherBaseCog(commands.Cog, abc.ABC, metaclass=GelbooruWatcherMet await modal.wait() if modal.value is not None: self.current_index = modal.value - 1 - # Edit the original message from the modal's followup context - result = self.all_results[self.current_index] - post_url = self.cog.post_url_template.format(result["id"]) - content = ( - f"Result {modal.value}/{len(self.all_results)}:\n" - f"{result['file_url']}\n{post_url}" - ) await interaction.followup.edit_message( - interaction.message.id, content=content, view=self + interaction.message.id, content="", view=self ) @@ -516,12 +529,11 @@ class GelbooruWatcherBaseCog(commands.Cog, abc.ABC, metaclass=GelbooruWatcherMet await interaction.response.edit_message(content="No results available.", view=None) return random_result = random.choice(self.all_results) - post_url = self.cog.post_url_template.format(random_result["id"]) - content = f"<{post_url}>\n{random_result['file_url']}" view = self.cog.GelbooruButtons( self.cog, self.tags, self.all_results, self.hidden ) - await interaction.response.edit_message(content=content, view=view) + view._update_container(random_result) + await interaction.response.edit_message(content="", view=view) class GoToModal(discord.ui.Modal): def __init__(self, max_pages: int): @@ -566,8 +578,8 @@ class GelbooruWatcherBaseCog(commands.Cog, abc.ABC, metaclass=GelbooruWatcherMet response = await self._fetch_posts_logic(ctx, tags) if isinstance(response, tuple): - content, all_results = response - view = self.GelbooruButtons(self, tags, all_results, hidden=False) # Prefix commands are not hidden + _, all_results = response + view = self.GelbooruButtons(self, tags, all_results, hidden=False) # _fetch_posts_logic sends initial reply, so we edit it original_message = ctx.message # This might not be the bot's reply message # We need a reference to the "Fetching data..." message. @@ -590,10 +602,10 @@ class GelbooruWatcherBaseCog(commands.Cog, abc.ABC, metaclass=GelbooruWatcherMet try: reply_msg = await ctx.channel.fetch_message(ctx.message.reference.message_id) if reply_msg.author == self.bot.user: - await reply_msg.edit(content=content, view=view) + await reply_msg.edit(content="", view=view) return except (discord.NotFound, discord.Forbidden): pass # Fallback to new message - await ctx.send(content, view=view) # Fallback + await ctx.send("", view=view) # Fallback elif isinstance(response, str): # Error # Similar issue with editing the reply. await ctx.send(response) @@ -603,12 +615,12 @@ class GelbooruWatcherBaseCog(commands.Cog, abc.ABC, metaclass=GelbooruWatcherMet response = await self._fetch_posts_logic(interaction, tags, hidden=hidden) if isinstance(response, tuple): - content, all_results = response + _, all_results = response view = self.GelbooruButtons(self, tags, all_results, hidden) if interaction.response.is_done(): - await interaction.followup.send(content, view=view, ephemeral=hidden) - else: # Should have been deferred by _fetch_posts_logic - await interaction.response.send_message(content, view=view, ephemeral=hidden) + await interaction.followup.send(content="", view=view, ephemeral=hidden) + else: + await interaction.response.send_message(content="", view=view, ephemeral=hidden) elif isinstance(response, str): # Error ephemeral_error = hidden if self.is_nsfw_site and response.startswith(f'This command for {self.cog_name} can only be used'): @@ -629,19 +641,17 @@ class GelbooruWatcherBaseCog(commands.Cog, abc.ABC, metaclass=GelbooruWatcherMet _, all_results = response if not all_results: content = f"No results found from {self.cog_name} for the given tags." - if not interaction.response.is_done(): await interaction.response.send_message(content, ephemeral=hidden) - else: await interaction.followup.send(content, ephemeral=hidden) + if not interaction.response.is_done(): + await interaction.response.send_message(content, ephemeral=hidden) + else: + await interaction.followup.send(content, ephemeral=hidden) return - result = all_results[0] - post_url = self.post_url_template.format(result["id"]) - content = ( - f"Result 1/{len(all_results)}:\n" - f"{result['file_url']}\n{post_url}" - ) view = self.BrowseView(self, tags, all_results, hidden, current_index=0) - if interaction.response.is_done(): await interaction.followup.send(content, view=view, ephemeral=hidden) - else: await interaction.response.send_message(content, view=view, ephemeral=hidden) + if interaction.response.is_done(): + await interaction.followup.send(content="", view=view, ephemeral=hidden) + else: + await interaction.response.send_message(content="", view=view, ephemeral=hidden) elif isinstance(response, str): # Error ephemeral_error = hidden if self.is_nsfw_site and response.startswith(f'This command for {self.cog_name} can only be used'):