Skip to content

Commit

Permalink
Kredcool?
Browse files Browse the repository at this point in the history
  • Loading branch information
KenwoodFox committed Dec 6, 2024
1 parent e934ded commit b4e91b9
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 82 deletions.
94 changes: 25 additions & 69 deletions admin_bot/admin_bot/cogs/image_cog.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import io
import discord
import logging

Expand All @@ -9,7 +10,7 @@
save_image_to_bytes,
)

from typing import Optional
from typing import Optional, Callable

# Just makes sure we decorate where the image_tasks go, cool python!
import utilities.image_tasks
Expand All @@ -18,46 +19,33 @@
class ImageCog(commands.Cog):
def __init__(self, bot):
self.bot = bot
self.register_image_tasks()

# Dynamically create context menus for registered tasks
self.register_context_menus()

# All done, bot will sync the whole tree once every cog is loaded
logging.info("image_cog finished loading.")

def register_context_menus(self):
def register_image_tasks(self):
"""
Register context menu commands for all image tasks in the IMAGE_TASKS registry.
Dynamically register context menu commands for image tasks.
"""
# Import registry here to avoid circular imports
from utilities.image_utils import IMAGE_TASKS
from utilities.image_utils import IMAGE_TASKS # Import the registered tasks

for task_name in IMAGE_TASKS:
# For every task in the IMAGE_TASKS list of registered (decorated tasks)

# Do a context menu thing (Discord)
# Create a context menu for each task
context_menu = app_commands.ContextMenu(
name=task_name.title(), # Could be improved, pass a real name here?
name=task_name.title(),
callback=self.process_image_context,
)

# Set a custom attribute to track the task name
# Attach the task name to the context menu
context_menu.task_name = task_name

# Add the context menu command to the bot
# Add the command to the bot
self.bot.tree.add_command(context_menu)

async def process_image_context(
self,
interaction: discord.Interaction,
message: discord.Message,
self, interaction: discord.Interaction, message: discord.Message
):
"""
Generic handler for image context menu tasks. (Stack overflow throw-in)
Handle image processing via context menu.
"""

task_name = interaction.command.task_name
await self.process_image_task(task_name, interaction, message)
await self.process_image_task(interaction, task_name, message)

async def process_image_task(
self,
Expand All @@ -66,86 +54,54 @@ async def process_image_task(
message: Optional[discord.Message] = None,
):
"""
Process an image task dynamically.
- For context menu tasks, `message` is provided.
- For command tasks, it fetches the message containing the command.
Process the image using the selected task.
"""

# If no message is provided, assume it's an interaction (command usage)
if not message:
# Try to fetch the most recent message from the interaction channel
channel = interaction.channel
async for msg in channel.history(limit=1):
message = msg
break

# If *still* not message lol
if not message:
await interaction.response.send_message(
"Unable to fetch a relevant message to process!", ephemeral=True
"No message to process!", ephemeral=True
)
return

# Ensure the message has an attachment
if not message.attachments:
await interaction.response.send_message(
"This message doesn't have an image attachment!", ephemeral=True
"No image attached to this message!", ephemeral=True
)
return

# Fetch the first attachment
attachment = interaction.message.attachments[0]
attachment = message.attachments[0]

if not attachment.content_type.startswith("image/"):
await interaction.response.send_message(
"The attachment is not an image!", ephemeral=True
)
return

# Fetch the image bytes
await interaction.response.defer() # Acknowledge the interaction
image_bytes = await attachment.read()

try:
# Load the image
# Process the image
input_image = load_image_from_bytes(image_bytes)

# Apply the task
output_image = apply_image_task(input_image, task_name)

# Convert the result to bytes
output_bytes = save_image_to_bytes(output_image)

# Send the result
await interaction.followup.send(
file=discord.File(io.BytesIO(output_bytes), "result.png")
file=discord.File(io.BytesIO(output_bytes), f"{task_name}.png")
)
except Exception as e:
logging.error(f"Error processing image task '{task_name}': {e}")
await interaction.followup.send(
"Failed to process the image.", ephemeral=True
)

@app_commands.command(name="myvote")
async def myvote_context(self, interaction: discord.Interaction):
"""
Add a voting frame to the image.
"""
await self.process_image_task(interaction, "myvote")

@app_commands.command(name="whiteboard")
async def whiteboard_context(self, interaction: discord.Interaction):
"""
Add an image to the whiteboard template.
"""
await self.process_image_task(interaction, "whiteboard")

@app_commands.command(name="keegan")
async def keegan_context(self, interaction: discord.Interaction):
async def cog_unload(self):
"""
Keegan's template
Unload the context menus when the cog is unloaded.
"""
await self.process_image_task(interaction, "keegan")
for command in self.bot.tree.get_commands(type=discord.AppCommandType.message):
if hasattr(command, "task_name"):
self.bot.tree.remove_command(command.name)


async def setup(bot):
Expand Down
Binary file not shown.
27 changes: 14 additions & 13 deletions admin_bot/admin_bot/utilities/image_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,23 +25,24 @@ def keegan_task(input_image: Image.Image) -> Image.Image:
"""
Keegan transformations lol!
"""
# Load the foreground overlay (with transparency)
# Load the foreground overlay (ensure it has an alpha channel)
foreground = Image.open(
"admin_bot/resources/what_is_keegan_looking_at/fore.png"
).convert("RGBA")

# Corner points for his screen (close enough)
corners = [(450, 1600), (1448, 856), (984, 2300), (1800, 1500)]
# Create a new blank RGBA image with the same size as the foreground
result_image = Image.new("RGBA", foreground.size, (0, 0, 0, 0)) # Fully transparent

# Perform a perspective transform on the input image
transformed_image = input_image.transform(
foreground.size, # Match the size of the foreground image
Image.QUAD,
[coord for point in corners for coord in point], # Flatten corner points
Image.BICUBIC,
)
# Resize image to fit screen
resized_image = input_image.resize((1550, 900))

# Composite the transformed image onto the foreground
result = Image.alpha_composite(foreground, transformed_image.convert("RGBA"))
# Rotate image counterclockwise by 38.2 degrees
rotated_image = resized_image.rotate(38.2, expand=True)

return result
# Paste the rotated image onto the result image
result_image.paste(rotated_image, (240, 780))

# Place the foreground on top
result_image.paste(foreground, (0, 0), foreground)

return result_image

0 comments on commit b4e91b9

Please sign in to comment.