169 lines
7.2 KiB
Python
169 lines
7.2 KiB
Python
import os
|
|
import discord
|
|
from discord.ext import commands
|
|
from discord import app_commands
|
|
import random as random_module
|
|
import typing # Need this for Optional
|
|
|
|
# Cache to store uploaded file URLs (local to this cog)
|
|
file_url_cache = {}
|
|
|
|
|
|
class RandomCog(commands.Cog):
|
|
def __init__(self, bot):
|
|
self.bot = bot
|
|
|
|
# Updated _random_logic
|
|
async def _random_logic(
|
|
self, interaction_or_ctx, hidden: bool = False
|
|
) -> typing.Optional[str]:
|
|
"""Core logic for the random command. Returns an error message string or None if successful."""
|
|
# NSFW Check
|
|
is_nsfw_channel = False
|
|
channel = interaction_or_ctx.channel
|
|
if isinstance(channel, discord.TextChannel) and channel.is_nsfw():
|
|
is_nsfw_channel = True
|
|
elif isinstance(
|
|
channel, discord.DMChannel
|
|
): # DMs are considered NSFW for this purpose
|
|
is_nsfw_channel = True
|
|
|
|
if not is_nsfw_channel:
|
|
# Return error message directly, ephemeral handled by caller
|
|
return "This command can only be used in age-restricted (NSFW) channels or DMs."
|
|
|
|
directory = os.getenv("UPLOAD_DIRECTORY")
|
|
if not directory:
|
|
return "UPLOAD_DIRECTORY is not set in the .env file."
|
|
if not os.path.isdir(directory):
|
|
return (
|
|
"The specified UPLOAD_DIRECTORY does not exist or is not a directory."
|
|
)
|
|
|
|
files = [
|
|
f
|
|
for f in os.listdir(directory)
|
|
if os.path.isfile(os.path.join(directory, f))
|
|
]
|
|
if not files:
|
|
return "The specified directory is empty."
|
|
|
|
# Attempt to send a random file, handling potential size issues
|
|
original_files = list(files) # Copy for checking if all files failed
|
|
while files:
|
|
chosen_file_name = random_module.choice(files)
|
|
file_path = os.path.join(directory, chosen_file_name)
|
|
|
|
# Check cache first
|
|
if chosen_file_name in file_url_cache:
|
|
# For interactions, defer if not already done, using the hidden flag
|
|
if (
|
|
not isinstance(interaction_or_ctx, commands.Context)
|
|
and not interaction_or_ctx.response.is_done()
|
|
):
|
|
await interaction_or_ctx.response.defer(
|
|
ephemeral=hidden
|
|
) # Defer before sending cached URL
|
|
# Send cached URL
|
|
if isinstance(interaction_or_ctx, commands.Context):
|
|
await interaction_or_ctx.reply(
|
|
file_url_cache[chosen_file_name]
|
|
) # Prefix commands can't be ephemeral
|
|
else:
|
|
await interaction_or_ctx.followup.send(
|
|
file_url_cache[chosen_file_name], ephemeral=hidden
|
|
)
|
|
return None # Indicate success
|
|
|
|
try:
|
|
# Determine how to send the file based on context/interaction
|
|
if isinstance(interaction_or_ctx, commands.Context):
|
|
message = await interaction_or_ctx.reply(
|
|
file=discord.File(file_path)
|
|
) # Use reply for context
|
|
else: # It's an interaction
|
|
# Interactions need followup for files after defer()
|
|
if not interaction_or_ctx.response.is_done():
|
|
await interaction_or_ctx.response.defer(
|
|
ephemeral=hidden
|
|
) # Defer before sending file
|
|
# Send file ephemerally if hidden is True
|
|
message = await interaction_or_ctx.followup.send(
|
|
file=discord.File(file_path), ephemeral=hidden
|
|
)
|
|
|
|
# Cache the URL if successfully sent
|
|
if message and message.attachments:
|
|
file_url_cache[chosen_file_name] = message.attachments[0].url
|
|
# Success, no further message needed
|
|
return None
|
|
else:
|
|
# Should not happen if send succeeded, but handle defensively
|
|
files.remove(chosen_file_name)
|
|
print(
|
|
f"Warning: File {chosen_file_name} sent but no attachment URL found."
|
|
) # Log warning
|
|
continue
|
|
|
|
except discord.HTTPException as e:
|
|
if e.code == 40005: # Request entity too large
|
|
print(f"File too large: {chosen_file_name}")
|
|
files.remove(chosen_file_name)
|
|
continue # Try another file
|
|
else:
|
|
print(f"HTTP Error sending file: {e}")
|
|
# Return error message directly, ephemeral handled by caller
|
|
return f"Failed to upload the file due to an HTTP error: {e}"
|
|
except Exception as e:
|
|
print(f"Generic Error sending file: {e}")
|
|
# Return error message directly, ephemeral handled by caller
|
|
return f"An unexpected error occurred while uploading the file: {e}"
|
|
|
|
# If loop finishes without returning/sending, all files were too large
|
|
# Return error message directly, ephemeral handled by caller
|
|
return "All files in the directory were too large to upload."
|
|
|
|
# --- Prefix Command ---
|
|
@commands.command(name="random")
|
|
async def random(self, ctx: commands.Context):
|
|
"""Upload a random NSFW image from the configured directory."""
|
|
# Call _random_logic, hidden is False by default and irrelevant for prefix
|
|
response = await self._random_logic(ctx)
|
|
if response is not None:
|
|
await ctx.reply(response)
|
|
|
|
# --- Slash Command ---
|
|
# Updated signature and logic
|
|
@app_commands.command(
|
|
name="random",
|
|
description="Upload a random NSFW image from the configured directory",
|
|
)
|
|
@app_commands.describe(
|
|
hidden="Set to True to make the response visible only to you (default: False)"
|
|
)
|
|
async def random_slash(
|
|
self, interaction: discord.Interaction, hidden: bool = False
|
|
):
|
|
"""Slash command version of random."""
|
|
# Pass hidden parameter to logic
|
|
response = await self._random_logic(interaction, hidden=hidden)
|
|
# If response is None, the logic already sent the file via followup/deferral
|
|
|
|
if response is not None: # An error occurred
|
|
# Ensure interaction hasn't already been responded to or deferred
|
|
if not interaction.response.is_done():
|
|
# Send error message ephemerally if hidden is True OR if it's the NSFW channel error
|
|
ephemeral_error = hidden or response.startswith(
|
|
"This command can only be used"
|
|
)
|
|
await interaction.response.send_message(
|
|
response, ephemeral=ephemeral_error
|
|
)
|
|
else:
|
|
# If deferred, use followup. Send ephemerally based on hidden flag.
|
|
await interaction.followup.send(response, ephemeral=hidden)
|
|
|
|
|
|
async def setup(bot):
|
|
await bot.add_cog(RandomCog(bot))
|