146 lines
8.5 KiB
Python
146 lines
8.5 KiB
Python
import discord
|
|
from discord.ext import commands
|
|
from discord import app_commands
|
|
import httpx
|
|
import io
|
|
|
|
# --- Helper: Owner Check ---
|
|
async def is_owner_check(interaction: discord.Interaction) -> bool:
|
|
"""Checks if the interacting user is the bot owner."""
|
|
return interaction.user.id == interaction.client.owner_id
|
|
|
|
class BotAppearanceCog(commands.Cog):
|
|
def __init__(self, bot):
|
|
self.bot = bot
|
|
|
|
@commands.command(name='change_nickname', help="Changes the bot's nickname in the current server. Admin only.")
|
|
@commands.has_permissions(administrator=True)
|
|
async def change_nickname(self, ctx: commands.Context, *, new_nickname: str):
|
|
"""Changes the bot's nickname in the current server."""
|
|
try:
|
|
await ctx.guild.me.edit(nick=new_nickname)
|
|
await ctx.send(f"My nickname has been changed to '{new_nickname}' in this server.")
|
|
except discord.Forbidden:
|
|
await ctx.send("I don't have permission to change my nickname here.")
|
|
except Exception as e:
|
|
await ctx.send(f"An error occurred: {e}")
|
|
|
|
@app_commands.command(name="change_nickname", description="Changes the bot's nickname in the current server.")
|
|
@app_commands.describe(new_nickname="The new nickname for the bot.")
|
|
@app_commands.checks.has_permissions(administrator=True)
|
|
async def slash_change_nickname(self, interaction: discord.Interaction, new_nickname: str):
|
|
"""Changes the bot's nickname in the current server."""
|
|
try:
|
|
await interaction.guild.me.edit(nick=new_nickname)
|
|
await interaction.response.send_message(f"My nickname has been changed to '{new_nickname}' in this server.", ephemeral=True)
|
|
except discord.Forbidden:
|
|
await interaction.response.send_message("I don't have permission to change my nickname here.", ephemeral=True)
|
|
except Exception as e:
|
|
await interaction.response.send_message(f"An error occurred: {e}", ephemeral=True)
|
|
|
|
@commands.command(name='change_avatar', help="Changes the bot's global avatar. Owner only. Provide a direct image URL.")
|
|
@commands.is_owner()
|
|
async def change_avatar(self, ctx: commands.Context, image_url: str):
|
|
"""Changes the bot's global avatar. Requires a direct image URL."""
|
|
if not (image_url.startswith('http://') or image_url.startswith('https://')):
|
|
await ctx.send("Invalid URL. Please provide a direct link to an image (http:// or https://).")
|
|
return
|
|
|
|
try:
|
|
async with httpx.AsyncClient() as client:
|
|
response = await client.get(image_url)
|
|
response.raise_for_status() # Raise an exception for bad status codes
|
|
image_bytes = await response.aread()
|
|
|
|
await self.bot.user.edit(avatar=image_bytes)
|
|
await ctx.send("My avatar has been updated!")
|
|
except httpx.RequestError as e:
|
|
await ctx.send(f"Could not fetch the image from the URL: {e}")
|
|
except discord.Forbidden:
|
|
await ctx.send("I don't have permission to change my avatar. This might be due to rate limits or other restrictions.")
|
|
except discord.HTTPException as e:
|
|
await ctx.send(f"Failed to change avatar. Discord API error: {e}")
|
|
except Exception as e:
|
|
await ctx.send(f"An unexpected error occurred: {e}")
|
|
|
|
@app_commands.command(name="change_avatar", description="Changes the bot's global avatar using a URL or an uploaded image.")
|
|
@app_commands.describe(
|
|
image_url="A direct URL to the image for the new avatar (optional if attachment is provided).",
|
|
attachment="An image file to use as the new avatar (optional if URL is provided)."
|
|
)
|
|
@app_commands.check(is_owner_check)
|
|
async def slash_change_avatar(self, interaction: discord.Interaction, image_url: str = None, attachment: discord.Attachment = None):
|
|
"""Changes the bot's global avatar. Accepts a direct image URL or an attachment."""
|
|
await interaction.response.defer(ephemeral=True)
|
|
image_bytes = None
|
|
|
|
if attachment:
|
|
if not attachment.content_type or not attachment.content_type.startswith('image/'):
|
|
await interaction.response.send_message("Invalid file type. Please upload an image.", ephemeral=True)
|
|
return
|
|
try:
|
|
image_bytes = await attachment.read()
|
|
except Exception as e:
|
|
await interaction.response.send_message(f"Could not read the attached image: {e}", ephemeral=True)
|
|
return
|
|
elif image_url:
|
|
if not (image_url.startswith('http://') or image_url.startswith('https://')):
|
|
await interaction.response.send_message("Invalid URL. Please provide a direct link to an image (http:// or https://).", ephemeral=True)
|
|
return
|
|
try:
|
|
async with httpx.AsyncClient() as client:
|
|
response = await client.get(image_url)
|
|
response.raise_for_status() # Raise an exception for bad status codes
|
|
image_bytes = await response.aread()
|
|
except httpx.RequestError as e:
|
|
await interaction.response.send_message(f"Could not fetch the image from the URL: {e}", ephemeral=True)
|
|
return
|
|
else:
|
|
await interaction.response.send_message("Please provide either an image URL or an attachment.", ephemeral=True)
|
|
return
|
|
|
|
if image_bytes:
|
|
try:
|
|
await self.bot.user.edit(avatar=image_bytes)
|
|
await interaction.response.send_message("My avatar has been updated!", ephemeral=True)
|
|
except discord.Forbidden:
|
|
await interaction.response.send_message("I don't have permission to change my avatar. This might be due to rate limits or other restrictions.", ephemeral=True)
|
|
except discord.HTTPException as e:
|
|
await interaction.response.send_message(f"Failed to change avatar. Discord API error: {e}", ephemeral=True)
|
|
except Exception as e:
|
|
await interaction.response.send_message(f"An unexpected error occurred: {e}", ephemeral=True)
|
|
# This else should ideally not be reached if logic above is correct, but as a fallback:
|
|
else:
|
|
await interaction.response.send_message("Failed to process the image.", ephemeral=True)
|
|
|
|
@change_nickname.error
|
|
@change_avatar.error
|
|
async def on_command_error(self, ctx: commands.Context, error):
|
|
if isinstance(error, commands.MissingPermissions):
|
|
await ctx.send("You don't have the required permissions (Administrator) to use this command.")
|
|
elif isinstance(error, commands.NotOwner):
|
|
await ctx.send("This command can only be used by the bot owner. If you wish to customize your bot's appearance, please set up a custom bot on the [web dashboard.](https://slipstreamm.dev/dashboard/)")
|
|
elif isinstance(error, commands.MissingRequiredArgument):
|
|
await ctx.send(f"Missing required argument: `{error.param.name}`. Please check the command's help.")
|
|
else:
|
|
print(f"Error in BotAppearanceCog: {error}") # Log other errors to console
|
|
await ctx.send("An internal error occurred. Please check the logs.")
|
|
|
|
# It's generally better to handle app command errors with a cog-level error handler
|
|
# or within each command if specific handling is needed.
|
|
# For simplicity, adding a basic error handler for app_commands.
|
|
async def cog_app_command_error(self, interaction: discord.Interaction, error: app_commands.AppCommandError):
|
|
if isinstance(error, app_commands.MissingPermissions):
|
|
await interaction.response.send_message("You don't have the required permissions (Administrator) to use this command.", ephemeral=True)
|
|
elif isinstance(error, app_commands.CheckFailure):
|
|
await interaction.response.send_message("This command can only be used by the bot owner. If you wish to customize your bot's appearance, please set up a custom bot on the web dashboard.", ephemeral=True)
|
|
else:
|
|
print(f"Error in BotAppearanceCog (app_command): {error}") # Log other errors to console
|
|
if not interaction.response.is_done():
|
|
await interaction.response.send_message("An internal error occurred. Please check the logs.", ephemeral=True)
|
|
else:
|
|
await interaction.followup.send("An internal error occurred. Please check the logs.", ephemeral=True)
|
|
|
|
async def setup(bot):
|
|
await bot.add_cog(BotAppearanceCog(bot))
|