347 lines
13 KiB
Python
347 lines
13 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")
|