-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add healthcheck * Move myvote (aaron) to new cog * At a pausing point * Kredcool?
- Loading branch information
1 parent
178e959
commit 4d42958
Showing
7 changed files
with
229 additions
and
59 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
import io | ||
import discord | ||
import logging | ||
|
||
from discord import app_commands | ||
from discord.ext import commands | ||
from utilities.image_utils import ( | ||
apply_image_task, | ||
load_image_from_bytes, | ||
save_image_to_bytes, | ||
) | ||
|
||
from typing import Optional, Callable | ||
|
||
# Just makes sure we decorate where the image_tasks go, cool python! | ||
import utilities.image_tasks | ||
|
||
|
||
class ImageCog(commands.Cog): | ||
def __init__(self, bot): | ||
self.bot = bot | ||
self.register_image_tasks() | ||
|
||
def register_image_tasks(self): | ||
""" | ||
Dynamically register context menu commands for image tasks. | ||
""" | ||
from utilities.image_utils import IMAGE_TASKS # Import the registered tasks | ||
|
||
for task_name in IMAGE_TASKS: | ||
# Create a context menu for each task | ||
context_menu = app_commands.ContextMenu( | ||
name=task_name.title(), | ||
callback=self.process_image_context, | ||
) | ||
# Attach the task name to the context menu | ||
context_menu.task_name = task_name | ||
# 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 | ||
): | ||
""" | ||
Handle image processing via context menu. | ||
""" | ||
task_name = interaction.command.task_name | ||
await self.process_image_task(interaction, task_name, message) | ||
|
||
async def process_image_task( | ||
self, | ||
interaction: discord.Interaction, | ||
task_name: str, | ||
message: Optional[discord.Message] = None, | ||
): | ||
""" | ||
Process the image using the selected task. | ||
""" | ||
if not message: | ||
await interaction.response.send_message( | ||
"No message to process!", ephemeral=True | ||
) | ||
return | ||
|
||
if not message.attachments: | ||
await interaction.response.send_message( | ||
"No image attached to this message!", ephemeral=True | ||
) | ||
return | ||
|
||
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 | ||
|
||
await interaction.response.defer() # Acknowledge the interaction | ||
image_bytes = await attachment.read() | ||
|
||
try: | ||
# Process the image | ||
input_image = load_image_from_bytes(image_bytes) | ||
output_image = apply_image_task(input_image, task_name) | ||
output_bytes = save_image_to_bytes(output_image) | ||
|
||
# Send the result | ||
await interaction.followup.send( | ||
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 | ||
) | ||
|
||
async def cog_unload(self): | ||
""" | ||
Unload the context menus when the cog is unloaded. | ||
""" | ||
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): | ||
await bot.add_cog(ImageCog(bot)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
from PIL import Image | ||
from utilities.image_utils import register_image_task | ||
|
||
|
||
@register_image_task("myvote") | ||
def myvote_task(input_image: Image.Image) -> Image.Image: | ||
frame = Image.open("admin_bot/resources/vote.png") | ||
input_image = input_image.resize((375, 250)) | ||
frame.paste(input_image, (40, 240)) | ||
return frame | ||
|
||
|
||
@register_image_task("whiteboard") | ||
def whiteboard_task(input_image: Image.Image) -> Image.Image: | ||
background = Image.open("admin_bot/resources/look_at_this/background.png") | ||
foreground = Image.open("admin_bot/resources/look_at_this/foreground.png") | ||
input_image = input_image.resize((1000, 2000)) | ||
background.paste(input_image, (1500, 75)) | ||
background.paste(foreground, (0, 0), foreground) | ||
return background | ||
|
||
|
||
@register_image_task("keegan") | ||
def keegan_task(input_image: Image.Image) -> Image.Image: | ||
""" | ||
Keegan transformations lol! | ||
""" | ||
# 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") | ||
|
||
# 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 | ||
|
||
# Resize image to fit screen | ||
resized_image = input_image.resize((1550, 900)) | ||
|
||
# Rotate image counterclockwise by 38.2 degrees | ||
rotated_image = resized_image.rotate(38.2, expand=True) | ||
|
||
# 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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import io | ||
import logging | ||
|
||
from PIL import Image, UnidentifiedImageError | ||
from typing import Callable, Dict | ||
|
||
# Registry for image manipulation tasks | ||
IMAGE_TASKS: Dict[str, Callable[[Image.Image], Image.Image]] = {} | ||
|
||
|
||
def register_image_task(name: str): | ||
""" | ||
Decorator to register an image task. | ||
:param name: The name of the task. | ||
""" | ||
|
||
def decorator(func: Callable[[Image.Image], Image.Image]): | ||
IMAGE_TASKS[name] = func | ||
return func | ||
|
||
return decorator | ||
|
||
|
||
def apply_image_task(image: Image.Image, task_name: str) -> Image.Image: | ||
""" | ||
Apply a registered image task to the given image. | ||
:param image: The input image. | ||
:param task_name: The task to apply. | ||
:return: The resulting image. | ||
""" | ||
if task_name not in IMAGE_TASKS: | ||
raise ValueError(f"Task '{task_name}' is not registered.") | ||
|
||
return IMAGE_TASKS[task_name](image) | ||
|
||
|
||
def load_image_from_bytes(image_bytes: bytes) -> Image.Image: | ||
""" | ||
Load an PIL image from bytes. | ||
:param image_bytes: The image data in bytes. | ||
:return: A PIL Image. | ||
""" | ||
try: | ||
return Image.open(io.BytesIO(image_bytes)) | ||
except UnidentifiedImageError as e: | ||
logging.error(f"Failed to load image: {e}") | ||
raise | ||
|
||
|
||
def save_image_to_bytes(image: Image.Image) -> bytes: | ||
""" | ||
Save a PIL Image to bytes. | ||
:param image: The PIL Image. | ||
:return: Image data as bytes. | ||
""" | ||
with io.BytesIO() as output: | ||
image.save(output, format="PNG") | ||
return output.getvalue() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -43,5 +43,7 @@ USER ${USER_ID} | |
|
||
EXPOSE 8000 | ||
|
||
HEALTHCHECK NONE | ||
|
||
# Run the entrypoint bin | ||
ENTRYPOINT ["entrypoint"] |