discordbot/cogs/emoji_cog.py
2025-05-16 20:42:51 -06:00

289 lines
12 KiB
Python

import discord
from discord.ext import commands
from discord import app_commands
import logging
import io
import aiohttp
from typing import Optional, Union
log = logging.getLogger(__name__)
class EmojiCog(commands.Cog, name="Emoji"):
"""Cog for emoji management commands"""
def __init__(self, bot: commands.Bot):
self.bot = bot
# Create the main command group for this cog
self.emoji_group = app_commands.Group(
name="emoji",
description="Manage server emojis"
)
# Register commands
self.register_commands()
# Add command group to the bot's tree
self.bot.tree.add_command(self.emoji_group)
log.info("EmojiCog initialized with emoji command group.")
def register_commands(self):
"""Register all commands for this cog"""
# Create emoji command
create_command = app_commands.Command(
name="create",
description="Create a new emoji from an uploaded image",
callback=self.emoji_create_callback,
parent=self.emoji_group
)
app_commands.describe(
name="The name for the new emoji",
image="The image to use for the emoji",
reason="Reason for creating this emoji"
)(create_command)
self.emoji_group.add_command(create_command)
# List emojis command
list_command = app_commands.Command(
name="list",
description="List all emojis in the server",
callback=self.emoji_list_callback,
parent=self.emoji_group
)
self.emoji_group.add_command(list_command)
# Delete emoji command
delete_command = app_commands.Command(
name="delete",
description="Delete an emoji from the server",
callback=self.emoji_delete_callback,
parent=self.emoji_group
)
app_commands.describe(
emoji="The emoji to delete",
reason="Reason for deleting this emoji"
)(delete_command)
self.emoji_group.add_command(delete_command)
# Emoji info command
info_command = app_commands.Command(
name="info",
description="Get information about an emoji",
callback=self.emoji_info_callback,
parent=self.emoji_group
)
app_commands.describe(
emoji="The emoji to get information about"
)(info_command)
self.emoji_group.add_command(info_command)
# --- Command Callbacks ---
@app_commands.checks.has_permissions(manage_emojis=True)
async def emoji_create_callback(self, interaction: discord.Interaction, name: str, image: discord.Attachment, reason: Optional[str] = None):
"""Create a new emoji from an uploaded image"""
await interaction.response.defer(ephemeral=False, thinking=True)
try:
# Check if the image is valid
if not image.content_type.startswith('image/'):
await interaction.followup.send("❌ The uploaded file is not an image.", ephemeral=True)
return
# Check file size (Discord limit is 256KB for emoji images)
if image.size > 256 * 1024:
await interaction.followup.send("❌ Image is too large. Emoji images must be under 256KB.", ephemeral=True)
return
# Read the image data
image_data = await image.read()
# Create the emoji
emoji = await interaction.guild.create_custom_emoji(
name=name,
image=image_data,
reason=f"{reason or 'No reason provided'} (Created by {interaction.user})"
)
# Create a success embed
embed = discord.Embed(
title="✅ Emoji Created",
description=f"Successfully created emoji {emoji}",
color=discord.Color.green()
)
embed.add_field(name="Name", value=emoji.name, inline=True)
embed.add_field(name="ID", value=emoji.id, inline=True)
embed.add_field(name="Created by", value=interaction.user.mention, inline=True)
if reason:
embed.add_field(name="Reason", value=reason, inline=False)
embed.set_thumbnail(url=emoji.url)
await interaction.followup.send(embed=embed)
log.info(f"Emoji '{emoji.name}' created by {interaction.user} in {interaction.guild.name}")
except discord.Forbidden:
await interaction.followup.send("❌ I don't have permission to create emojis in this server.", ephemeral=True)
except discord.HTTPException as e:
await interaction.followup.send(f"❌ Failed to create emoji: {e}", ephemeral=True)
async def emoji_list_callback(self, interaction: discord.Interaction):
"""List all emojis in the server"""
await interaction.response.defer(ephemeral=False)
try:
# Get all emojis in the guild
emojis = interaction.guild.emojis
if not emojis:
await interaction.followup.send("This server has no custom emojis.")
return
# Create an embed to display the emojis
embed = discord.Embed(
title=f"Emojis in {interaction.guild.name}",
description=f"Total: {len(emojis)} emojis",
color=discord.Color.blue()
)
# Split emojis into animated and static
animated_emojis = [e for e in emojis if e.animated]
static_emojis = [e for e in emojis if not e.animated]
# Add static emojis to the embed
if static_emojis:
static_emoji_text = " ".join(str(e) for e in static_emojis[:20])
if len(static_emojis) > 20:
static_emoji_text += f" ... and {len(static_emojis) - 20} more"
embed.add_field(name=f"Static Emojis ({len(static_emojis)})", value=static_emoji_text or "None", inline=False)
# Add animated emojis to the embed
if animated_emojis:
animated_emoji_text = " ".join(str(e) for e in animated_emojis[:20])
if len(animated_emojis) > 20:
animated_emoji_text += f" ... and {len(animated_emojis) - 20} more"
embed.add_field(name=f"Animated Emojis ({len(animated_emojis)})", value=animated_emoji_text or "None", inline=False)
await interaction.followup.send(embed=embed)
except Exception as e:
await interaction.followup.send(f"❌ An error occurred: {e}", ephemeral=True)
log.error(f"Error listing emojis: {e}")
@app_commands.checks.has_permissions(manage_emojis=True)
async def emoji_delete_callback(self, interaction: discord.Interaction, emoji: str, reason: Optional[str] = None):
"""Delete an emoji from the server"""
await interaction.response.defer(ephemeral=False)
try:
# Parse the emoji string to get the ID
emoji_id = None
emoji_name = None
# Check if it's a custom emoji format <:name:id> or <a:name:id>
if emoji.startswith('<') and emoji.endswith('>'):
parts = emoji.strip('<>').split(':')
if len(parts) == 3: # <a:name:id> format
emoji_name = parts[1]
emoji_id = int(parts[2])
elif len(parts) == 2: # <:name:id> format
emoji_name = parts[0]
emoji_id = int(parts[1])
# If we couldn't parse the emoji, try to find it by name
emoji_obj = None
if emoji_id:
emoji_obj = discord.utils.get(interaction.guild.emojis, id=emoji_id)
else:
# Try to find by name
emoji_obj = discord.utils.get(interaction.guild.emojis, name=emoji)
if not emoji_obj:
await interaction.followup.send("❌ Emoji not found. Please provide a valid emoji from this server.", ephemeral=True)
return
# Store emoji info before deletion for the embed
emoji_name = emoji_obj.name
emoji_url = str(emoji_obj.url)
emoji_id = emoji_obj.id
# Delete the emoji
await emoji_obj.delete(reason=f"{reason or 'No reason provided'} (Deleted by {interaction.user})")
# Create a success embed
embed = discord.Embed(
title="✅ Emoji Deleted",
description=f"Successfully deleted emoji `{emoji_name}`",
color=discord.Color.red()
)
embed.add_field(name="Name", value=emoji_name, inline=True)
embed.add_field(name="ID", value=emoji_id, inline=True)
embed.add_field(name="Deleted by", value=interaction.user.mention, inline=True)
if reason:
embed.add_field(name="Reason", value=reason, inline=False)
embed.set_thumbnail(url=emoji_url)
await interaction.followup.send(embed=embed)
log.info(f"Emoji '{emoji_name}' deleted by {interaction.user} in {interaction.guild.name}")
except discord.Forbidden:
await interaction.followup.send("❌ I don't have permission to delete emojis in this server.", ephemeral=True)
except discord.HTTPException as e:
await interaction.followup.send(f"❌ Failed to delete emoji: {e}", ephemeral=True)
except Exception as e:
await interaction.followup.send(f"❌ An error occurred: {e}", ephemeral=True)
log.error(f"Error deleting emoji: {e}")
async def emoji_info_callback(self, interaction: discord.Interaction, emoji: str):
"""Get information about an emoji"""
await interaction.response.defer(ephemeral=False)
try:
# Parse the emoji string to get the ID
emoji_id = None
# Check if it's a custom emoji format <:name:id> or <a:name:id>
if emoji.startswith('<') and emoji.endswith('>'):
parts = emoji.strip('<>').split(':')
if len(parts) == 3: # <a:name:id> format
emoji_id = int(parts[2])
elif len(parts) == 2: # <:name:id> format
emoji_id = int(parts[1])
# If we couldn't parse the emoji, try to find it by name
emoji_obj = None
if emoji_id:
emoji_obj = discord.utils.get(interaction.guild.emojis, id=emoji_id)
else:
# Try to find by name
emoji_obj = discord.utils.get(interaction.guild.emojis, name=emoji)
if not emoji_obj:
await interaction.followup.send("❌ Emoji not found. Please provide a valid emoji from this server.", ephemeral=True)
return
# Create an embed with emoji information
embed = discord.Embed(
title=f"Emoji Information: {emoji_obj.name}",
color=discord.Color.blue()
)
embed.add_field(name="Name", value=emoji_obj.name, inline=True)
embed.add_field(name="ID", value=emoji_obj.id, inline=True)
embed.add_field(name="Animated", value="Yes" if emoji_obj.animated else "No", inline=True)
embed.add_field(name="Created At", value=discord.utils.format_dt(emoji_obj.created_at), inline=True)
embed.add_field(name="URL", value=f"[Link]({emoji_obj.url})", inline=True)
embed.add_field(name="Usage", value=f"`{str(emoji_obj)}`", inline=True)
embed.set_thumbnail(url=emoji_obj.url)
await interaction.followup.send(embed=embed)
except Exception as e:
await interaction.followup.send(f"❌ An error occurred: {e}", ephemeral=True)
log.error(f"Error getting emoji info: {e}")
async def setup(bot: commands.Bot):
"""Setup function for the emoji cog"""
await bot.add_cog(EmojiCog(bot))
log.info("EmojiCog loaded")