discordbot/cogs/safebooru_cog.py
2025-06-05 21:31:06 -06:00

207 lines
8.0 KiB
Python

import discord
from discord.ext import commands, tasks
from discord import app_commands
import typing # Need this for Optional
import logging
from .gelbooru_watcher_base_cog import GelbooruWatcherBaseCog
# Setup logger for this cog
log = logging.getLogger(__name__)
class SafebooruCog(GelbooruWatcherBaseCog): # Removed name="Safebooru"
# Define the command group specific to this cog
safebooruwatch = app_commands.Group(
name="safebooruwatch",
description="Manage Safebooru tag watchers for new posts.",
)
def __init__(self, bot: commands.Bot):
super().__init__(
bot=bot,
cog_name="Safebooru",
api_base_url="https://safebooru.org/index.php", # Corrected base URL
default_tags="hatsune_miku 1girl", # Example default
is_nsfw_site=False, # Safebooru is generally SFW
command_group_name="safebooruwatch",
main_command_name="safebooru",
post_url_template="https://safebooru.org/index.php?page=post&s=view&id={}",
)
# --- Prefix Command ---
@commands.command(name="safebooru")
async def safebooru_prefix(
self, ctx: commands.Context, *, tags: typing.Optional[str] = None
):
"""Search for images on Safebooru with the provided tags."""
actual_tags = tags or self.default_tags
loading_msg = await ctx.reply(
f"Fetching data from {self.cog_name}, please wait..."
)
response = await self._fetch_posts_logic(
"prefix_internal", actual_tags, hidden=False
)
if isinstance(response, tuple):
content, all_results = response
view = self.GelbooruButtons(self, actual_tags, all_results, hidden=False)
await loading_msg.edit(content=content, view=view)
elif isinstance(response, str): # Error
await loading_msg.edit(content=response, view=None)
# --- Slash Command ---
@app_commands.command(
name="safebooru",
description="Get random image from Safebooru with specified tags",
)
@app_commands.describe(
tags="The tags to search for (e.g., '1girl cat_ears')",
hidden="Set to True to make the response visible only to you (default: False)",
)
async def safebooru_slash(
self,
interaction: discord.Interaction,
tags: typing.Optional[str] = None,
hidden: bool = False,
):
"""Slash command version of safebooru."""
actual_tags = tags or self.default_tags
await self._slash_command_logic(interaction, actual_tags, hidden)
# --- New Browse Command ---
@app_commands.command(
name="safeboorubrowse",
description="Browse Safebooru results with navigation buttons",
)
@app_commands.describe(
tags="The tags to search for (e.g., '1girl dog_ears')",
hidden="Set to True to make the response visible only to you (default: False)",
)
async def safebooru_browse_slash(
self,
interaction: discord.Interaction,
tags: typing.Optional[str] = None,
hidden: bool = False,
):
"""Browse Safebooru results with navigation buttons."""
actual_tags = tags or self.default_tags
await self._browse_slash_command_logic(interaction, actual_tags, hidden)
# --- safebooruwatch slash command group ---
@safebooruwatch.command(
name="add",
description="Watch for new Safebooru posts with specific tags in a channel or thread.",
)
@app_commands.describe(
tags="The tags to search for (e.g., '1girl cat_ears').",
channel="The parent channel for the subscription. Must be a Forum Channel if using forum mode.",
thread_target="Optional: Name or ID of a thread within the channel (for TextChannels only).",
post_title="Optional: Title for a new forum post if 'channel' is a Forum Channel.",
)
@app_commands.checks.has_permissions(manage_guild=True)
async def safebooruwatch_add(
self,
interaction: discord.Interaction,
tags: str,
channel: typing.Union[discord.TextChannel, discord.ForumChannel],
thread_target: typing.Optional[str] = None,
post_title: typing.Optional[str] = None,
):
await interaction.response.defer(ephemeral=True)
await self._watch_add_logic(
interaction, tags, channel, thread_target, post_title
)
@safebooruwatch.command(
name="request",
description="Request a new Safebooru tag watch (requires moderator approval).",
)
@app_commands.describe(
tags="The tags you want to watch.",
forum_channel="The Forum Channel where a new post for this watch should be created.",
post_title="Optional: A title for the new forum post (defaults to tags).",
)
async def safebooruwatch_request(
self,
interaction: discord.Interaction,
tags: str,
forum_channel: discord.ForumChannel,
post_title: typing.Optional[str] = None,
):
await interaction.response.defer(ephemeral=True)
await self._watch_request_logic(interaction, tags, forum_channel, post_title)
@safebooruwatch.command(
name="pending_list", description="Lists all pending Safebooru watch requests."
)
@app_commands.checks.has_permissions(manage_guild=True)
async def safebooruwatch_pending_list(self, interaction: discord.Interaction):
await self._watch_pending_list_logic(interaction)
@safebooruwatch.command(
name="approve_request",
description="Approves a pending Safebooru watch request.",
)
@app_commands.describe(request_id="The ID of the request to approve.")
@app_commands.checks.has_permissions(manage_guild=True)
async def safebooruwatch_approve_request(
self, interaction: discord.Interaction, request_id: str
):
await interaction.response.defer(ephemeral=True)
await self._watch_approve_request_logic(interaction, request_id)
@safebooruwatch.command(
name="reject_request", description="Rejects a pending Safebooru watch request."
)
@app_commands.describe(
request_id="The ID of the request to reject.",
reason="Optional reason for rejection.",
)
@app_commands.checks.has_permissions(manage_guild=True)
async def safebooruwatch_reject_request(
self,
interaction: discord.Interaction,
request_id: str,
reason: typing.Optional[str] = None,
):
await interaction.response.defer(ephemeral=True)
await self._watch_reject_request_logic(interaction, request_id, reason)
@safebooruwatch.command(
name="list", description="List active Safebooru tag watches for this server."
)
@app_commands.checks.has_permissions(manage_guild=True)
async def safebooruwatch_list(self, interaction: discord.Interaction):
await self._watch_list_logic(interaction)
@safebooruwatch.command(
name="remove",
description="Stop watching for new Safebooru posts using a subscription ID.",
)
@app_commands.describe(
subscription_id="The ID of the subscription to remove (get from 'list' command)."
)
@app_commands.checks.has_permissions(manage_guild=True)
async def safebooruwatch_remove(
self, interaction: discord.Interaction, subscription_id: str
):
await self._watch_remove_logic(interaction, subscription_id)
@safebooruwatch.command(
name="send_test",
description="Send a test new Safebooru post message using a subscription ID.",
)
@app_commands.describe(subscription_id="The ID of the subscription to test.")
@app_commands.checks.has_permissions(manage_guild=True)
async def safebooruwatch_send_test(
self, interaction: discord.Interaction, subscription_id: str
):
await self._watch_test_message_logic(interaction, subscription_id)
async def setup(bot: commands.Bot):
await bot.add_cog(SafebooruCog(bot))
log.info("SafebooruCog (refactored) added to bot.")